Skip to content

Commit 6f38c6b

Browse files
authored
Update config maps based on hash like other resources (#2321)
* Update config maps based on hash like other resources
1 parent 3f1c085 commit 6f38c6b

17 files changed

+131
-235
lines changed

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.kubernetes.client.openapi.models.V1beta1PodDisruptionBudgetList;
2929
import oracle.kubernetes.operator.TuningParameters.WatchTuning;
3030
import oracle.kubernetes.operator.helpers.ConfigMapHelper;
31+
import oracle.kubernetes.operator.helpers.SemanticVersion;
3132
import oracle.kubernetes.operator.watcher.WatchListener;
3233
import oracle.kubernetes.operator.work.Step;
3334
import oracle.kubernetes.operator.work.ThreadFactorySingleton;
@@ -64,6 +65,8 @@ public class DomainNamespaces {
6465
private final WatcherControl<V1beta1PodDisruptionBudget, PodDisruptionBudgetWatcher> podDisruptionBudgetWatchers
6566
= new WatcherControl<>(PodDisruptionBudgetWatcher::create, d -> d::dispatchPodDisruptionBudgetWatch);
6667

68+
private final SemanticVersion productVersion;
69+
6770
AtomicBoolean isStopping(String ns) {
6871
return namespaceStoppingMap.computeIfAbsent(ns, (key) -> new AtomicBoolean(false));
6972
}
@@ -78,9 +81,10 @@ boolean isStarting(String ns) {
7881
/**
7982
* Constructs a DomainNamespace object.
8083
*/
81-
DomainNamespaces() {
84+
DomainNamespaces(SemanticVersion productVersion) {
8285
namespaceStatuses.clear();
8386
namespaceStoppingMap.clear();
87+
this.productVersion = productVersion;
8488
}
8589

8690
/**
@@ -176,7 +180,7 @@ Step readExistingResources(String ns, DomainProcessor processor) {
176180
NamespacedResources resources = new NamespacedResources(ns, null);
177181
resources.addProcessing(new DomainResourcesValidation(ns, processor).getProcessors());
178182
resources.addProcessing(createWatcherStartupProcessing(ns, processor));
179-
return Step.chain(ConfigMapHelper.createScriptConfigMapStep(ns), resources.createListSteps());
183+
return Step.chain(ConfigMapHelper.createScriptConfigMapStep(ns, productVersion), resources.createListSteps());
180184
}
181185

182186
public boolean shouldStartNamespace(String ns) {

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import oracle.kubernetes.operator.helpers.NamespaceHelper;
5050
import oracle.kubernetes.operator.helpers.PodDisruptionBudgetHelper;
5151
import oracle.kubernetes.operator.helpers.PodHelper;
52+
import oracle.kubernetes.operator.helpers.SemanticVersion;
5253
import oracle.kubernetes.operator.helpers.ServiceHelper;
5354
import oracle.kubernetes.operator.logging.LoggingContext;
5455
import oracle.kubernetes.operator.logging.LoggingFacade;
@@ -98,6 +99,7 @@ public class DomainProcessorImpl implements DomainProcessor {
9899
private static Map<String, Map<String, DomainPresenceInfo>> DOMAINS = new ConcurrentHashMap<>();
99100
private static final Map<String, Map<String, ScheduledFuture<?>>> statusUpdaters = new ConcurrentHashMap<>();
100101
private final DomainProcessorDelegate delegate;
102+
private final SemanticVersion productVersion;
101103

102104
// Map namespace to map of domainUID to KubernetesEventObjects; tests may replace this value.
103105
@SuppressWarnings({"FieldMayBeFinal", "CanBeFinal"})
@@ -108,7 +110,12 @@ public class DomainProcessorImpl implements DomainProcessor {
108110
private static Map<String, KubernetesEventObjects> namespaceEventK8SObjects = new ConcurrentHashMap<>();
109111

110112
public DomainProcessorImpl(DomainProcessorDelegate delegate) {
113+
this(delegate, null);
114+
}
115+
116+
public DomainProcessorImpl(DomainProcessorDelegate delegate, SemanticVersion productVersion) {
111117
this.delegate = delegate;
118+
this.productVersion = productVersion;
112119
}
113120

114121
private static DomainPresenceInfo getExistingDomainPresenceInfo(String ns, String domainUid) {
@@ -530,7 +537,7 @@ public void dispatchConfigMapWatch(Watch.Response<V1ConfigMap> item) {
530537
case "DELETED":
531538
delegate.runSteps(
532539
ConfigMapHelper.createScriptConfigMapStep(
533-
c.getMetadata().getNamespace()));
540+
c.getMetadata().getNamespace(), productVersion));
534541
break;
535542

536543
case "ERROR":

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class DomainRecheck {
5656
this(domainProcessor, domainNamespaces, false);
5757
}
5858

59-
private DomainRecheck(DomainProcessor domainProcessor, DomainNamespaces domainNamespaces, boolean fullRecheck) {
59+
DomainRecheck(DomainProcessor domainProcessor, DomainNamespaces domainNamespaces, boolean fullRecheck) {
6060
this.domainProcessor = domainProcessor;
6161
this.domainNamespaces = domainNamespaces;
6262
this.fullRecheck = fullRecheck;

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ static class MainDelegateImpl implements MainDelegate, DomainProcessorDelegate {
134134
private final KubernetesVersion kubernetesVersion;
135135
private final Engine engine;
136136
private final DomainProcessor domainProcessor;
137-
private final DomainNamespaces domainNamespaces = new DomainNamespaces();
137+
private final DomainNamespaces domainNamespaces;
138138

139139
public MainDelegateImpl(Properties buildProps, ScheduledExecutorService scheduledExecutorService) {
140140
buildVersion = getBuildVersion(buildProps);
@@ -145,7 +145,9 @@ public MainDelegateImpl(Properties buildProps, ScheduledExecutorService schedule
145145
kubernetesVersion = HealthCheckHelper.performK8sVersionCheck();
146146

147147
engine = new Engine(scheduledExecutorService);
148-
domainProcessor = new DomainProcessorImpl(this);
148+
domainProcessor = new DomainProcessorImpl(this, productVersion);
149+
150+
domainNamespaces = new DomainNamespaces(productVersion);
149151

150152
PodHelper.setProductVersion(productVersion.toString());
151153
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ public NextAction apply(Packet packet) {
116116

117117
@Nonnull
118118
private Step readExistingNamespaces() {
119-
return mainDelegate.getDomainNamespaces().readExistingResources(namespace, mainDelegate.getDomainProcessor());
119+
return mainDelegate.getDomainNamespaces().readExistingResources(
120+
namespace, mainDelegate.getDomainProcessor());
120121
}
121122

122123
private Step createForcedDeletePodStep(V1Pod pod) {

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

Lines changed: 51 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import java.util.Map;
1717
import java.util.Objects;
1818
import java.util.Optional;
19-
import java.util.regex.Pattern;
2019
import java.util.stream.Collectors;
2120
import javax.annotation.Nonnull;
2221

@@ -69,7 +68,7 @@ public class ConfigMapHelper {
6968

7069
private static final String SCRIPT_LOCATION = "/scripts";
7170
private static final String UPDATEDOMAINRESULT = "UPDATEDOMAINRESULT";
72-
private static final ConfigMapComparator COMPARATOR = new ConfigMapComparatorImpl();
71+
private static final ConfigMapComparator COMPARATOR = new ConfigMapComparator();
7372

7473
private static final FileGroupReader scriptReader = new FileGroupReader(SCRIPT_LOCATION);
7574

@@ -82,12 +81,8 @@ private ConfigMapHelper() {
8281
* @param domainNamespace the domain's namespace
8382
* @return Step for creating config map containing scripts
8483
*/
85-
public static Step createScriptConfigMapStep(String domainNamespace) {
86-
return new ScriptConfigMapStep(domainNamespace);
87-
}
88-
89-
static FileGroupReader getScriptReader() {
90-
return scriptReader;
84+
public static Step createScriptConfigMapStep(String domainNamespace, SemanticVersion productVersion) {
85+
return new ScriptConfigMapStep(domainNamespace, productVersion);
9186
}
9287

9388
static Map<String, String> parseIntrospectorResult(String text, String domainUid) {
@@ -162,23 +157,25 @@ public static String getIntrospectorConfigMapName(String domainUid) {
162157
return IntrospectorConfigMapConstants.getIntrospectorConfigMapName(domainUid, 0);
163158
}
164159

165-
abstract static class ConfigMapComparator {
166-
boolean containsAll(V1ConfigMap actual, V1ConfigMap expected) {
167-
return containsAllData(getData(actual), getData(expected));
168-
}
160+
static class ConfigMapComparator {
161+
boolean isOutdated(SemanticVersion productVersion, V1ConfigMap actual, V1ConfigMap expected) {
162+
// Check product version label
163+
if (productVersion != null) {
164+
SemanticVersion currentVersion = KubernetesUtils.getProductVersionFromMetadata(actual.getMetadata());
165+
if (currentVersion == null || productVersion.compareTo(currentVersion) > 0) {
166+
return true;
167+
}
168+
}
169169

170-
private Map<String,String> getData(V1ConfigMap map) {
171-
return Optional.ofNullable(map).map(V1ConfigMap::getData).orElse(Collections.emptyMap());
170+
return !AnnotationHelper.getHash(expected).equals(AnnotationHelper.getHash(actual));
172171
}
173-
174-
abstract boolean containsAllData(Map<String, String> actual, Map<String, String> expected);
175172
}
176173

177174
static class ScriptConfigMapStep extends Step {
178175
final ConfigMapContext context;
179176

180-
ScriptConfigMapStep(String domainNamespace) {
181-
context = new ScriptConfigMapContext(this, domainNamespace);
177+
ScriptConfigMapStep(String domainNamespace, SemanticVersion productVersion) {
178+
context = new ScriptConfigMapContext(this, domainNamespace, productVersion);
182179
}
183180

184181
@Override
@@ -188,25 +185,23 @@ public NextAction apply(Packet packet) {
188185
}
189186

190187
static class ScriptConfigMapContext extends ConfigMapContext {
191-
192-
ScriptConfigMapContext(Step conflictStep, String domainNamespace) {
193-
super(conflictStep, SCRIPT_CONFIG_MAP_NAME, domainNamespace, loadScriptsFromClasspath(domainNamespace), null);
188+
ScriptConfigMapContext(Step conflictStep, String domainNamespace, SemanticVersion productVersion) {
189+
super(conflictStep, SCRIPT_CONFIG_MAP_NAME, domainNamespace,
190+
loadScriptsFromClasspath(domainNamespace), null, productVersion);
194191

195192
addLabel(LabelConstants.OPERATORNAME_LABEL, getOperatorNamespace());
196193
}
197194

198-
private static synchronized Map<String, String> loadScriptsFromClasspath(String domainNamespace) {
199-
Map<String, String> scripts = scriptReader.loadFilesFromClasspath();
200-
LOGGER.fine(MessageKeys.SCRIPT_LOADED, domainNamespace);
201-
return scripts;
202-
}
203-
204195
@Override
205196
void recordCurrentMap(Packet packet, V1ConfigMap configMap) {
206197
packet.put(ProcessingConstants.SCRIPT_CONFIG_MAP, configMap);
207198
}
199+
}
208200

209-
201+
static synchronized Map<String, String> loadScriptsFromClasspath(String domainNamespace) {
202+
Map<String, String> scripts = scriptReader.loadFilesFromClasspath();
203+
LOGGER.fine(MessageKeys.SCRIPT_LOADED, domainNamespace);
204+
return scripts;
210205
}
211206

212207
abstract static class ConfigMapContext extends StepContextBase {
@@ -216,14 +211,21 @@ abstract static class ConfigMapContext extends StepContextBase {
216211
private final String namespace;
217212
private V1ConfigMap model;
218213
private final Map<String, String> labels = new HashMap<>();
214+
protected final SemanticVersion productVersion;
219215

220216
ConfigMapContext(Step conflictStep, String name, String namespace, Map<String, String> contents,
221217
DomainPresenceInfo info) {
218+
this(conflictStep, name, namespace, contents, info, null);
219+
}
220+
221+
ConfigMapContext(Step conflictStep, String name, String namespace, Map<String, String> contents,
222+
DomainPresenceInfo info, SemanticVersion productVersion) {
222223
super(info);
223224
this.conflictStep = conflictStep;
224225
this.name = name;
225226
this.namespace = namespace;
226227
this.contents = contents;
228+
this.productVersion = productVersion;
227229

228230
addLabel(LabelConstants.CREATEDBYOPERATOR_LABEL, "true");
229231
}
@@ -253,15 +255,22 @@ protected V1ConfigMap getModel() {
253255
}
254256

255257
protected final V1ConfigMap createModel(Map<String, String> data) {
256-
return new V1ConfigMap().kind("ConfigMap").apiVersion("v1").metadata(createMetadata()).data(data);
258+
return AnnotationHelper.withSha256Hash(
259+
new V1ConfigMap().kind("ConfigMap").apiVersion("v1").metadata(createMetadata()).data(data), data);
257260
}
258261

259262
private V1ObjectMeta createMetadata() {
260-
return updateForOwnerReference(
263+
V1ObjectMeta metadata = updateForOwnerReference(
261264
new V1ObjectMeta()
262265
.name(name)
263266
.namespace(namespace)
264267
.labels(labels));
268+
269+
if (productVersion != null) {
270+
metadata.putLabelsItem(LabelConstants.OPERATOR_VERSION, productVersion.toString());
271+
}
272+
273+
return metadata;
265274
}
266275

267276
@SuppressWarnings("SameParameterValue")
@@ -283,8 +292,8 @@ Step verifyConfigMap(Step next) {
283292
return new CallBuilder().readConfigMapAsync(getName(), namespace, null, new ReadResponseStep(next));
284293
}
285294

286-
boolean isIncompatibleMap(V1ConfigMap existingMap) {
287-
return !COMPARATOR.containsAll(existingMap, getModel());
295+
boolean isOutdated(V1ConfigMap existingMap) {
296+
return COMPARATOR.isOutdated(productVersion, existingMap, getModel());
288297
}
289298

290299
V1ConfigMap withoutTransientData(V1ConfigMap originalMap) {
@@ -315,8 +324,8 @@ public NextAction onSuccess(Packet packet, CallResponse<V1ConfigMap> callRespons
315324
V1ConfigMap existingMap = withoutTransientData(callResponse.getResult());
316325
if (existingMap == null) {
317326
return doNext(createConfigMap(getNext()), packet);
318-
} else if (isIncompatibleMap(existingMap)) {
319-
return doNext(updateConfigMap(getNext(), existingMap), packet);
327+
} else if (isOutdated(existingMap)) {
328+
return doNext(replaceConfigMap(getNext()), packet);
320329
} else if (mustPatchCurrentMap(existingMap)) {
321330
return doNext(patchCurrentMap(existingMap, getNext()), packet);
322331
} else {
@@ -335,9 +344,9 @@ private void logConfigMapExists() {
335344
LOGGER.fine(MessageKeys.CM_EXISTS, getName(), namespace);
336345
}
337346

338-
private Step updateConfigMap(Step next, V1ConfigMap existingConfigMap) {
347+
private Step replaceConfigMap(Step next) {
339348
return new CallBuilder().replaceConfigMapAsync(name, namespace,
340-
createModel(getCombinedData(existingConfigMap)),
349+
model,
341350
createReplaceResponseStep(next));
342351
}
343352

@@ -370,12 +379,6 @@ private boolean labelsNotDefined(V1ConfigMap currentMap) {
370379
}
371380
}
372381

373-
private Map<String, String> getCombinedData(V1ConfigMap existingConfigMap) {
374-
Map<String, String> updated = Objects.requireNonNull(existingConfigMap.getData());
375-
updated.putAll(contents);
376-
return updated;
377-
}
378-
379382
private ResponseStep<V1ConfigMap> createCreateResponseStep(Step next) {
380383
return new CreateResponseStep(next);
381384
}
@@ -440,15 +443,6 @@ public NextAction onSuccess(Packet packet, CallResponse<V1ConfigMap> callRespons
440443

441444
}
442445

443-
/** Returns true if the actual map contains all of the entries from the expected map. */
444-
static class ConfigMapComparatorImpl extends ConfigMapComparator {
445-
446-
@Override
447-
boolean containsAllData(Map<String, String> actual, Map<String, String> expected) {
448-
return actual.entrySet().containsAll(expected.entrySet());
449-
}
450-
}
451-
452446
/**
453447
* Factory for a step that creates or updates the generated domain config map from introspection results.
454448
* Reads the following packet fields:
@@ -596,7 +590,8 @@ private IntrospectorConfigMapContext createIntrospectorConfigMapContext() {
596590
return createIntrospectorConfigMapContext(data, 0);
597591
}
598592

599-
private IntrospectorConfigMapContext createIntrospectorConfigMapContext(Map<String, String> data, int index) {
593+
private IntrospectorConfigMapContext createIntrospectorConfigMapContext(
594+
Map<String, String> data, int index) {
600595
return new IntrospectorConfigMapContext(conflictStep, info, data, index);
601596
}
602597

@@ -662,11 +657,10 @@ private String perLine(List<String> errors) {
662657

663658
public static class IntrospectorConfigMapContext extends ConfigMapContext implements SplitterTarget {
664659

665-
private static final Pattern ENCODED_ZIP_PATTERN = Pattern.compile("([A-Za-z_]+)\\.secure");
666-
667660
private boolean patchOnly;
668661

669-
IntrospectorConfigMapContext(Step conflictStep, DomainPresenceInfo info, Map<String, String> data, int index) {
662+
IntrospectorConfigMapContext(Step conflictStep, DomainPresenceInfo info,
663+
Map<String, String> data, int index) {
670664
super(conflictStep, getConfigMapName(info, index), info.getNamespace(), data, info);
671665

672666
addLabel(LabelConstants.DOMAINUID_LABEL, info.getDomainUid());
@@ -687,8 +681,8 @@ IntrospectorConfigMapContext patchOnly() {
687681
}
688682

689683
@Override
690-
boolean isIncompatibleMap(V1ConfigMap existingMap) {
691-
return !patchOnly && super.isIncompatibleMap(existingMap);
684+
boolean isOutdated(V1ConfigMap existingMap) {
685+
return !patchOnly && super.isOutdated(existingMap);
692686
}
693687

694688
@Override

0 commit comments

Comments
 (0)