Skip to content

Commit 5d70e49

Browse files
committed
Use sha256 hash to decide whether to replace pods
1 parent 4754046 commit 5d70e49

File tree

11 files changed

+399
-550
lines changed

11 files changed

+399
-550
lines changed

model/src/main/java/oracle/kubernetes/weblogic/domain/v2/DomainV2Configurator.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public DomainConfigurator createFor(Domain domain) {
2828

2929
public DomainV2Configurator() {}
3030

31-
public DomainV2Configurator(@Nonnull Domain domain) {
31+
DomainV2Configurator(@Nonnull Domain domain) {
3232
super(domain);
3333
setApiVersion(domain);
3434
}
@@ -93,26 +93,20 @@ public DomainConfigurator withConfigOverrides(String configMapName) {
9393
}
9494

9595
@Override
96-
/**
97-
* Sets the WebLogic configuration overrides secret names for the domain
98-
*
99-
* @param secretNames a list of secret names
100-
* @return this object
101-
*/
10296
public DomainConfigurator withConfigOverrideSecrets(String... secretNames) {
10397
getDomainSpec().setConfigOverrideSecrets(Arrays.asList(secretNames));
10498
return this;
10599
}
106100

107101
@Override
108102
public DomainConfigurator withPodLabel(String name, String value) {
109-
((BaseConfiguration) getDomainSpec()).addPodLabel(name, value);
103+
getDomainSpec().addPodLabel(name, value);
110104
return this;
111105
}
112106

113107
@Override
114108
public DomainConfigurator withPodAnnotation(String name, String value) {
115-
((BaseConfiguration) getDomainSpec()).addPodAnnotation(name, value);
109+
getDomainSpec().addPodAnnotation(name, value);
116110
return this;
117111
}
118112

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1-
// Copyright 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved.
1+
// Copyright 2017, 2019, Oracle Corporation and/or its affiliates. All rights reserved.
22
// Licensed under the Universal Permissive License v 1.0 as shown at
33
// http://oss.oracle.com/licenses/upl.
44

55
package oracle.kubernetes.operator.helpers;
66

77
import io.kubernetes.client.models.V1ObjectMeta;
8+
import io.kubernetes.client.models.V1Pod;
9+
import io.kubernetes.client.util.Yaml;
10+
import org.apache.commons.codec.digest.DigestUtils;
811

912
/** Annotates pods, services with details about the Domain instance and checks these annotations. */
1013
public class AnnotationHelper {
14+
static final String SHA256_ANNOTATION = "weblogic.sha256";
15+
1116
/**
1217
* Marks metadata with annotations that let Prometheus know how to retrieve metrics from the
1318
* wls-exporter web-app. The specified httpPort should be the listen port of the WebLogic server
@@ -16,10 +21,23 @@ public class AnnotationHelper {
1621
* @param meta Metadata
1722
* @param httpPort HTTP listen port
1823
*/
19-
public static void annotateForPrometheus(V1ObjectMeta meta, int httpPort) {
24+
static void annotateForPrometheus(V1ObjectMeta meta, int httpPort) {
2025
meta.putAnnotationsItem(
2126
"prometheus.io/port", "" + httpPort); // should be the ListenPort of the server in the pod
2227
meta.putAnnotationsItem("prometheus.io/path", "/wls-exporter/metrics");
2328
meta.putAnnotationsItem("prometheus.io/scrape", "true");
2429
}
30+
31+
static V1Pod withSha256Hash(V1Pod pod) {
32+
pod.getMetadata().putAnnotationsItem(SHA256_ANNOTATION, computeHash(pod));
33+
return pod;
34+
}
35+
36+
static String computeHash(V1Pod pod) {
37+
return DigestUtils.sha256Hex(Yaml.dump(pod));
38+
}
39+
40+
static String getHash(V1Pod pod) {
41+
return pod.getMetadata().getAnnotations().get(SHA256_ANNOTATION);
42+
}
2543
}

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

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
import io.kubernetes.client.models.V1PodSpec;
1717
import io.kubernetes.client.models.V1Probe;
1818
import io.kubernetes.client.models.V1ResourceRequirements;
19-
import io.kubernetes.client.models.V1Volume;
20-
import io.kubernetes.client.models.V1VolumeMount;
2119
import java.util.ArrayList;
2220
import java.util.Collection;
2321
import java.util.Collections;
@@ -28,14 +26,13 @@
2826
import java.util.Objects;
2927
import java.util.Optional;
3028
import java.util.Set;
31-
import java.util.stream.Collectors;
3229
import oracle.kubernetes.operator.LabelConstants;
3330

3431
/** A class which defines the compatability rules for existing vs. specified pods. */
3532
class PodCompatibility extends CollectiveCompatibility {
36-
PodCompatibility(V1Pod expected, V1Pod actual, List<String> volumesToIgnore) {
33+
PodCompatibility(V1Pod expected, V1Pod actual) {
3734
add(new PodMetadataCompatibility(expected.getMetadata(), actual.getMetadata()));
38-
add(new PodSpecCompatibility(expected.getSpec(), actual.getSpec(), volumesToIgnore));
35+
add(new PodSpecCompatibility(expected.getSpec(), actual.getSpec()));
3936
}
4037

4138
static class PodMetadataCompatibility extends CollectiveCompatibility {
@@ -101,25 +98,15 @@ public String getIncompatibility() {
10198
}
10299

103100
static class PodSpecCompatibility extends CollectiveCompatibility {
104-
private List<String> volumesToIgnore;
105101

106-
PodSpecCompatibility(V1PodSpec expected, V1PodSpec actual, List<String> volumesToIgnore) {
107-
this.volumesToIgnore = volumesToIgnore;
102+
PodSpecCompatibility(V1PodSpec expected, V1PodSpec actual) {
108103
add("securityContext", expected.getSecurityContext(), actual.getSecurityContext());
109104
add(new EqualsMaps<>("nodeSelector", expected.getNodeSelector(), actual.getNodeSelector()));
110-
addSets("volumes", expected.getVolumes(), relevantVolumes(actual.getVolumes()));
105+
addSets("volumes", expected.getVolumes(), actual.getVolumes());
111106
addSets("imagePullSecrets", expected.getImagePullSecrets(), actual.getImagePullSecrets());
112107
addContainerChecks(expected.getContainers(), actual.getContainers());
113108
}
114109

115-
private List<V1Volume> relevantVolumes(List<V1Volume> volumes) {
116-
if (volumes == null) return volumes;
117-
return volumes
118-
.stream()
119-
.filter(m -> !volumesToIgnore.contains(m.getName()))
120-
.collect(Collectors.toList());
121-
}
122-
123110
private void addContainerChecks(
124111
List<V1Container> expectedContainers, List<V1Container> actualContainers) {
125112
Map<String, V1Container> expected = createMap(expectedContainers);
@@ -142,7 +129,7 @@ private void addContainerChecks(
142129

143130
private ContainerCompatibility createCompatibilityCheck(
144131
V1Container expected, V1Container actual) {
145-
return new ContainerCompatibility(expected, actual, volumesToIgnore);
132+
return new ContainerCompatibility(expected, actual);
146133
}
147134

148135
private Map<String, V1Container> createMap(List<V1Container> containers) {
@@ -156,10 +143,8 @@ private Map<String, V1Container> createMap(List<V1Container> containers) {
156143

157144
static class ContainerCompatibility extends CollectiveCompatibility {
158145
private final String name;
159-
private List<String> volumesToIgnore;
160146

161-
ContainerCompatibility(V1Container expected, V1Container actual, List<String> volumesToIgnore) {
162-
this.volumesToIgnore = volumesToIgnore;
147+
ContainerCompatibility(V1Container expected, V1Container actual) {
163148
this.name = expected.getName();
164149

165150
add("image", expected.getImage(), actual.getImage());
@@ -168,7 +153,7 @@ static class ContainerCompatibility extends CollectiveCompatibility {
168153
add(new Probes("liveness", expected.getLivenessProbe(), actual.getLivenessProbe()));
169154
add(new Probes("readiness", expected.getReadinessProbe(), actual.getReadinessProbe()));
170155
add(new EqualResources(expected.getResources(), actual.getResources()));
171-
addSets("volumeMounts", expected.getVolumeMounts(), relevantMounts(actual.getVolumeMounts()));
156+
addSets("volumeMounts", expected.getVolumeMounts(), actual.getVolumeMounts());
172157
addSets("ports", expected.getPorts(), actual.getPorts());
173158
addSets("env", expected.getEnv(), actual.getEnv());
174159
addSets("envFrom", expected.getEnvFrom(), actual.getEnvFrom());
@@ -183,14 +168,6 @@ String getHeader() {
183168
String getIndent() {
184169
return " ";
185170
}
186-
187-
private List<V1VolumeMount> relevantMounts(List<V1VolumeMount> volumeMounts) {
188-
if (volumeMounts == null) return volumeMounts;
189-
return volumeMounts
190-
.stream()
191-
.filter(m -> !volumesToIgnore.contains(m.getName()))
192-
.collect(Collectors.toList());
193-
}
194171
}
195172

196173
static class Mismatch implements CompatibilityCheck {

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

Lines changed: 38 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import java.util.Collections;
3232
import java.util.List;
3333
import java.util.Map;
34-
import java.util.Objects;
3534
import java.util.Optional;
3635
import javax.json.Json;
3736
import javax.json.JsonPatchBuilder;
@@ -92,7 +91,7 @@ private void createSubstitutionMap() {
9291
substitutionVariables.put("ADMIN_PORT", getAsPort().toString());
9392
}
9493

95-
private V1Pod getPodModel() {
94+
V1Pod getPodModel() {
9695
return podModel;
9796
}
9897

@@ -168,10 +167,6 @@ private String getLogHome() {
168167
return getDomain().getLogHome();
169168
}
170169

171-
protected boolean isDomainHomeInImage() {
172-
return getDomain().isDomainHomeInImage();
173-
}
174-
175170
private String getEffectiveLogHome() {
176171
if (!getDomain().getLogHomeEnabled()) return null;
177172
String logHome = getLogHome();
@@ -280,7 +275,15 @@ private Step deletePod(Step next) {
280275
* @return a step to be scheduled.
281276
*/
282277
Step createPod(Step next) {
283-
return new CallBuilder().createPodAsync(getNamespace(), getPodModel(), createResponse(next));
278+
return createPodAsync(createResponse(next));
279+
}
280+
281+
private Step createPodAsync(ResponseStep<V1Pod> response) {
282+
return new CallBuilder().createPodAsync(getNamespace(), getPodModelWithChecksum(), response);
283+
}
284+
285+
private V1Pod getPodModelWithChecksum() {
286+
return AnnotationHelper.withSha256Hash(getPodModel());
284287
}
285288

286289
/**
@@ -298,7 +301,7 @@ Step createPod(Step next) {
298301
* @return a step to be scheduled.
299302
*/
300303
private Step replacePod(Step next) {
301-
return new CallBuilder().createPodAsync(getNamespace(), getPodModel(), replaceResponse(next));
304+
return createPodAsync(replaceResponse(next));
302305
}
303306

304307
private Step patchCurrentPod(V1Pod currentPod, Step next) {
@@ -364,47 +367,15 @@ private boolean mustPatchPod(V1Pod currentPod) {
364367
}
365368

366369
private boolean canUseCurrentPod(V1Pod currentPod) {
367-
List<String> ignoring = getVolumesToIgnore(currentPod);
368-
369-
PodCompatibility compatibility = new PodCompatibility(getPodModel(), currentPod, ignoring);
370-
return compatibility.isCompatible();
370+
return AnnotationHelper.getHash(getPodModel()).equals(AnnotationHelper.getHash(currentPod));
371371
}
372372

373373
private String getReasonToRecycle(V1Pod currentPod) {
374-
List<String> ignoring = getVolumesToIgnore(currentPod);
375374

376-
PodCompatibility compatibility = new PodCompatibility(getPodModel(), currentPod, ignoring);
375+
PodCompatibility compatibility = new PodCompatibility(getPodModel(), currentPod);
377376
return compatibility.getIncompatibility();
378377
}
379378

380-
private static List<String> getVolumesToIgnore(V1Pod current) {
381-
List<String> k8sVolumeNames = new ArrayList<>();
382-
for (V1Container container : getContainers(current))
383-
for (V1VolumeMount mount : getVolumeMounts(container))
384-
if (PodDefaults.K8S_SERVICE_ACCOUNT_MOUNT_PATH.equals(mount.getMountPath()))
385-
k8sVolumeNames.add(mount.getName());
386-
387-
return k8sVolumeNames;
388-
}
389-
390-
private static List<V1Container> getContainers(V1Pod current) {
391-
return Optional.ofNullable(current.getSpec().getContainers()).orElse(Collections.emptyList());
392-
}
393-
394-
private static List<V1VolumeMount> getVolumeMounts(V1Container container) {
395-
return Optional.ofNullable(container.getVolumeMounts()).orElse(Collections.emptyList());
396-
}
397-
398-
private static boolean isRestartVersionValid(V1ObjectMeta build, V1ObjectMeta current) {
399-
return isLabelSame(build, current, LabelConstants.DOMAINRESTARTVERSION_LABEL)
400-
&& isLabelSame(build, current, LabelConstants.CLUSTERRESTARTVERSION_LABEL)
401-
&& isLabelSame(build, current, LabelConstants.SERVERRESTARTVERSION_LABEL);
402-
}
403-
404-
private static boolean isLabelSame(V1ObjectMeta build, V1ObjectMeta current, String labelName) {
405-
return Objects.equals(build.getLabels().get(labelName), current.getLabels().get(labelName));
406-
}
407-
408379
private class VerifyPodStep extends Step {
409380

410381
VerifyPodStep(Step next) {
@@ -602,16 +573,36 @@ public NextAction onSuccess(
602573
// ---------------------- model methods ------------------------------
603574

604575
private V1Pod createPodModel() {
576+
return withPatchableElements(AnnotationHelper.withSha256Hash(createPodRecipe()));
577+
}
578+
579+
// Adds labels and annotations to a pod, skipping any whose names begin with "weblogic."
580+
private V1Pod withPatchableElements(V1Pod pod) {
581+
V1ObjectMeta metadata = pod.getMetadata();
582+
getPodLabels()
583+
.entrySet()
584+
.stream()
585+
.filter(PodStepContext::isCustomerItem)
586+
.forEach(e -> metadata.putLabelsItem(e.getKey(), e.getValue()));
587+
getPodAnnotations()
588+
.entrySet()
589+
.stream()
590+
.filter(PodStepContext::isCustomerItem)
591+
.forEach(e -> metadata.putAnnotationsItem(e.getKey(), e.getValue()));
592+
return pod;
593+
}
594+
595+
private static boolean isCustomerItem(Map.Entry<String, String> entry) {
596+
return !entry.getKey().startsWith("weblogic.");
597+
}
598+
599+
// Creates a pod model containing elements which are not patchable.
600+
private V1Pod createPodRecipe() {
605601
return new V1Pod().metadata(createMetadata()).spec(createSpec(TuningParameters.getInstance()));
606602
}
607603

608604
protected V1ObjectMeta createMetadata() {
609605
V1ObjectMeta metadata = new V1ObjectMeta().name(getPodName()).namespace(getNamespace());
610-
// Add custom labels
611-
getPodLabels().forEach(metadata::putLabelsItem);
612-
613-
// Add internal labels. This will overwrite any custom labels that conflict with internal
614-
// labels.
615606
metadata
616607
.putLabelsItem(LabelConstants.RESOURCE_VERSION_LABEL, DEFAULT_DOMAIN_VERSION)
617608
.putLabelsItem(LabelConstants.DOMAINUID_LABEL, getDomainUID())
@@ -625,9 +616,6 @@ LabelConstants.CLUSTERRESTARTVERSION_LABEL, getServerSpec().getClusterRestartVer
625616
.putLabelsItem(
626617
LabelConstants.SERVERRESTARTVERSION_LABEL, getServerSpec().getServerRestartVersion());
627618

628-
// Add custom annotations
629-
getPodAnnotations().forEach(metadata::putAnnotationsItem);
630-
631619
// Add prometheus annotations. This will overwrite any custom annotations with same name.
632620
AnnotationHelper.annotateForPrometheus(metadata, getDefaultPort());
633621
return metadata;

operator/src/main/java/oracle/kubernetes/operator/wlsconfig/WlsServerConfig.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved.
1+
// Copyright 2017, 2019, Oracle Corporation and/or its affiliates. All rights reserved.
22
// Licensed under the Universal Permissive License v 1.0 as shown at
33
// http://oss.oracle.com/licenses/upl.
44

@@ -91,6 +91,11 @@ public List<NetworkAccessPoint> getNetworkAccessPoints() {
9191
return networkAccessPoints;
9292
}
9393

94+
public void addNetworkAccessPoint(NetworkAccessPoint networkAccessPoint) {
95+
if (networkAccessPoints == null) networkAccessPoints = new ArrayList<>();
96+
networkAccessPoints.add(networkAccessPoint);
97+
}
98+
9499
public String getClusterName() {
95100
return this.clusterName;
96101
}
@@ -107,6 +112,10 @@ public void setAdminPort(Integer adminPort) {
107112
this.adminPort = adminPort;
108113
}
109114

115+
public void setListenPort(Integer listenPort) {
116+
this.listenPort = listenPort;
117+
}
118+
110119
public boolean isAdminPortEnabled() {
111120
return adminPort != null;
112121
}

0 commit comments

Comments
 (0)