Skip to content

Commit 1eb00e7

Browse files
committed
feat: introduce declarative support for dependent resources
1 parent 2e9bd22 commit 1eb00e7

File tree

70 files changed

+1791
-681
lines changed

Some content is hidden

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

70 files changed

+1791
-681
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public Operator(ConfigurationService configurationService) {
3434
public Operator(KubernetesClient kubernetesClient, ConfigurationService configurationService) {
3535
this.kubernetesClient = kubernetesClient;
3636
this.configurationService = configurationService;
37+
ExecutorServiceManager.init(configurationService);
3738
}
3839

3940
/** Adds a shutdown hook that automatically calls {@link #close()} when the app shuts down. */
@@ -85,7 +86,6 @@ public void start() {
8586
throw new OperatorException(error, e);
8687
}
8788

88-
ExecutorServiceManager.init(configurationService);
8989
controllers.start();
9090
}
9191

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Locale;
44

5+
import io.javaoperatorsdk.operator.api.reconciler.Constants;
56
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
67
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
78

@@ -19,7 +20,7 @@ public static String getNameFor(Class<? extends Reconciler> reconcilerClass) {
1920
final var annotation = reconcilerClass.getAnnotation(ControllerConfiguration.class);
2021
if (annotation != null) {
2122
final var name = annotation.name();
22-
if (!ControllerConfiguration.EMPTY_STRING.equals(name)) {
23+
if (!Constants.EMPTY_STRING.equals(name)) {
2324
return name;
2425
}
2526
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Cloner.java

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
public interface Cloner {
66

7+
/**
8+
* Returns a deep copy of the given object if not {@code null} or {@code null} otherwise.
9+
*
10+
* @param object the object to be cloned
11+
* @param <R> the type of the object to be cloned
12+
* @return a deep copy of the given object if it isn't {@code null}, {@code null} otherwise
13+
*/
714
<R extends HasMetadata> R clone(R object);
815

916
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ public interface ConfigurationService {
2121

2222
@Override
2323
public HasMetadata clone(HasMetadata object) {
24+
if (object == null) {
25+
return null;
26+
}
2427
try {
2528
return OBJECT_MAPPER.readValue(OBJECT_MAPPER.writeValueAsString(object), object.getClass());
2629
} catch (JsonProcessingException e) {
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,45 @@
11
package io.javaoperatorsdk.operator.api.config;
22

3-
import java.lang.reflect.ParameterizedType;
43
import java.util.Collections;
5-
import java.util.Set;
4+
import java.util.List;
65

76
import io.fabric8.kubernetes.api.model.HasMetadata;
8-
import io.fabric8.kubernetes.client.CustomResource;
97
import io.javaoperatorsdk.operator.ReconcilerUtils;
108
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
11-
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilters;
9+
import io.javaoperatorsdk.operator.api.reconciler.Constants;
10+
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
1211

13-
public interface ControllerConfiguration<R extends HasMetadata> {
12+
public interface ControllerConfiguration<R extends HasMetadata> extends
13+
ResourceConfiguration<R, ControllerConfiguration<R>> {
1414

1515
default String getName() {
1616
return ReconcilerUtils.getDefaultReconcilerName(getAssociatedReconcilerClassName());
1717
}
1818

19-
default String getResourceTypeName() {
20-
return CustomResource.getCRDName(getResourceClass());
21-
}
22-
2319
default String getFinalizer() {
2420
return ReconcilerUtils.getDefaultFinalizerName(getResourceTypeName());
2521
}
2622

27-
/**
28-
* Retrieves the label selector that is used to filter which custom resources are actually watched
29-
* by the associated controller. See
30-
* https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more details on
31-
* syntax.
32-
*
33-
* @return the label selector filtering watched custom resources
34-
*/
35-
default String getLabelSelector() {
36-
return null;
37-
}
38-
3923
default boolean isGenerationAware() {
4024
return true;
4125
}
4226

43-
default Class<R> getResourceClass() {
44-
ParameterizedType type = (ParameterizedType) getClass().getGenericInterfaces()[0];
45-
return (Class<R>) type.getActualTypeArguments()[0];
46-
}
47-
4827
String getAssociatedReconcilerClassName();
4928

50-
default Set<String> getNamespaces() {
51-
return Collections.emptySet();
52-
}
53-
54-
default boolean watchAllNamespaces() {
55-
return allNamespacesWatched(getNamespaces());
56-
}
57-
58-
static boolean allNamespacesWatched(Set<String> namespaces) {
59-
return namespaces == null || namespaces.isEmpty();
60-
}
61-
62-
default boolean watchCurrentNamespace() {
63-
return currentNamespaceWatched(getNamespaces());
64-
}
65-
66-
static boolean currentNamespaceWatched(Set<String> namespaces) {
67-
return namespaces != null
68-
&& namespaces.size() == 1
69-
&& namespaces.contains(
70-
io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration.WATCH_CURRENT_NAMESPACE);
71-
}
72-
73-
/**
74-
* Computes the effective namespaces based on the set specified by the user, in particular
75-
* retrieves the current namespace from the client when the user specified that they wanted to
76-
* watch the current namespace only.
77-
*
78-
* @return a Set of namespace names the associated controller will watch
79-
*/
80-
default Set<String> getEffectiveNamespaces() {
81-
var targetNamespaces = getNamespaces();
82-
if (watchCurrentNamespace()) {
83-
final var parent = getConfigurationService();
84-
if (parent == null) {
85-
throw new IllegalStateException(
86-
"Parent ConfigurationService must be set before calling this method");
87-
}
88-
targetNamespaces = Collections.singleton(parent.getClientConfiguration().getNamespace());
89-
}
90-
return targetNamespaces;
91-
}
92-
9329
default RetryConfiguration getRetryConfiguration() {
9430
return RetryConfiguration.DEFAULT;
9531
}
9632

97-
ConfigurationService getConfigurationService();
98-
99-
default void setConfigurationService(ConfigurationService service) {}
100-
10133
default boolean useFinalizer() {
102-
return !io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration.NO_FINALIZER
103-
.equals(getFinalizer());
34+
return !Constants.NO_FINALIZER.equals(getFinalizer());
35+
}
36+
37+
@Override
38+
default ResourceEventFilter<R, ControllerConfiguration<R>> getEventFilter() {
39+
return ResourceConfiguration.super.getEventFilter();
10440
}
10541

106-
/**
107-
* Allow controllers to filter events before they are provided to the
108-
* {@link io.javaoperatorsdk.operator.processing.event.EventHandler}. Note that the provided
109-
* filter is combined with {@link #isGenerationAware()} to compute the final set of fiolters that
110-
* should be applied;
111-
*
112-
* @return filter
113-
*/
114-
default ResourceEventFilter<R> getEventFilter() {
115-
return ResourceEventFilters.passthrough();
42+
default List<? extends DependentResource> getDependentResources() {
43+
return Collections.emptyList();
11644
}
11745
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class ControllerConfigurationOverrider<R extends HasMetadata> {
1414
private final Set<String> namespaces;
1515
private RetryConfiguration retry;
1616
private String labelSelector;
17-
private ResourceEventFilter<R> customResourcePredicate;
17+
private ResourceEventFilter<R, ControllerConfiguration<R>> customResourcePredicate;
1818
private final ControllerConfiguration<R> original;
1919

2020
private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
@@ -69,7 +69,7 @@ public ControllerConfigurationOverrider<R> withLabelSelector(String labelSelecto
6969
}
7070

7171
public ControllerConfigurationOverrider<R> withCustomResourcePredicate(
72-
ResourceEventFilter<R> customResourcePredicate) {
72+
ResourceEventFilter<R, ControllerConfiguration<R>> customResourcePredicate) {
7373
this.customResourcePredicate = customResourcePredicate;
7474
return this;
7575
}
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,77 @@
11
package io.javaoperatorsdk.operator.api.config;
22

3-
import java.util.Collections;
43
import java.util.Set;
54

65
import io.fabric8.kubernetes.api.model.HasMetadata;
76
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
87

98
public class DefaultControllerConfiguration<R extends HasMetadata>
9+
extends DefaultResourceConfiguration<R, ControllerConfiguration<R>>
1010
implements ControllerConfiguration<R> {
1111

1212
private final String associatedControllerClassName;
1313
private final String name;
14-
private final String crdName;
1514
private final String finalizer;
16-
private final boolean generationAware;
17-
private final Set<String> namespaces;
18-
private final boolean watchAllNamespaces;
1915
private final RetryConfiguration retryConfiguration;
20-
private final String labelSelector;
21-
private final ResourceEventFilter<R> resourceEventFilter;
22-
private final Class<R> resourceClass;
23-
private ConfigurationService service;
16+
private final ResourceEventFilter<R, ControllerConfiguration<R>> resourceEventFilter;
17+
private final boolean generationAware;
2418

2519
public DefaultControllerConfiguration(
2620
String associatedControllerClassName,
2721
String name,
28-
String crdName,
22+
String resourceName,
2923
String finalizer,
3024
boolean generationAware,
3125
Set<String> namespaces,
3226
RetryConfiguration retryConfiguration,
3327
String labelSelector,
34-
ResourceEventFilter<R> resourceEventFilter,
28+
ResourceEventFilter<R, ControllerConfiguration<R>> resourceEventFilter,
3529
Class<R> resourceClass,
3630
ConfigurationService service) {
31+
super(resourceName, resourceClass, namespaces, labelSelector, service);
3732
this.associatedControllerClassName = associatedControllerClassName;
3833
this.name = name;
39-
this.crdName = crdName;
4034
this.finalizer = finalizer;
4135
this.generationAware = generationAware;
42-
this.namespaces =
43-
namespaces != null ? Collections.unmodifiableSet(namespaces) : Collections.emptySet();
44-
this.watchAllNamespaces = this.namespaces.isEmpty();
4536
this.retryConfiguration =
4637
retryConfiguration == null
4738
? ControllerConfiguration.super.getRetryConfiguration()
4839
: retryConfiguration;
49-
this.labelSelector = labelSelector;
5040
this.resourceEventFilter = resourceEventFilter;
51-
this.resourceClass =
52-
resourceClass == null ? ControllerConfiguration.super.getResourceClass()
53-
: resourceClass;
54-
setConfigurationService(service);
5541
}
5642

5743
@Override
5844
public String getName() {
5945
return name;
6046
}
6147

62-
@Override
63-
public String getResourceTypeName() {
64-
return crdName;
65-
}
66-
6748
@Override
6849
public String getFinalizer() {
6950
return finalizer;
7051
}
7152

72-
@Override
73-
public boolean isGenerationAware() {
74-
return generationAware;
75-
}
76-
7753
@Override
7854
public String getAssociatedReconcilerClassName() {
7955
return associatedControllerClassName;
8056
}
8157

82-
@Override
83-
public Set<String> getNamespaces() {
84-
return namespaces;
85-
}
86-
87-
@Override
88-
public boolean watchAllNamespaces() {
89-
return watchAllNamespaces;
90-
}
91-
9258
@Override
9359
public RetryConfiguration getRetryConfiguration() {
9460
return retryConfiguration;
9561
}
9662

9763
@Override
98-
public ConfigurationService getConfigurationService() {
99-
return service;
100-
}
101-
102-
@Override
103-
public void setConfigurationService(ConfigurationService service) {
104-
if (this.service != null) {
105-
throw new RuntimeException("A ConfigurationService is already associated with '" + name
106-
+ "' ControllerConfiguration. Cannot change it once set!");
107-
}
108-
this.service = service;
109-
}
110-
111-
@Override
112-
public String getLabelSelector() {
113-
return labelSelector;
64+
public boolean isGenerationAware() {
65+
return generationAware;
11466
}
11567

11668
@Override
117-
public Class<R> getResourceClass() {
118-
return resourceClass;
69+
public ResourceEventFilter<R, ControllerConfiguration<R>> getEventFilter() {
70+
return resourceEventFilter;
11971
}
12072

12173
@Override
122-
public ResourceEventFilter<R> getEventFilter() {
123-
return resourceEventFilter;
74+
protected String identifierForException() {
75+
return "'" + name + "' ControllerConfiguration";
12476
}
12577
}

0 commit comments

Comments
 (0)