Skip to content

Commit 300dbb6

Browse files
committed
feat: implementation of Kubernetes dependent resources
1 parent b468830 commit 300dbb6

File tree

10 files changed

+399
-10
lines changed

10 files changed

+399
-10
lines changed

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

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

3+
import java.util.Collections;
4+
import java.util.List;
5+
36
import io.fabric8.kubernetes.api.model.HasMetadata;
47
import io.javaoperatorsdk.operator.ReconcilerUtils;
8+
import io.javaoperatorsdk.operator.api.config.dependent.DependentResource;
59
import io.javaoperatorsdk.operator.api.reconciler.Constants;
610
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
711
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilters;
@@ -46,4 +50,8 @@ default boolean useFinalizer() {
4650
default ResourceEventFilter<R> getEventFilter() {
4751
return ResourceEventFilters.passthrough();
4852
}
53+
54+
default List<? extends DependentResource> getDependentResources() {
55+
return Collections.emptyList();
56+
}
4957
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.javaoperatorsdk.operator.api.config.dependent;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
5+
@FunctionalInterface
6+
public interface Builder<R, P extends HasMetadata> {
7+
R buildFor(P primary);
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package io.javaoperatorsdk.operator.api.config.dependent;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializationContext;
5+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
6+
7+
public abstract class DependentResource<R, P extends HasMetadata>
8+
implements Builder<R, P>, Updater<R, P>, Persister<R, P> {
9+
10+
private final Builder<R, P> builder;
11+
private final Updater<R, P> updater;
12+
private final Class<R> resourceType;
13+
14+
public DependentResource(Class<R> resourceType, Builder<R, P> builder, Updater<R, P> updater) {
15+
this.builder = builder;
16+
this.updater = updater;
17+
this.resourceType = resourceType;
18+
}
19+
20+
public String descriptionFor(R resource) {
21+
return resource.toString();
22+
}
23+
24+
@Override
25+
public R buildFor(P primary) {
26+
return builder.buildFor(primary);
27+
}
28+
29+
@Override
30+
public R update(R fetched, P primary) {
31+
return updater.update(fetched, primary);
32+
}
33+
34+
public Class<R> getResourceType() {
35+
return resourceType;
36+
}
37+
38+
public abstract EventSource initEventSource(EventSourceInitializationContext<P> context);
39+
40+
public boolean creatable() {
41+
return builder != null;
42+
}
43+
44+
public boolean updatable() {
45+
return updater != null;
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package io.javaoperatorsdk.operator.api.config.dependent;
2+
3+
import java.util.Set;
4+
5+
import io.fabric8.kubernetes.api.model.HasMetadata;
6+
import io.javaoperatorsdk.operator.processing.event.ResourceID;
7+
import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier;
8+
import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever;
9+
10+
import static io.javaoperatorsdk.operator.api.reconciler.Constants.EMPTY_STRING;
11+
12+
public @interface DependentResourceConfiguration {
13+
boolean OWNED_DEFAULT = true;
14+
boolean SKIP_UPDATE_DEFAULT = true;
15+
16+
boolean owned() default OWNED_DEFAULT;
17+
18+
Class<?> resourceType();
19+
20+
Class<? extends DependentResource<?, ? extends HasMetadata>> dependentType();
21+
22+
Class<? extends Builder> builder() default DEFAULT_BUILDER.class;
23+
24+
Class<? extends Updater> updater() default DEFAULT_UPDATER.class;
25+
26+
Class<? extends PrimaryResourcesRetriever> associatedPrimariesRetriever() default DEFAULT_PRIMARIES_RETRIEVER.class;
27+
28+
Class<? extends AssociatedSecondaryResourceIdentifier> associatedSecondaryIdentifier() default DEFAULT_SECONDARY_IDENTIFIER.class;
29+
30+
boolean skipUpdateIfUnchanged() default SKIP_UPDATE_DEFAULT;
31+
32+
/**
33+
* Specified which namespaces this Controller monitors for custom resources events. If no
34+
* namespace is specified then the controller will monitor all namespaces by default.
35+
*
36+
* @return the list of namespaces this controller monitors
37+
*/
38+
String[] namespaces() default {};
39+
40+
/**
41+
* Optional label selector used to identify the set of custom resources the controller will acc
42+
* upon. The label selector can be made of multiple comma separated requirements that acts as a
43+
* logical AND operator.
44+
*
45+
* @return the label selector
46+
*/
47+
String labelSelector() default EMPTY_STRING;
48+
49+
50+
final class DEFAULT_BUILDER implements Builder<HasMetadata, HasMetadata> {
51+
52+
@Override
53+
public HasMetadata buildFor(HasMetadata primary) {
54+
return null;
55+
}
56+
}
57+
58+
final class DEFAULT_UPDATER implements Updater<HasMetadata, HasMetadata> {
59+
60+
@Override
61+
public HasMetadata update(HasMetadata fetched, HasMetadata primary) {
62+
return null;
63+
}
64+
}
65+
66+
67+
final class DEFAULT_PRIMARIES_RETRIEVER implements PrimaryResourcesRetriever<Object> {
68+
69+
@Override
70+
public Set<ResourceID> associatedPrimaryResources(Object dependentResource) {
71+
return null;
72+
}
73+
}
74+
75+
final class DEFAULT_SECONDARY_IDENTIFIER
76+
implements AssociatedSecondaryResourceIdentifier<HasMetadata> {
77+
78+
@Override
79+
public ResourceID associatedSecondaryID(HasMetadata primary) {
80+
return null;
81+
}
82+
}
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package io.javaoperatorsdk.operator.api.config.dependent;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
import io.fabric8.kubernetes.client.KubernetesClient;
5+
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializationContext;
6+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
7+
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerConfiguration;
8+
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
9+
10+
public class KubernetesDependentResource<R extends HasMetadata, P extends HasMetadata>
11+
extends DependentResource<R, P> {
12+
private final InformerConfiguration<R, P> configuration;
13+
private final boolean owned;
14+
private KubernetesClient client;
15+
private InformerEventSource<R, P> informer;
16+
17+
18+
public KubernetesDependentResource(Class<R> resourceType, boolean owned, Builder<R, P> builder,
19+
Updater<R, P> updater, InformerConfiguration<R, P> configuration) {
20+
super(resourceType, builder, updater);
21+
this.configuration = configuration;
22+
this.owned = owned;
23+
}
24+
25+
@Override
26+
public String descriptionFor(R resource) {
27+
return String.format("'%s' %s dependent in namespace %s", resource.getMetadata().getName(),
28+
resource.getFullResourceName(),
29+
resource.getMetadata().getNamespace());
30+
}
31+
32+
@Override
33+
public EventSource initEventSource(EventSourceInitializationContext<P> context) {
34+
this.client = context.getClient();
35+
informer = new InformerEventSource<>(client.resources(getResourceType()), configuration);
36+
return informer;
37+
}
38+
39+
@Override
40+
public void createOrReplace(R dependentResource) {
41+
client.resource(dependentResource).createOrReplace();
42+
}
43+
44+
@Override
45+
public R getFor(P primary) {
46+
return informer.getAssociated(primary).orElse(null);
47+
}
48+
49+
public boolean owned() {
50+
return owned;
51+
}
52+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.javaoperatorsdk.operator.api.config.dependent;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
5+
public interface Persister<R, P extends HasMetadata> {
6+
7+
void createOrReplace(R dependentResource);
8+
9+
R getFor(P primary);
10+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.javaoperatorsdk.operator.api.config.dependent;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
5+
@FunctionalInterface
6+
public interface Updater<R, P extends HasMetadata> {
7+
8+
R update(R fetched, P primary);
9+
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.lang.annotation.RetentionPolicy;
66
import java.lang.annotation.Target;
77

8+
import io.javaoperatorsdk.operator.api.config.dependent.DependentResource;
9+
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration;
810
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
911

1012
@Retention(RetentionPolicy.RUNTIME)
@@ -56,4 +58,13 @@
5658
*/
5759
@SuppressWarnings("rawtypes")
5860
Class<ResourceEventFilter>[] eventFilters() default {};
61+
62+
/**
63+
* Optional list of classes providing {@link DependentResource} implementations encapsulating
64+
* logic to handle the associated {@link io.javaoperatorsdk.operator.processing.Controller}'s
65+
* reconciliation of dependent resources
66+
*
67+
* @return the list of {@link DependentResource} implementations
68+
*/
69+
DependentResourceConfiguration[] dependents() default {};
5970
}

0 commit comments

Comments
 (0)