Skip to content

Commit 5b00e27

Browse files
ankediarjeberhard
andauthored
Owls 87757 - common mount feature to separate WDT model and archive from WLS binary image. (#2338)
* common mount feature to separate WDT model and archive from WLS binary image. Co-authored-by: Ryan Eberhard <ryan.eberhard@oracle.com>
1 parent 3146e03 commit 5b00e27

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1719
-248
lines changed

documentation/domains/Domain.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,10 @@
583583
"modelHome": {
584584
"description": "Location of the WebLogic Deploy Tooling model home. Defaults to /u01/wdt/models.",
585585
"type": "string"
586+
},
587+
"wdtInstallHome": {
588+
"description": "Location of the WebLogic Deploy Tooling installation. Defaults to /u01/wdt/weblogic-deploy.",
589+
"type": "string"
586590
}
587591
}
588592
},

documentation/domains/Domain.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ The current status of the operation of the WebLogic domain. Updated automaticall
220220
| `modelHome` | string | Location of the WebLogic Deploy Tooling model home. Defaults to /u01/wdt/models. |
221221
| `onlineUpdate` | [Online Update](#online-update) | Online update option for Model In Image dynamic update. |
222222
| `runtimeEncryptionSecret` | string | Runtime encryption secret. Required when `domainHomeSourceType` is set to FromModel. |
223+
| `wdtInstallHome` | string | Location of the WebLogic Deploy Tooling installation. Defaults to /u01/wdt/weblogic-deploy. |
223224

224225
### Opss
225226

kubernetes/crd/domain-crd.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ apiVersion: apiextensions.k8s.io/v1
55
kind: CustomResourceDefinition
66
metadata:
77
annotations:
8-
weblogic.sha256: 2c458de3536da4e8a31d375fc7375c55387080a19f260f687dd687ec4f61d67b
8+
weblogic.sha256: 3e2981c2a3c6057a30a7d22c0a969b992f3a36051a133b6ba4e9fe20121d3088
99
name: domains.weblogic.oracle
1010
spec:
1111
group: weblogic.oracle
@@ -188,6 +188,10 @@ spec:
188188
description: Location of the WebLogic Deploy Tooling model
189189
home. Defaults to /u01/wdt/models.
190190
type: string
191+
wdtInstallHome:
192+
description: Location of the WebLogic Deploy Tooling installation.
193+
Defaults to /u01/wdt/weblogic-deploy.
194+
type: string
191195
type: object
192196
secrets:
193197
description: A list of names of the Secrets for WebLogic configuration

operator/src/main/java/oracle/kubernetes/operator/TuningParametersImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ private Collection<String> generateFeatureGates(String featureGatesProperty) {
115115
Arrays.stream(
116116
featureGatesProperty.split(","))
117117
.filter(s -> s.endsWith("=true"))
118-
.map(s -> s.substring(s.indexOf('=')))
118+
.map(s -> s.substring(0, s.indexOf('=')))
119119
.collect(Collectors.toCollection(() -> enabledGates));
120120
}
121121
return enabledGates;

operator/src/main/java/oracle/kubernetes/operator/helpers/BasePodStepContext.java

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,40 @@
33

44
package oracle.kubernetes.operator.helpers;
55

6+
import java.util.ArrayList;
7+
import java.util.Arrays;
8+
import java.util.Collections;
69
import java.util.HashMap;
710
import java.util.List;
811
import java.util.Map;
912
import java.util.Optional;
13+
import java.util.StringJoiner;
14+
import java.util.regex.Pattern;
15+
import java.util.stream.Collectors;
1016

17+
import io.kubernetes.client.custom.Quantity;
1118
import io.kubernetes.client.openapi.models.V1Container;
19+
import io.kubernetes.client.openapi.models.V1EmptyDirVolumeSource;
1220
import io.kubernetes.client.openapi.models.V1EnvVar;
1321
import io.kubernetes.client.openapi.models.V1EnvVarSource;
1422
import io.kubernetes.client.openapi.models.V1Pod;
1523
import io.kubernetes.client.openapi.models.V1PodSpec;
1624
import io.kubernetes.client.openapi.models.V1Toleration;
25+
import io.kubernetes.client.openapi.models.V1Volume;
26+
import io.kubernetes.client.openapi.models.V1VolumeMount;
1727
import oracle.kubernetes.operator.KubernetesConstants;
1828
import oracle.kubernetes.operator.TuningParameters;
29+
import oracle.kubernetes.weblogic.domain.model.CommonMount;
30+
import oracle.kubernetes.weblogic.domain.model.CommonMountEnvVars;
31+
import oracle.kubernetes.weblogic.domain.model.CommonMountVolume;
1932
import oracle.kubernetes.weblogic.domain.model.ServerSpec;
2033

34+
import static oracle.kubernetes.operator.helpers.LegalNames.toDns1123LegalName;
35+
import static oracle.kubernetes.weblogic.domain.model.CommonMount.COMMON_MOUNT_INIT_CONTAINER_NAME_PREFIX;
36+
import static oracle.kubernetes.weblogic.domain.model.CommonMount.COMMON_MOUNT_INIT_CONTAINER_WRAPPER_SCRIPT;
37+
import static oracle.kubernetes.weblogic.domain.model.CommonMount.COMMON_MOUNT_TARGET_PATH;
38+
import static oracle.kubernetes.weblogic.domain.model.CommonMount.COMMON_MOUNT_VOLUME_NAME_PREFIX;
39+
2140
public abstract class BasePodStepContext extends StepContextBase {
2241

2342
BasePodStepContext(DomainPresenceInfo info) {
@@ -32,6 +51,34 @@ final <T> T updateForDeepSubstitution(V1PodSpec podSpec, T target) {
3251

3352
abstract ServerSpec getServerSpec();
3453

54+
String getMountPath(CommonMount commonMount, List<CommonMountVolume> commonMountVolumes) {
55+
return commonMountVolumes.stream().filter(
56+
commonMountVolume -> hasMatchingVolumeName(commonMountVolume, commonMount)).findFirst()
57+
.map(CommonMountVolume::getMountPath).orElse(null);
58+
}
59+
60+
private boolean hasMatchingVolumeName(CommonMountVolume commonMountVolume, CommonMount commonMount) {
61+
return commonMount.getVolume().equals(commonMountVolume.getName());
62+
}
63+
64+
protected void addVolumeMount(V1Container container, CommonMount cm) {
65+
Optional.ofNullable(getMountPath(cm, info.getDomain().getCommonMountVolumes())).ifPresent(mountPath ->
66+
addVolumeMountIfMissing(container, cm, mountPath));
67+
}
68+
69+
protected void addVolumeMountIfMissing(V1Container container, CommonMount cm, String mountPath) {
70+
if (Optional.ofNullable(container.getVolumeMounts()).map(volumeMounts -> volumeMounts.stream().noneMatch(
71+
volumeMount -> hasMatchingVolumeMountName(volumeMount, cm))).orElse(true)) {
72+
container.addVolumeMountsItem(
73+
new V1VolumeMount().name(getDNS1123CommonMountVolumeName(cm.getVolume()))
74+
.mountPath(mountPath));
75+
}
76+
}
77+
78+
private boolean hasMatchingVolumeMountName(V1VolumeMount volumeMount, CommonMount commonMount) {
79+
return getDNS1123CommonMountVolumeName(commonMount.getVolume()).equals(volumeMount.getName());
80+
}
81+
3582
abstract String getContainerName();
3683

3784
abstract List<String> getContainerCommand();
@@ -49,6 +96,60 @@ protected V1Container createPrimaryContainer(TuningParameters tuningParameters)
4996
.securityContext(getServerSpec().getContainerSecurityContext());
5097
}
5198

99+
protected V1Volume createEmptyDirVolume(CommonMountVolume cmv) {
100+
V1EmptyDirVolumeSource emptyDirVolumeSource = new V1EmptyDirVolumeSource();
101+
Optional.ofNullable(cmv.getMedium()).ifPresent(emptyDirVolumeSource::medium);
102+
Optional.ofNullable(cmv.getSizeLimit())
103+
.ifPresent(sl -> emptyDirVolumeSource.sizeLimit(Quantity.fromString((String) sl)));
104+
return new V1Volume().name(getDNS1123CommonMountVolumeName(cmv.getName())).emptyDir(emptyDirVolumeSource);
105+
}
106+
107+
public String getDNS1123CommonMountVolumeName(String name) {
108+
return toDns1123LegalName(COMMON_MOUNT_VOLUME_NAME_PREFIX + name);
109+
}
110+
111+
protected V1Container createInitContainerForCommonMount(CommonMount commonMount, int index) {
112+
return new V1Container().name(getName(index))
113+
.image(commonMount.getImage())
114+
.imagePullPolicy(commonMount.getImagePullPolicy())
115+
.command(Collections.singletonList(COMMON_MOUNT_INIT_CONTAINER_WRAPPER_SCRIPT))
116+
.env(createEnv(commonMount, info.getDomain().getCommonMountVolumes(), getName(index)))
117+
.volumeMounts(Arrays.asList(
118+
new V1VolumeMount().name(getDNS1123CommonMountVolumeName(commonMount.getVolume()))
119+
.mountPath(COMMON_MOUNT_TARGET_PATH),
120+
new V1VolumeMount().name(SCRIPTS_VOLUME).mountPath(SCRIPTS_MOUNTS_PATH)));
121+
}
122+
123+
private String getName(int index) {
124+
return COMMON_MOUNT_INIT_CONTAINER_NAME_PREFIX + (index + 1);
125+
}
126+
127+
protected List<V1EnvVar> createEnv(CommonMount commonMount, List<CommonMountVolume> commonMountVolumes, String name) {
128+
List<V1EnvVar> vars = new ArrayList<>();
129+
addEnvVar(vars, CommonMountEnvVars.COMMON_MOUNT_PATH, getMountPath(commonMount, commonMountVolumes));
130+
addEnvVar(vars, CommonMountEnvVars.COMMON_MOUNT_TARGET_PATH, COMMON_MOUNT_TARGET_PATH);
131+
addEnvVar(vars, CommonMountEnvVars.COMMON_MOUNT_COMMAND, commonMount.getCommand());
132+
addEnvVar(vars, CommonMountEnvVars.COMMON_MOUNT_CONTAINER_IMAGE, commonMount.getImage());
133+
addEnvVar(vars, CommonMountEnvVars.COMMON_MOUNT_CONTAINER_NAME, name);
134+
return vars;
135+
}
136+
137+
protected void addEmptyDirVolume(V1PodSpec podSpec, List<CommonMountVolume> commonMountVolumes) {
138+
Optional.ofNullable(commonMountVolumes).ifPresent(volumes -> volumes.forEach(commonMountVolume ->
139+
addVolumeIfMissing(podSpec, commonMountVolume)));
140+
}
141+
142+
private void addVolumeIfMissing(V1PodSpec podSpec, CommonMountVolume commonMountVolume) {
143+
if (Optional.ofNullable(podSpec.getVolumes()).map(volumes -> volumes.stream().noneMatch(
144+
volume -> podHasMatchingVolumeName(volume, commonMountVolume))).orElse(true)) {
145+
podSpec.addVolumesItem(createEmptyDirVolume(commonMountVolume));
146+
}
147+
}
148+
149+
private boolean podHasMatchingVolumeName(V1Volume volume, CommonMountVolume commonMountVolume) {
150+
return volume.getName().equals(commonMountVolume.getName());
151+
}
152+
52153
protected V1PodSpec createPodSpec(TuningParameters tuningParameters) {
53154
return new V1PodSpec()
54155
.containers(getContainers())
@@ -208,4 +309,16 @@ protected boolean isK8sContainer(V1Container c) {
208309
protected String getMainContainerName() {
209310
return KubernetesConstants.CONTAINER_NAME;
210311
}
312+
313+
protected String getCommonMountPaths(List<CommonMount> commonMounts, List<CommonMountVolume> commonMountVolumes) {
314+
return Optional.ofNullable(commonMounts).map(cmList -> createCommonMountPathsEnv(cmList, commonMountVolumes))
315+
.orElse(null);
316+
}
317+
318+
private String createCommonMountPathsEnv(List<CommonMount> commonMounts, List<CommonMountVolume> commonMountVolumes) {
319+
StringJoiner commonMountPaths = new StringJoiner(",","","");
320+
commonMounts.forEach(commonMount -> commonMountPaths.add(getMountPath(commonMount, commonMountVolumes)));
321+
return Arrays.stream(commonMountPaths.toString().split(Pattern.quote(","))).distinct()
322+
.filter(st -> !st.isEmpty()).collect(Collectors.joining(","));
323+
}
211324
}

operator/src/main/java/oracle/kubernetes/operator/helpers/CallBuilder.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public class CallBuilder {
8585
public static final int NOT_FOUND = 404;
8686

8787
private static final String RESOURCE_VERSION_MATCH_UNSET = null;
88+
private String container;
8889

8990
private static final SynchronousCallDispatcher DEFAULT_DISPATCHER =
9091
new SynchronousCallDispatcher() {
@@ -240,7 +241,7 @@ public <T> T execute(
240241
usage,
241242
requestParams.name,
242243
requestParams.namespace,
243-
null,
244+
container,
244245
null,
245246
null,
246247
null,
@@ -494,6 +495,16 @@ public CallBuilder withLabelSelectors(String... selectors) {
494495
return this;
495496
}
496497

498+
/**
499+
* Set container name for the CallBuilder.
500+
* @param containerName container name
501+
* @return this CallBuilder
502+
*/
503+
public CallBuilder withContainerName(String containerName) {
504+
this.container = containerName;
505+
return this;
506+
}
507+
497508
public CallBuilder withFieldSelector(String fieldSelector) {
498509
this.fieldSelector = fieldSelector;
499510
return this;

operator/src/main/java/oracle/kubernetes/operator/helpers/JobHelper.java

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.Objects;
1010
import java.util.Optional;
1111

12+
import io.kubernetes.client.openapi.models.V1Container;
1213
import io.kubernetes.client.openapi.models.V1DeleteOptions;
1314
import io.kubernetes.client.openapi.models.V1EnvVar;
1415
import io.kubernetes.client.openapi.models.V1Job;
@@ -17,6 +18,7 @@
1718
import io.kubernetes.client.openapi.models.V1ObjectMeta;
1819
import io.kubernetes.client.openapi.models.V1Pod;
1920
import io.kubernetes.client.openapi.models.V1PodList;
21+
import io.kubernetes.client.openapi.models.V1PodSpec;
2022
import io.kubernetes.client.openapi.models.V1Volume;
2123
import io.kubernetes.client.openapi.models.V1VolumeMount;
2224
import oracle.kubernetes.operator.DomainStatusUpdater;
@@ -38,6 +40,7 @@
3840
import oracle.kubernetes.operator.work.Packet;
3941
import oracle.kubernetes.operator.work.Step;
4042
import oracle.kubernetes.weblogic.domain.model.Cluster;
43+
import oracle.kubernetes.weblogic.domain.model.CommonMountEnvVars;
4144
import oracle.kubernetes.weblogic.domain.model.ConfigurationConstants;
4245
import oracle.kubernetes.weblogic.domain.model.Domain;
4346
import oracle.kubernetes.weblogic.domain.model.DomainSpec;
@@ -346,8 +349,17 @@ List<V1EnvVar> getConfiguredEnvVars(TuningParameters tuningParameters) {
346349
if (modelHome != null && !modelHome.isEmpty()) {
347350
addEnvVar(vars, IntrospectorJobEnvVars.WDT_MODEL_HOME, modelHome);
348351
}
352+
353+
String wdtInstallHome = getWdtInstallHome();
354+
if (wdtInstallHome != null && !wdtInstallHome.isEmpty()) {
355+
addEnvVar(vars, IntrospectorJobEnvVars.WDT_INSTALL_HOME, wdtInstallHome);
356+
}
357+
358+
Optional.ofNullable(getCommonMountPaths(getServerSpec().getCommonMounts(), getDomain().getCommonMountVolumes()))
359+
.ifPresent(c -> addEnvVar(vars, CommonMountEnvVars.COMMON_MOUNT_PATHS, c));
349360
return vars;
350361
}
362+
351363
}
352364

353365
static class DomainIntrospectorJobStep extends Step {
@@ -449,9 +461,10 @@ public NextAction apply(Packet packet) {
449461

450462
private Step readDomainIntrospectorPodLog(String jobPodName, String namespace, String domainUid, Step next) {
451463
return new CallBuilder()
452-
.readPodLogAsync(
453-
jobPodName, namespace, domainUid, new ReadDomainIntrospectorPodLogResponseStep(next));
464+
.readPodLogAsync(
465+
jobPodName, namespace, domainUid, new ReadDomainIntrospectorPodLogResponseStep(next));
454466
}
467+
455468
}
456469

457470
private static class ReadDomainIntrospectorPodLogResponseStep extends ResponseStep<String> {
@@ -477,7 +490,7 @@ public NextAction onSuccess(Packet packet, CallResponse<String> callResponse) {
477490
}
478491

479492
V1Job domainIntrospectorJob =
480-
(V1Job) packet.get(ProcessingConstants.DOMAIN_INTROSPECTOR_JOB);
493+
(V1Job) packet.get(ProcessingConstants.DOMAIN_INTROSPECTOR_JOB);
481494

482495
if (isNotComplete(domainIntrospectorJob)) {
483496
List<String> jobConditionsReason = new ArrayList<>();
@@ -495,11 +508,11 @@ public NextAction onSuccess(Packet packet, CallResponse<String> callResponse) {
495508
}
496509
//Introspector job is incomplete, update domain status and terminate processing
497510
return doNext(
498-
DomainStatusUpdater.createFailureRelatedSteps(
499-
onSeparateLines(jobConditionsReason),
500-
onSeparateLines(severeStatuses),
501-
null),
502-
packet);
511+
DomainStatusUpdater.createFailureRelatedSteps(
512+
onSeparateLines(jobConditionsReason),
513+
onSeparateLines(severeStatuses),
514+
null),
515+
packet);
503516
}
504517

505518
return doNext(packet);
@@ -662,12 +675,21 @@ private String getName(V1Pod pod) {
662675
return Optional.of(pod).map(V1Pod::getMetadata).map(V1ObjectMeta::getName).orElse("");
663676
}
664677

678+
private List<V1Container> getInitContainers(V1Pod pod) {
679+
return Optional.of(pod).map(V1Pod::getSpec).map(V1PodSpec::getInitContainers).orElse(Collections.emptyList());
680+
}
681+
665682
private boolean isJobPodName(String podName) {
666683
return podName.startsWith(createJobName(domainUid));
667684
}
668685

686+
private boolean isJobPod(V1Pod pod) {
687+
return pod.getMetadata().getName().startsWith(createJobName(domainUid));
688+
}
689+
669690
private void recordJobPodName(Packet packet, String podName) {
670691
packet.put(ProcessingConstants.JOB_POD_NAME, podName);
671692
}
693+
672694
}
673695
}

0 commit comments

Comments
 (0)