Skip to content

Commit 530486c

Browse files
metacosmcsviri
authored andcommitted
feat: add resource metadata to Context and ControllerExecution
Fixes #1324.
1 parent 2894e53 commit 530486c

File tree

10 files changed

+101
-28
lines changed

10 files changed

+101
-28
lines changed

micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import io.javaoperatorsdk.operator.OperatorException;
1010
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
11+
import io.javaoperatorsdk.operator.api.reconciler.Constants;
1112
import io.javaoperatorsdk.operator.api.reconciler.RetryInfo;
1213
import io.javaoperatorsdk.operator.processing.event.Event;
1314
import io.javaoperatorsdk.operator.processing.event.ResourceID;
@@ -27,9 +28,18 @@ public MicrometerMetrics(MeterRegistry registry) {
2728
public <T> T timeControllerExecution(ControllerExecution<T> execution) {
2829
final var name = execution.controllerName();
2930
final var execName = PREFIX + "controllers.execution." + execution.name();
31+
final var resourceID = execution.resourceID();
32+
final var metadata = execution.metadata();
3033
final var timer =
3134
Timer.builder(execName)
32-
.tags("controller", name)
35+
.tags(
36+
"controller", name,
37+
"resource.name", resourceID.getName(),
38+
"resource.namespace", resourceID.getNamespace().orElse(""),
39+
"resource.scope", resourceID.getNamespace().isPresent() ? "namespace" : "cluster",
40+
"resource.group", metadata.get(Constants.RESOURCE_GROUP_KEY).toString(),
41+
"resource.version", metadata.get(Constants.RESOURCE_VERSION_KEY).toString(),
42+
"resource.kind", metadata.get(Constants.RESOURCE_KIND_KEY).toString())
3343
.publishPercentiles(0.3, 0.5, 0.95)
3444
.publishPercentileHistogram()
3545
.register(registry);
@@ -113,9 +123,9 @@ private void incrementCounter(ResourceID id, String counterName, Map<String, Obj
113123
tags.addAll(List.of(additionalTags));
114124
}
115125
if (metadataNb > 0) {
116-
addReservedMetadataToTags(metadata, tags, "group", Metrics.RESOURCE_GROUP_KEY);
117-
addReservedMetadataToTags(metadata, tags, "version", Metrics.RESOURCE_VERSION_KEY);
118-
addReservedMetadataToTags(metadata, tags, "kind", Metrics.RESOURCE_KIND_KEY);
126+
addReservedMetadataToTags(metadata, tags, "group", Constants.RESOURCE_GROUP_KEY);
127+
addReservedMetadataToTags(metadata, tags, "version", Constants.RESOURCE_VERSION_KEY);
128+
addReservedMetadataToTags(metadata, tags, "kind", Constants.RESOURCE_KIND_KEY);
119129
metadata.forEach((k, v) -> {
120130
tags.add(k);
121131
tags.add(v.toString());

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/monitoring/Metrics.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
public interface Metrics {
1111
Metrics NOOP = new Metrics() {};
1212

13-
String RESOURCE_GROUP_KEY = "josdk.resource.group";
14-
String RESOURCE_VERSION_KEY = "josdk.resource.version";
15-
String RESOURCE_KIND_KEY = "josdk.resource.kind";
16-
1713
default void receivedEvent(Event event) {}
1814

1915
/**
@@ -72,6 +68,10 @@ interface ControllerExecution<T> {
7268

7369
String successTypeName(T result);
7470

71+
ResourceID resourceID();
72+
73+
Map<String, Object> metadata();
74+
7575
T execute() throws Exception;
7676
}
7777

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,9 @@ public final class Constants {
1919
public static final long NO_RECONCILIATION_MAX_INTERVAL = -1L;
2020
public static final String SAME_AS_CONTROLLER = "JOSDK_SAME_AS_CONTROLLER";
2121

22+
public static final String RESOURCE_GROUP_KEY = "josdk.resource.group";
23+
public static final String RESOURCE_VERSION_KEY = "josdk.resource.version";
24+
public static final String RESOURCE_KIND_KEY = "josdk.resource.kind";
25+
2226
private Constants() {}
2327
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package io.javaoperatorsdk.operator.api.reconciler;
22

3+
import java.util.HashMap;
4+
import java.util.Map;
35
import java.util.Optional;
46
import java.util.Set;
57

68
import io.fabric8.kubernetes.api.model.HasMetadata;
79
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
810
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext;
11+
import io.javaoperatorsdk.operator.processing.event.ResourceID;
912

1013
public interface Context<P extends HasMetadata> {
1114

@@ -22,4 +25,21 @@ default <T> Optional<T> getSecondaryResource(Class<T> expectedType) {
2225
ControllerConfiguration<P> getControllerConfiguration();
2326

2427
ManagedDependentResourceContext managedDependentResourceContext();
28+
29+
ResourceID currentlyReconciledResourceID();
30+
31+
Map<String, Object> metadata();
32+
33+
static Map<String, Object> metadataFor(HasMetadata resource) {
34+
final var metadata = new HashMap<String, Object>();
35+
fillMetadataFor(resource, metadata);
36+
return metadata;
37+
}
38+
39+
static void fillMetadataFor(HasMetadata resource, Map<String, Object> metadata) {
40+
final Class<? extends HasMetadata> resourceClass = resource.getClass();
41+
metadata.put(Constants.RESOURCE_GROUP_KEY, HasMetadata.getGroup(resourceClass));
42+
metadata.put(Constants.RESOURCE_KIND_KEY, resource.getKind());
43+
metadata.put(Constants.RESOURCE_VERSION_KEY, HasMetadata.getVersion(resourceClass));
44+
}
2545
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.javaoperatorsdk.operator.api.reconciler;
22

3+
import java.util.Map;
34
import java.util.Optional;
45
import java.util.Set;
56
import java.util.stream.Collectors;
@@ -9,6 +10,7 @@
910
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DefaultManagedDependentResourceContext;
1011
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext;
1112
import io.javaoperatorsdk.operator.processing.Controller;
13+
import io.javaoperatorsdk.operator.processing.event.ResourceID;
1214

1315
public class DefaultContext<P extends HasMetadata> implements Context<P> {
1416

@@ -17,13 +19,16 @@ public class DefaultContext<P extends HasMetadata> implements Context<P> {
1719
private final P primaryResource;
1820
private final ControllerConfiguration<P> controllerConfiguration;
1921
private final DefaultManagedDependentResourceContext defaultManagedDependentResourceContext;
22+
private final Map<String, Object> metadata;
2023

21-
public DefaultContext(RetryInfo retryInfo, Controller<P> controller, P primaryResource) {
24+
public DefaultContext(RetryInfo retryInfo, Controller<P> controller, P primaryResource,
25+
Map<String, Object> metadata) {
2226
this.retryInfo = retryInfo;
2327
this.controller = controller;
2428
this.primaryResource = primaryResource;
2529
this.controllerConfiguration = controller.getConfiguration();
2630
this.defaultManagedDependentResourceContext = new DefaultManagedDependentResourceContext();
31+
this.metadata = metadata;
2732
}
2833

2934
@Override
@@ -32,7 +37,6 @@ public Optional<RetryInfo> getRetryInfo() {
3237
}
3338

3439
@Override
35-
@SuppressWarnings("unchecked")
3640
public <T> Set<T> getSecondaryResources(Class<T> expectedType) {
3741
return controller.getEventSourceManager().getEventSourcesFor(expectedType).stream()
3842
.map(es -> es.getSecondaryResources(primaryResource))
@@ -58,6 +62,16 @@ public ManagedDependentResourceContext managedDependentResourceContext() {
5862
return defaultManagedDependentResourceContext;
5963
}
6064

65+
@Override
66+
public ResourceID currentlyReconciledResourceID() {
67+
return ResourceID.fromResource(primaryResource);
68+
}
69+
70+
@Override
71+
public Map<String, Object> metadata() {
72+
return metadata;
73+
}
74+
6175
public DefaultContext<P> setRetryInfo(RetryInfo retryInfo) {
6276
this.retryInfo = retryInfo;
6377
return this;

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.javaoperatorsdk.operator.processing;
22

3+
import java.util.Map;
34
import java.util.Optional;
45
import java.util.Set;
56

@@ -36,6 +37,7 @@
3637
import io.javaoperatorsdk.operator.processing.dependent.workflow.ManagedWorkflow;
3738
import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowCleanupResult;
3839
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
40+
import io.javaoperatorsdk.operator.processing.event.ResourceID;
3941

4042
import static io.javaoperatorsdk.operator.api.reconciler.Constants.WATCH_CURRENT_NAMESPACE;
4143

@@ -96,6 +98,16 @@ public String successTypeName(UpdateControl<P> result) {
9698
return successType;
9799
}
98100

101+
@Override
102+
public ResourceID resourceID() {
103+
return context.currentlyReconciledResourceID();
104+
}
105+
106+
@Override
107+
public Map<String, Object> metadata() {
108+
return context.metadata();
109+
}
110+
99111
@Override
100112
public UpdateControl<P> execute() throws Exception {
101113
initContextIfNeeded(resource, context);
@@ -130,6 +142,16 @@ public String successTypeName(DeleteControl deleteControl) {
130142
return deleteControl.isRemoveFinalizer() ? "delete" : "finalizerNotRemoved";
131143
}
132144

145+
@Override
146+
public ResourceID resourceID() {
147+
return context.currentlyReconciledResourceID();
148+
}
149+
150+
@Override
151+
public Map<String, Object> metadata() {
152+
return context.metadata();
153+
}
154+
133155
@Override
134156
public DeleteControl execute() {
135157
initContextIfNeeded(resource, context);

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider;
1515
import io.javaoperatorsdk.operator.api.config.ExecutorServiceManager;
1616
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
17+
import io.javaoperatorsdk.operator.api.reconciler.Context;
1718
import io.javaoperatorsdk.operator.processing.LifecycleAware;
1819
import io.javaoperatorsdk.operator.processing.MDCUtils;
1920
import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter;
@@ -41,7 +42,6 @@ class EventProcessor<R extends HasMetadata> implements EventHandler, LifecycleAw
4142
private final Cache<R> cache;
4243
private final EventSourceManager<R> eventSourceManager;
4344
private final RateLimiter<? extends RateLimitState> rateLimiter;
44-
4545
private final ResourceStateManager resourceStateManager = new ResourceStateManager();
4646

4747
EventProcessor(EventSourceManager<R> eventSourceManager) {
@@ -147,11 +147,10 @@ private void submitReconciliationExecution(ResourceState state) {
147147
}
148148
state.setUnderProcessing(true);
149149
final var latest = maybeLatest.get();
150-
state.addMetadata(latest);
151-
final var retryInfo = state.getRetry();
152-
ExecutionScope<R> executionScope = new ExecutionScope<>(latest, retryInfo);
150+
Context.fillMetadataFor(latest, state.mutableMetadata());
151+
ExecutionScope<R> executionScope = new ExecutionScope<>(latest, state.getRetry());
153152
state.unMarkEventReceived();
154-
metrics.reconcileCustomResource(state.getId(), retryInfo, state.getMetadata());
153+
metrics.reconcileCustomResource(state.getId(), state.getRetry(), state.immutableMetadata());
155154
log.debug("Executing events for custom resource. Scope: {}", executionScope);
156155
executor.execute(new ControllerExecution(executionScope));
157156
} else {
@@ -242,7 +241,7 @@ synchronized void eventProcessingFinished(
242241
return;
243242
}
244243
cleanupOnSuccessfulExecution(executionScope);
245-
metrics.finishedReconciliation(resourceID, state.getMetadata());
244+
metrics.finishedReconciliation(resourceID, state.immutableMetadata());
246245
if (state.deleteEventPresent()) {
247246
cleanupForDeletedEvent(executionScope.getResourceID());
248247
} else if (postExecutionControl.isFinalizerRemoved()) {
@@ -309,7 +308,7 @@ private void handleRetryOnException(
309308
"Scheduling timer event for retry with delay:{} for resource: {}",
310309
delay,
311310
resourceID);
312-
metrics.failedReconciliation(resourceID, exception, state.getMetadata());
311+
metrics.failedReconciliation(resourceID, exception, state.immutableMetadata());
313312
retryEventSource().scheduleOnce(resourceID, delay);
314313
},
315314
() -> log.error("Exhausted retries for {}", executionScope));
@@ -337,7 +336,7 @@ private ResourceState getOrInitRetryExecution(ExecutionScope<R> executionScope)
337336
private void cleanupForDeletedEvent(ResourceID resourceID) {
338337
log.debug("Cleaning up for delete event for: {}", resourceID);
339338
final var state = resourceStateManager.remove(resourceID);
340-
metrics.cleanupDoneFor(resourceID, state.getMetadata());
339+
metrics.cleanupDoneFor(resourceID, state.immutableMetadata());
341340
}
342341

343342
private boolean isControllerUnderExecution(ResourceState state) {

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExecutionScope.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package io.javaoperatorsdk.operator.processing.event;
22

3+
import java.util.Map;
4+
35
import io.fabric8.kubernetes.api.model.HasMetadata;
6+
import io.javaoperatorsdk.operator.api.reconciler.Context;
47
import io.javaoperatorsdk.operator.api.reconciler.RetryInfo;
58

69
class ExecutionScope<R extends HasMetadata> {
@@ -9,7 +12,7 @@ class ExecutionScope<R extends HasMetadata> {
912
private final R resource;
1013
private final RetryInfo retryInfo;
1114

12-
public ExecutionScope(R resource, RetryInfo retryInfo) {
15+
ExecutionScope(R resource, RetryInfo retryInfo) {
1316
this.resource = resource;
1417
this.retryInfo = retryInfo;
1518
}
@@ -35,4 +38,8 @@ public String toString() {
3538
public RetryInfo getRetryInfo() {
3639
return retryInfo;
3740
}
41+
42+
public Map<String, Object> resourceMetadata() {
43+
return Context.metadataFor(resource);
44+
}
3845
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ private PostExecutionControl<R> handleDispatch(ExecutionScope<R> executionScope)
7979
}
8080

8181
Context<R> context =
82-
new DefaultContext<>(executionScope.getRetryInfo(), controller, originalResource);
82+
new DefaultContext<>(executionScope.getRetryInfo(), controller, originalResource,
83+
executionScope.resourceMetadata());
8384
if (markedForDeletion) {
8485
return handleCleanup(resourceForExecution, context);
8586
} else {

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceState.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package io.javaoperatorsdk.operator.processing.event;
22

3+
import java.util.Collections;
34
import java.util.HashMap;
45
import java.util.Map;
56

6-
import io.fabric8.kubernetes.api.model.HasMetadata;
7-
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
87
import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter.RateLimitState;
98
import io.javaoperatorsdk.operator.processing.retry.RetryExecution;
109

@@ -116,14 +115,11 @@ public void unMarkEventReceived() {
116115
}
117116
}
118117

119-
public Map<String, Object> getMetadata() {
118+
Map<String, Object> mutableMetadata() {
120119
return metadata;
121120
}
122121

123-
public void addMetadata(HasMetadata resource) {
124-
final Class<? extends HasMetadata> resourceClass = resource.getClass();
125-
metadata.put(Metrics.RESOURCE_GROUP_KEY, HasMetadata.getGroup(resourceClass));
126-
metadata.put(Metrics.RESOURCE_KIND_KEY, resource.getKind());
127-
metadata.put(Metrics.RESOURCE_VERSION_KEY, HasMetadata.getVersion(resourceClass));
122+
public Map<String, Object> immutableMetadata() {
123+
return Collections.unmodifiableMap(metadata);
128124
}
129125
}

0 commit comments

Comments
 (0)