Skip to content

Commit d738226

Browse files
committed
feat: DependentResource is now a class that's populated from config
1 parent c0d5607 commit d738226

File tree

6 files changed

+207
-14
lines changed

6 files changed

+207
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.javaoperatorsdk.operator.api.reconciler.dependent;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
5+
@FunctionalInterface
6+
public interface Builder<R extends HasMetadata> {
7+
R build();
8+
}
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,57 @@
11
package io.javaoperatorsdk.operator.api.reconciler.dependent;
22

33
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
import io.javaoperatorsdk.operator.api.config.dependent.DefaultDependentResourceConfiguration;
45
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration;
56
import io.javaoperatorsdk.operator.processing.event.ResourceID;
67
import io.javaoperatorsdk.operator.processing.event.source.ResourceCache;
8+
import io.javaoperatorsdk.operator.processing.event.source.ResourceEventSource;
79

8-
public interface DependentResource<R extends HasMetadata> {
9-
default R build() {
10+
public class DependentResource<R extends HasMetadata> {
11+
12+
private final DefaultDependentResourceConfiguration<R> configuration;
13+
private final Builder<R> builder;
14+
private final Updater<R> updater;
15+
private final Fetcher<R> fetcher;
16+
private ResourceEventSource<R> source;
17+
18+
public DependentResource(DefaultDependentResourceConfiguration<R> configuration,
19+
Builder<R> builder, Updater<R> updater, Fetcher<R> fetcher) {
20+
this.configuration = configuration;
21+
this.builder = builder;
22+
this.updater = updater;
23+
this.fetcher = fetcher;
24+
}
25+
26+
public R build() {
1027
if (getConfiguration().creatable()) {
1128
throw new IllegalStateException(
1229
"Should be implemented if DependentResource is configured as creatable");
1330
}
1431
throw new IllegalStateException("Should not be called if DependentResource is not creatable");
1532
}
1633

17-
ResourceCache<R> getCache();
34+
public ResourceCache<R> getCache() {
35+
return source.getResourceCache();
36+
}
1837

19-
default R fetchFor(HasMetadata owner) {
38+
public R fetchFor(HasMetadata owner) {
2039
return getCache().get(ResourceID.fromResource(owner)).orElse(null);
2140
}
2241

23-
DependentResourceConfiguration<R> getConfiguration();
42+
public DependentResourceConfiguration<R> getConfiguration() {
43+
return configuration;
44+
}
2445

25-
default R update(R fetched) {
46+
public R update(R fetched) {
2647
if (getConfiguration().updatable()) {
2748
throw new IllegalStateException(
2849
"Should be implemented if DependentResource is configured as updatable");
2950
}
3051
throw new IllegalStateException("Should not be called if DependentResource is not updatable");
3152
}
3253

54+
public void setSource(ResourceEventSource<R> source) {
55+
this.source = source;
56+
}
3357
}

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

+62-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package io.javaoperatorsdk.operator.api.reconciler.dependent;
22

33
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
import io.javaoperatorsdk.operator.processing.event.source.ResourceCache;
5+
import io.javaoperatorsdk.operator.processing.event.source.ResourceEventFilter;
6+
7+
import static io.javaoperatorsdk.operator.api.reconciler.Constants.EMPTY_STRING;
48

59
public @interface DependentResourceConfiguration {
610
boolean CREATABLE_DEFAULT = true;
@@ -13,5 +17,62 @@
1317

1418
boolean owned() default OWNED_DEFAULT;
1519

16-
Class<? extends DependentResource<? extends HasMetadata>> impl();
20+
Class<? extends HasMetadata> resourceType();
21+
22+
Class<? extends Builder> builder() default DEFAULT_BUILDER.class;
23+
24+
Class<? extends Updater> updater() default DEFAULT_UPDATER.class;
25+
26+
Class<? extends Fetcher> fetcher() default DEFAULT_FETCHER.class;
27+
28+
/**
29+
* Specified which namespaces this Controller monitors for custom resources events. If no
30+
* namespace is specified then the controller will monitor all namespaces by default.
31+
*
32+
* @return the list of namespaces this controller monitors
33+
*/
34+
String[] namespaces() default {};
35+
36+
/**
37+
* Optional label selector used to identify the set of custom resources the controller will acc
38+
* upon. The label selector can be made of multiple comma separated requirements that acts as a
39+
* logical AND operator.
40+
*
41+
* @return the label selector
42+
*/
43+
String labelSelector() default EMPTY_STRING;
44+
45+
46+
/**
47+
* Optional list of classes providing custom {@link ResourceEventFilter}.
48+
*
49+
* @return the list of event filters.
50+
*/
51+
@SuppressWarnings("rawtypes")
52+
Class<ResourceEventFilter>[] eventFilters() default {};
53+
54+
55+
final class DEFAULT_BUILDER implements Builder {
56+
57+
@Override
58+
public HasMetadata build() {
59+
return null;
60+
}
61+
}
62+
63+
final class DEFAULT_UPDATER implements Updater {
64+
65+
@Override
66+
public HasMetadata update(HasMetadata fetched) {
67+
return null;
68+
}
69+
}
70+
71+
final class DEFAULT_FETCHER implements Fetcher {
72+
73+
@Override
74+
public HasMetadata fetchFor(HasMetadata owner, ResourceCache cache) {
75+
return null;
76+
}
77+
}
1778
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.javaoperatorsdk.operator.api.reconciler.dependent;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
import io.javaoperatorsdk.operator.processing.event.ResourceID;
5+
import io.javaoperatorsdk.operator.processing.event.source.ResourceCache;
6+
7+
@FunctionalInterface
8+
public interface Fetcher<R extends HasMetadata> {
9+
Fetcher<? extends HasMetadata> DEFAULT =
10+
(owner, cache) -> cache.get(ResourceID.fromResource(owner)).orElse(null);
11+
12+
@SuppressWarnings("unchecked")
13+
static <T extends HasMetadata> Fetcher<T> defaultFetcher() {
14+
return (Fetcher<T>) DEFAULT;
15+
}
16+
17+
R fetchFor(HasMetadata owner, ResourceCache<R> cache);
18+
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.javaoperatorsdk.operator.api.reconciler.dependent;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
5+
@FunctionalInterface
6+
public interface Updater<R extends HasMetadata> {
7+
8+
R update(R fetched);
9+
}

operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java

+79-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
package io.javaoperatorsdk.operator.config.runtime;
22

3+
import java.lang.reflect.InvocationTargetException;
4+
import java.util.ArrayList;
5+
import java.util.Collections;
6+
import java.util.List;
37
import java.util.Set;
48
import java.util.function.Function;
59

610
import io.fabric8.kubernetes.api.model.HasMetadata;
11+
import io.fabric8.kubernetes.client.CustomResource;
712
import io.javaoperatorsdk.operator.ControllerUtils;
813
import io.javaoperatorsdk.operator.api.config.ConfigurationService;
14+
import io.javaoperatorsdk.operator.api.config.dependent.DefaultDependentResourceConfiguration;
915
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
1016
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
17+
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
18+
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceConfiguration;
1119
import io.javaoperatorsdk.operator.processing.event.source.ResourceEventFilter;
1220
import io.javaoperatorsdk.operator.processing.event.source.ResourceEventFilters;
1321

@@ -81,7 +89,7 @@ public ResourceEventFilter<R, io.javaoperatorsdk.operator.api.config.ControllerC
8189

8290
var filterTypes =
8391
(Class<ResourceEventFilter<R, io.javaoperatorsdk.operator.api.config.ControllerConfiguration<R>>>[]) valueOrDefault(
84-
annotation, ControllerConfiguration::eventFilters, new Object[] {});
92+
annotation, ControllerConfiguration::eventFilters, new Class[] {});
8593
if (filterTypes.length > 0) {
8694
for (var filterType : filterTypes) {
8795
try {
@@ -102,13 +110,77 @@ public ResourceEventFilter<R, io.javaoperatorsdk.operator.api.config.ControllerC
102110
: ResourceEventFilters.passthrough();
103111
}
104112

105-
public static <T> T valueOrDefault(ControllerConfiguration controllerConfiguration,
106-
Function<ControllerConfiguration, T> mapper,
107-
T defaultValue) {
108-
if (controllerConfiguration == null) {
109-
return defaultValue;
113+
@Override
114+
public List<? extends DependentResource> getDependentResources() {
115+
final var dependentConfigs = valueOrDefault(annotation,
116+
ControllerConfiguration::dependents, new DependentResourceConfiguration[] {});
117+
if (dependentConfigs.length > 0) {
118+
final List<DependentResource> result = new ArrayList<>(dependentConfigs.length);
119+
for (DependentResourceConfiguration dependentConfig : dependentConfigs) {
120+
final var creatable = valueOrDefault(dependentConfig,
121+
DependentResourceConfiguration::creatable,
122+
DependentResourceConfiguration.CREATABLE_DEFAULT);
123+
final var updatable = valueOrDefault(dependentConfig,
124+
DependentResourceConfiguration::updatable,
125+
DependentResourceConfiguration.UPDATABLE_DEFAULT);
126+
final var owned = valueOrDefault(dependentConfig,
127+
DependentResourceConfiguration::owned,
128+
DependentResourceConfiguration.OWNED_DEFAULT);
129+
130+
final var resourceType =
131+
valueOrDefault(dependentConfig, DependentResourceConfiguration::resourceType, null);
132+
final var crdName = CustomResource.getCRDName(resourceType);
133+
final var namespaces = Set.of(
134+
valueOrDefault(dependentConfig, DependentResourceConfiguration::namespaces,
135+
new String[] {}));
136+
final var labelSelector =
137+
valueOrDefault(dependentConfig, DependentResourceConfiguration::labelSelector, "");
138+
139+
final DefaultDependentResourceConfiguration<? extends HasMetadata> configuration =
140+
new DefaultDependentResourceConfiguration<>(
141+
crdName, resourceType, namespaces, labelSelector, service, creatable, updatable,
142+
owned,
143+
null, null, true);
144+
145+
final var builder =
146+
valueIfPresentOrNull(dependentConfig, DependentResourceConfiguration::builder,
147+
DependentResourceConfiguration.DEFAULT_BUILDER.class);
148+
final var updater =
149+
valueIfPresentOrNull(dependentConfig, DependentResourceConfiguration::updater,
150+
DependentResourceConfiguration.DEFAULT_UPDATER.class);
151+
final var fetcher =
152+
valueIfPresentOrNull(dependentConfig, DependentResourceConfiguration::fetcher,
153+
DependentResourceConfiguration.DEFAULT_FETCHER.class);
154+
155+
final var dependent = new DependentResource(configuration, builder, updater, fetcher);
156+
result.add(dependent);
157+
}
158+
return result;
110159
} else {
111-
return mapper.apply(controllerConfiguration);
160+
return Collections.emptyList();
161+
}
162+
}
163+
164+
private static <C, T> T valueOrDefault(C annotation, Function<C, T> mapper, T defaultValue) {
165+
return annotation == null ? defaultValue : mapper.apply(annotation);
166+
}
167+
168+
private static <T> T valueIfPresentOrNull(DependentResourceConfiguration annotation,
169+
Function<DependentResourceConfiguration, Class<? extends T>> mapper,
170+
Class<? extends T> defaultValue) {
171+
if (annotation == null) {
172+
return null;
173+
}
174+
175+
final var value = mapper.apply(annotation);
176+
if (defaultValue.equals(value)) {
177+
return null;
178+
}
179+
try {
180+
return value.getConstructor().newInstance();
181+
} catch (InstantiationException | NoSuchMethodException | InvocationTargetException
182+
| IllegalAccessException e) {
183+
throw new RuntimeException(e);
112184
}
113185
}
114186
}

0 commit comments

Comments
 (0)