From 5628db534baae68053dbecfbbf9616966295ade8 Mon Sep 17 00:00:00 2001 From: csviri Date: Mon, 7 Feb 2022 17:10:58 +0100 Subject: [PATCH 01/25] feat: refactor to support standalon mode --- .../dependent/AbstractDependentResource.java | 33 +++++++ .../dependent/DependentResource.java | 50 ++--------- .../KubernetesDependentResource.java | 69 +++++++++++++++ .../dependent/ObservedResource.java | 19 ++++ .../DependentResourceController.java | 88 ++----------------- .../dependent/DependentResourceManager.java | 6 +- ...KubernetesDependentResourceController.java | 41 ++------- .../event/source/EventSourceContextAware.java | 1 + ...formerEventSourceTestCustomReconciler.java | 10 ++- .../sample/MySQLSchemaReconciler.java | 11 +-- .../sample/SchemaDependentResource.java | 42 +++++---- .../sample/DeploymentDependentResource.java | 27 ++++-- .../sample/ServiceDependentResource.java | 17 ++-- .../sample/TomcatDependentResource.java | 13 ++- 14 files changed, 222 insertions(+), 205 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ObservedResource.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java new file mode 100644 index 0000000000..9e7b7064e8 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -0,0 +1,33 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.Context; + +public abstract class AbstractDependentResource + implements DependentResource { + + @Override + public void reconcile(P primary, Context context) { + var actual = getResource(primary); + var desired = desired(primary, context); + if (actual.isEmpty()) { + create(desired, context); + } else { + if (!match(actual.get(), desired, context)) { + update(actual.get(), desired, context); + } + } + } + + protected abstract R desired(P primary, Context context); + + protected boolean match(R actual, R target, Context context) { + return actual.equals(target); + } + + protected abstract R create(R target, Context context); + + // the actual needed to copy/preserve new labels or annotations + protected abstract R update(R actual, R target, Context context); + +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java index df144ade1f..7be1bf0bb7 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java @@ -9,54 +9,18 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; public interface DependentResource { - default EventSource initEventSource(EventSourceContext

context) { - throw new IllegalStateException("Must be implemented if not automatically provided by the SDK"); - } + + Optional initEventSource(EventSourceContext

context); @SuppressWarnings("unchecked") default Class resourceType() { return (Class) Utils.getFirstTypeArgumentFromInterface(getClass()); } - default void delete(R fetched, P primary, Context context) {} - - /** - * Computes the desired state of the dependent based on the state provided by the specified - * primary resource. - * - * The default implementation returns {@code empty} which corresponds to the case where the - * associated dependent should never be created by the associated reconciler or that the global - * state of the cluster doesn't allow for the resource to be created at this point. - * - * @param primary the primary resource associated with the reconciliation process - * @param context the {@link Context} associated with the reconciliation process - * @return an instance of the dependent resource matching the desired state specified by the - * primary resource or {@code empty} if the dependent shouldn't be created at this point - * (or ever) - */ - default Optional desired(P primary, Context context) { - return Optional.empty(); - } + void reconcile(P primary, Context context); + + void delete(P primary, Context context); + + Optional getResource(P primaryResource); - /** - * Checks whether the actual resource as fetched from the cluster matches the desired state - * expressed by the specified primary resource. - * - * The default implementation always return {@code true}, which corresponds to the behavior where - * the dependent never needs to be updated after it's been created. - * - * Note that failure to properly implement this method will lead to infinite loops. In particular, - * for typical Kubernetes resource implementations, simply calling - * {@code desired(primary, context).equals(actual)} is not enough because metadata will usually be - * different. - * - * @param actual the current state of the resource as fetched from the cluster - * @param primary the primary resource associated with the reconciliation request - * @param context the {@link Context} associated with the reconciliation request - * @return {@code true} if the actual state of the resource matches the desired state expressed by - * the specified primary resource, {@code false} otherwise - */ - default boolean match(R actual, P primary, Context context) { - return true; - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java new file mode 100644 index 0000000000..27b1f41645 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -0,0 +1,69 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +import java.util.Optional; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; + +public abstract class KubernetesDependentResource + extends AbstractDependentResource { + + private KubernetesClient client; + private boolean manageDelete; + private InformerEventSource informerEventSource; + + public KubernetesDependentResource() { + this(null, false); + } + + public KubernetesDependentResource(KubernetesClient client) { + this(client, false); + } + + public KubernetesDependentResource(KubernetesClient client, boolean manageDelete) { + this.client = client; + this.manageDelete = manageDelete; + } + + @Override + protected R create(R target, Context context) { + return client.resource(target).createOrReplace(); + } + + @Override + protected R update(R actual, R target, Context context) { + // todo map annotation and labels ? + return client.resource(target).createOrReplace(); + } + + @Override + public Optional initEventSource(EventSourceContext

context) { + InformerConfiguration config = InformerConfiguration.from(context, resourceType()).build(); + informerEventSource = new InformerEventSource(config, context); + return Optional.of(informerEventSource); + } + + @Override + public void delete(P primary, Context context) { + if (manageDelete) { + var resource = getResource(primary); + resource.ifPresent(r -> client.resource(r).delete()); + } + } + + @Override + public Optional getResource(P primaryResource) { + return informerEventSource.getAssociated(primaryResource); + } + + + public KubernetesDependentResource setClient(KubernetesClient client) { + this.client = client; + return this; + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ObservedResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ObservedResource.java new file mode 100644 index 0000000000..99478dd43b --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ObservedResource.java @@ -0,0 +1,19 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +import java.util.Optional; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; + +// todo resource: resource which we don't manage just aware of, and needs it for input +// +public interface ObservedResource { + + default Optional initEventSource(EventSourceContext

context) { + return Optional.empty(); + } + + Optional getResource(); + +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java index d0004111af..b4ed16e73f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java @@ -8,28 +8,22 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.Ignore; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import io.javaoperatorsdk.operator.api.reconciler.dependent.Persister; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @Ignore public class DependentResourceController> - implements DependentResource, Persister, Reconciler

{ + implements DependentResource { private static final Logger log = LoggerFactory.getLogger(DependentResourceController.class); - private final Persister persister; private final DependentResource delegate; private final C configuration; public DependentResourceController(DependentResource delegate, C configuration) { this.delegate = delegate; - persister = initPersister(delegate); this.configuration = configuration; } @@ -39,96 +33,30 @@ public Class resourceType() { } @Override - public boolean match(R actual, P primary, Context context) { - return delegate.match(actual, primary, context); + public void delete(P primary, Context context) { + delegate.delete(primary, context); } @Override - public Optional desired(P primary, Context context) { - return delegate.desired(primary, context); + public Optional getResource(P primaryResource) { + return delegate.getResource(primaryResource); } - @Override - public void delete(R fetched, P primary, Context context) { - delegate.delete(fetched, primary, context); - } - - @SuppressWarnings("unchecked") - protected Persister initPersister(DependentResource delegate) { - if (delegate instanceof Persister) { - return (Persister) delegate; - } else { - throw new IllegalArgumentException( - "DependentResource '" + delegate.getClass().getName() + "' must implement Persister"); - } - } - - public String descriptionFor(R resource) { - return resource.toString(); - } - - public Class getResourceType() { - return delegate.resourceType(); - } @Override - public EventSource initEventSource(EventSourceContext

context) { + public Optional initEventSource(EventSourceContext

context) { return delegate.initEventSource(context); } - @Override - public void createOrReplace(R dependentResource, Context context) { - persister.createOrReplace(dependentResource, context); - } - - @Override - public R getFor(P primary, Context context) { - return persister.getFor(primary, context); - } public C getConfiguration() { return configuration; } @Override - public UpdateControl

reconcile(P resource, Context context) { - var actual = getFor(resource, context); - if (actual == null || !match(actual, resource, context)) { - final var desired = desired(resource, context); - desired.ifPresent(d -> createOrReplaceDependent(resource, d, context)); - } - return UpdateControl.noUpdate(); - } - - @Override - public DeleteControl cleanup(P primary, Context context) { - var dependent = getFor(primary, context); - if (dependent != null) { - delete(dependent, primary, context); - logOperationInfo(primary, dependent, "Deleting"); - } else { - log.info("Ignoring already deleted {} for '{}' {}", - getResourceType().getName(), - primary.getMetadata().getName(), - primary.getKind()); - } - return Reconciler.super.cleanup(primary, context); + public void reconcile(P resource, Context context) { + delegate.reconcile(resource, context); } - protected void createOrReplaceDependent(P primary, R dependent, Context context) { - logOperationInfo(primary, dependent, "Reconciling"); - // commit the changes - // todo: add metrics timing for dependent resource - createOrReplace(dependent, context); - } - - private void logOperationInfo(P resource, R dependentResource, String operationDescription) { - if (log.isInfoEnabled()) { - log.info("{} {} for '{}' {}", operationDescription, - descriptionFor(dependentResource), - resource.getMetadata().getName(), - resource.getKind()); - } - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java index 8ab04d7d09..213b4fbeae 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java @@ -44,7 +44,9 @@ public List prepareEventSources(EventSourceContext

context) { configured.forEach(dependent -> { final var dependentResourceController = from(dependent); dependents.add(dependentResourceController); - sources.add(dependentResourceController.initEventSource(context)); + dependentResourceController.initEventSource(context) + .ifPresent(es -> sources.add((EventSource) es)); + }); return sources; @@ -68,7 +70,7 @@ public UpdateControl

reconcile(P resource, Context context) { @Override public DeleteControl cleanup(P resource, Context context) { initContextIfNeeded(resource, context); - dependents.forEach(dependent -> dependent.cleanup(resource, context)); + dependents.forEach(dependent -> dependent.delete(resource, context)); return Reconciler.super.cleanup(resource, context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java index 63d533193b..e81bcfe53d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java @@ -1,14 +1,14 @@ package io.javaoperatorsdk.operator.processing.dependent; +import java.util.Optional; + import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.Ignore; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import io.javaoperatorsdk.operator.api.reconciler.dependent.Persister; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; @@ -46,45 +46,16 @@ public KubernetesDependentResourceController(DependentResource delegate, configuration.getDependentResourceClass()); } - @SuppressWarnings("unchecked") - @Override - protected Persister initPersister(DependentResource delegate) { - return (delegate instanceof Persister) ? (Persister) delegate : this; - } - - @Override - public String descriptionFor(R resource) { - return String.format("'%s' %s dependent in namespace %s", resource.getMetadata().getName(), - resource.getFullResourceName(), - resource.getMetadata().getNamespace()); - } - @Override - public EventSource initEventSource(EventSourceContext

context) { + public Optional initEventSource(EventSourceContext

context) { this.client = context.getClient(); informer = new InformerEventSource<>(configuration, context); - return informer; + return Optional.of(informer); } @Override - public void createOrReplace(R dependentResource, Context context) { - client.resource(dependentResource).createOrReplace(); + public Optional getResource(P primaryResource) { + return Optional.ofNullable(informer.getAssociated(primaryResource).orElse(null)); } - @Override - public R getFor(P primary, Context context) { - return informer.getAssociated(primary).orElse(null); - } - - public boolean owned() { - return getConfiguration().isOwned(); - } - - @Override - protected void createOrReplaceDependent(P primary, R dependent, Context context) { - if (owned()) { - dependent.addOwnerReference(primary); - } - super.createOrReplaceDependent(primary, dependent, context); - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java index 95042d0c41..39847f0f87 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java @@ -3,6 +3,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +// todo do we really need this public interface EventSourceContextAware

{ void initWith(EventSourceContext

context); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java index 33128a6b8c..b244a6293c 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java @@ -13,7 +13,7 @@ import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; @@ -40,7 +40,8 @@ public class InformerEventSourceTestCustomReconciler private final AtomicInteger numberOfExecutions = new AtomicInteger(0); public static class ConfigMapDR - implements DependentResource, + extends KubernetesDependentResource + implements PrimaryResourcesRetriever { private final PrimaryResourcesRetriever retriever = Mappers.fromAnnotation( RELATED_RESOURCE_NAME); @@ -49,6 +50,11 @@ public static class ConfigMapDR public Set associatedPrimaryResources(ConfigMap dependentResource) { return retriever.associatedPrimaryResources(dependentResource); } + + @Override + protected ConfigMap desired(InformerEventSourceTestCustomResource primary, Context context) { + return null; + } } @Override diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java index ff4fcad131..6242fae2e5 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java @@ -19,7 +19,7 @@ import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.RetryInfo; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.sample.MySQLSchemaReconciler.SecretDependentResource; import io.javaoperatorsdk.operator.sample.schema.Schema; @@ -50,15 +50,16 @@ public MySQLSchemaReconciler(MySQLDbConfig mysqlDbConfig) { this.mysqlDbConfig = mysqlDbConfig; } - public static class SecretDependentResource implements DependentResource { + public static class SecretDependentResource + extends KubernetesDependentResource { private static String encode(String value) { return Base64.getEncoder().encodeToString(value.getBytes()); } @Override - public Optional desired(MySQLSchema schema, Context context) { - return Optional.of(new SecretBuilder() + public Secret desired(MySQLSchema schema, Context context) { + return new SecretBuilder() .withNewMetadata() .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) .withNamespace(schema.getMetadata().getNamespace()) @@ -67,7 +68,7 @@ public Optional desired(MySQLSchema schema, Context context) { context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) .addToData("MYSQL_PASSWORD", encode( context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) - .build()); + .build(); } } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java index 8ba9612029..051cfb5564 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java @@ -7,8 +7,7 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import io.javaoperatorsdk.operator.api.reconciler.dependent.Persister; +import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; import io.javaoperatorsdk.operator.sample.schema.Schema; @@ -16,22 +15,21 @@ import static java.lang.String.format; -public class SchemaDependentResource - implements DependentResource, Persister { +public class SchemaDependentResource extends AbstractDependentResource { private static final int POLL_PERIOD = 500; private MySQLDbConfig dbConfig; @Override - public EventSource initEventSource(EventSourceContext context) { + public Optional initEventSource(EventSourceContext context) { dbConfig = context.getMandatory(MySQLSchemaReconciler.MYSQL_DB_CONFIG, MySQLDbConfig.class); - return new PerResourcePollingEventSource<>( + return Optional.of(new PerResourcePollingEventSource<>( new SchemaPollingResourceSupplier(dbConfig), context.getPrimaryCache(), POLL_PERIOD, - Schema.class); + Schema.class)); } @Override - public Optional desired(MySQLSchema primary, Context context) { + public Schema desired(MySQLSchema primary, Context context) { try (Connection connection = getConnection()) { final var schema = SchemaService.createSchemaAndRelatedUser( connection, @@ -42,13 +40,23 @@ public Optional desired(MySQLSchema primary, Context context) { // put the newly built schema in the context to let the reconciler know we just built it context.put(MySQLSchemaReconciler.BUILT_SCHEMA, schema); - return Optional.of(schema); + return schema; } catch (SQLException e) { MySQLSchemaReconciler.log.error("Error while creating Schema", e); throw new IllegalStateException(e); } } + @Override + protected Schema create(Schema target, Context context) { + return null; + } + + @Override + protected Schema update(Schema actual, Schema target, Context context) { + return null; + } + private Connection getConnection() throws SQLException { String connectURL = format("jdbc:mysql://%1$s:%2$s", dbConfig.getHost(), dbConfig.getPort()); @@ -58,7 +66,7 @@ private Connection getConnection() throws SQLException { } @Override - public void delete(Schema fetched, MySQLSchema primary, Context context) { + public void delete(MySQLSchema primary, Context context) { try (Connection connection = getConnection()) { var userName = primary.getStatus() != null ? primary.getStatus().getUserName() : null; SchemaService.deleteSchemaAndRelatedUser(connection, primary.getMetadata().getName(), @@ -69,18 +77,14 @@ public void delete(Schema fetched, MySQLSchema primary, Context context) { } @Override - public void createOrReplace(Schema dependentResource, Context context) { - // this is actually implemented in buildFor, the cleaner way to do this would be to have all - // the needed information in Schema instead of creating both the schema and user from - // heterogeneous information - } - - @Override - public Schema getFor(MySQLSchema primary, Context context) { + public Optional getResource(MySQLSchema primaryResource) { try (Connection connection = getConnection()) { - return SchemaService.getSchema(connection, primary.getMetadata().getName()).orElse(null); + var schema = + SchemaService.getSchema(connection, primaryResource.getMetadata().getName()).orElse(null); + return Optional.ofNullable(schema); } catch (SQLException e) { throw new RuntimeException("Error while trying to delete Schema", e); } } + } diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index 58200df988..52fa1ad689 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -1,20 +1,27 @@ package io.javaoperatorsdk.operator.sample; -import java.util.Optional; - import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependent; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; @KubernetesDependent(labelSelector = "app.kubernetes.io/managed-by=tomcat-operator") public class DeploymentDependentResource - implements DependentResource { + extends KubernetesDependentResource { + + public DeploymentDependentResource(KubernetesClient client) { + super(client); + } + + public DeploymentDependentResource(KubernetesClient client, boolean manageDelete) { + super(client, manageDelete); + } @Override - public Optional desired(Tomcat tomcat, Context context) { + public Deployment desired(Tomcat tomcat, Context context) { Deployment deployment = TomcatReconciler.loadYaml(Deployment.class, "deployment.yaml"); final ObjectMeta tomcatMetadata = tomcat.getMetadata(); final String tomcatName = tomcatMetadata.getName(); @@ -39,7 +46,7 @@ public Optional desired(Tomcat tomcat, Context context) { .endTemplate() .endSpec() .build(); - return Optional.of(deployment); + return deployment; } private String tomcatImage(Tomcat tomcat) { @@ -47,8 +54,10 @@ private String tomcatImage(Tomcat tomcat) { } @Override - public boolean match(Deployment fetched, Tomcat tomcat, Context context) { - return fetched.getSpec().getTemplate().getSpec().getContainers().stream() - .findFirst().map(c -> tomcatImage(tomcat).equals(c.getImage())).orElse(false); + public boolean match(Deployment fetched, Deployment target, Context context) { + // todo compare spec + return true; + // return fetched.getSpec().getTemplate().getSpec().getContainers().stream() + // .findFirst().map(c -> tomcatImage(tomcat).equals(c.getImage())).orElse(false); } } diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java index 52d043203b..f84825bcca 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java @@ -1,19 +1,22 @@ package io.javaoperatorsdk.operator.sample; -import java.util.Optional; - import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; + +public class ServiceDependentResource extends KubernetesDependentResource { -public class ServiceDependentResource implements DependentResource { + public ServiceDependentResource(KubernetesClient client, boolean manageDelete) { + super(client, manageDelete); + } @Override - public Optional desired(Tomcat tomcat, Context context) { + public Service desired(Tomcat tomcat, Context context) { final ObjectMeta tomcatMetadata = tomcat.getMetadata(); - return Optional.of(new ServiceBuilder(TomcatReconciler.loadYaml(Service.class, "service.yaml")) + return new ServiceBuilder(TomcatReconciler.loadYaml(Service.class, "service.yaml")) .editMetadata() .withName(tomcatMetadata.getName()) .withNamespace(tomcatMetadata.getNamespace()) @@ -21,6 +24,6 @@ public Optional desired(Tomcat tomcat, Context context) { .editSpec() .addToSelector("app", tomcatMetadata.getName()) .endSpec() - .build()); + .build(); } } diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java index abb4e62358..6a9848692c 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java @@ -3,16 +3,18 @@ import java.util.Set; import java.util.stream.Collectors; +import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.EventSourceContextAware; import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; import io.javaoperatorsdk.operator.processing.event.source.ResourceCache; -public class TomcatDependentResource - implements DependentResource, PrimaryResourcesRetriever, +public class TomcatDependentResource extends KubernetesDependentResource + implements PrimaryResourcesRetriever, + // todo discuss these kind of implementations, since cannot be used in standalone mode AssociatedSecondaryResourceIdentifier, EventSourceContextAware { private ResourceCache primaryCache; @@ -38,4 +40,9 @@ public Set associatedPrimaryResources(Tomcat t) { public ResourceID associatedSecondaryID(Webapp primary) { return new ResourceID(primary.getSpec().getTomcat(), primary.getMetadata().getNamespace()); } + + @Override + protected Tomcat desired(Webapp primary, Context context) { + return null; + } } From 0d2363c14584d4d0e2af573d9dd1735f4b99d7dc Mon Sep 17 00:00:00 2001 From: csviri Date: Tue, 8 Feb 2022 10:06:50 +0100 Subject: [PATCH 02/25] fix: wip --- .../reconciler/dependent/DependentResource.java | 2 +- .../dependent/KubernetesDependentResource.java | 10 +++++++++- .../api/reconciler/dependent/Persister.java | 11 ----------- .../dependent/DependentResourceController.java | 6 +++--- .../dependent/DependentResourceManager.java | 11 ++++++++--- .../KubernetesDependentResourceController.java | 16 +++++++--------- .../operator/sample/SchemaDependentResource.java | 2 +- 7 files changed, 29 insertions(+), 29 deletions(-) delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Persister.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java index 7be1bf0bb7..b097554107 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java @@ -10,7 +10,7 @@ public interface DependentResource { - Optional initEventSource(EventSourceContext

context); + Optional eventSource(EventSourceContext

context); @SuppressWarnings("unchecked") default Class resourceType() { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index 27b1f41645..e30c5d0521 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -42,12 +42,20 @@ protected R update(R actual, R target, Context context) { } @Override - public Optional initEventSource(EventSourceContext

context) { + public Optional eventSource(EventSourceContext

context) { + if (informerEventSource != null) { + return Optional.of(informerEventSource); + } InformerConfiguration config = InformerConfiguration.from(context, resourceType()).build(); informerEventSource = new InformerEventSource(config, context); return Optional.of(informerEventSource); } + public KubernetesDependentResource setInformerEventSource(InformerEventSource informerEventSource) { + this.informerEventSource = informerEventSource; + return this; + } + @Override public void delete(P primary, Context context) { if (manageDelete) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Persister.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Persister.java deleted file mode 100644 index ab34372917..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Persister.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.javaoperatorsdk.operator.api.reconciler.dependent; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public interface Persister { - - void createOrReplace(R dependentResource, Context context); - - R getFor(P primary, Context context); -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java index b4ed16e73f..b694b2296c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java @@ -19,7 +19,7 @@ public class DependentResourceController delegate; + protected final DependentResource delegate; private final C configuration; public DependentResourceController(DependentResource delegate, C configuration) { @@ -44,8 +44,8 @@ public Optional getResource(P primaryResource) { @Override - public Optional initEventSource(EventSourceContext

context) { - return delegate.initEventSource(context); + public Optional eventSource(EventSourceContext

context) { + return delegate.eventSource(context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java index 213b4fbeae..3d4c3ddae4 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java @@ -5,6 +5,7 @@ import java.util.List; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; @@ -18,6 +19,7 @@ import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.Controller; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -42,9 +44,9 @@ public List prepareEventSources(EventSourceContext

context) { List sources = new ArrayList<>(configured.size() + 5); configured.forEach(dependent -> { - final var dependentResourceController = from(dependent); + final var dependentResourceController = from(dependent,context.getClient()); dependents.add(dependentResourceController); - dependentResourceController.initEventSource(context) + dependentResourceController.eventSource(context) .ifPresent(es -> sources.add((EventSource) es)); }); @@ -82,12 +84,15 @@ private void initContextIfNeeded(P resource, Context context) { } } - private DependentResourceController from(DependentResourceConfiguration config) { + private DependentResourceController from(DependentResourceConfiguration config, KubernetesClient client) { try { final var dependentResource = (DependentResource) config.getDependentResourceClass().getConstructor() .newInstance(); if (config instanceof KubernetesDependentResourceConfiguration) { + if (dependentResource instanceof KubernetesDependentResource) { + ((KubernetesDependentResource)dependentResource).setClient(client); + } return new KubernetesDependentResourceController(dependentResource, (KubernetesDependentResourceConfiguration) config); } else { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java index e81bcfe53d..abbba556fb 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java @@ -3,12 +3,12 @@ import java.util.Optional; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.Ignore; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; @@ -19,9 +19,6 @@ public class KubernetesDependentResourceController> { private final KubernetesDependentResourceConfiguration configuration; - private KubernetesClient client; - private InformerEventSource informer; - @SuppressWarnings("unchecked") public KubernetesDependentResourceController(DependentResource delegate, @@ -47,15 +44,16 @@ public KubernetesDependentResourceController(DependentResource delegate, } @Override - public Optional initEventSource(EventSourceContext

context) { - this.client = context.getClient(); - informer = new InformerEventSource<>(configuration, context); - return Optional.of(informer); + public Optional eventSource(EventSourceContext

context) { + var client = context.getClient(); + var informer = new InformerEventSource<>(configuration, context); + ((KubernetesDependentResource)delegate).setInformerEventSource(informer); + return this.eventSource(context); } @Override public Optional getResource(P primaryResource) { - return Optional.ofNullable(informer.getAssociated(primaryResource).orElse(null)); + return delegate.getResource(primaryResource); } } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java index 051cfb5564..9082fa9248 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java @@ -21,7 +21,7 @@ public class SchemaDependentResource extends AbstractDependentResource initEventSource(EventSourceContext context) { + public Optional eventSource(EventSourceContext context) { dbConfig = context.getMandatory(MySQLSchemaReconciler.MYSQL_DB_CONFIG, MySQLDbConfig.class); return Optional.of(new PerResourcePollingEventSource<>( new SchemaPollingResourceSupplier(dbConfig), context.getPrimaryCache(), POLL_PERIOD, From 6dff17b4571ceb96e76381531561be85ef4c3528 Mon Sep 17 00:00:00 2001 From: csviri Date: Tue, 8 Feb 2022 13:06:08 +0100 Subject: [PATCH 03/25] fix: wip --- .../KubernetesDependentResource.java | 29 ++++++++++++++++--- .../dependent/DependentResourceManager.java | 7 +++-- ...KubernetesDependentResourceController.java | 3 +- .../sample/TomcatDependentResource.java | 1 - 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index e30c5d0521..1871276cd5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -7,8 +7,12 @@ import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; +import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; public abstract class KubernetesDependentResource extends AbstractDependentResource { @@ -46,12 +50,30 @@ public Optional eventSource(EventSourceContext

context) { if (informerEventSource != null) { return Optional.of(informerEventSource); } - InformerConfiguration config = InformerConfiguration.from(context, resourceType()).build(); - informerEventSource = new InformerEventSource(config, context); + var informerConfig = initInformerConfiguration(context); + informerEventSource = new InformerEventSource(informerConfig, context); return Optional.of(informerEventSource); } - public KubernetesDependentResource setInformerEventSource(InformerEventSource informerEventSource) { + private InformerConfiguration initInformerConfiguration(EventSourceContext

context) { + PrimaryResourcesRetriever associatedPrimaries = + (this instanceof PrimaryResourcesRetriever) ? (PrimaryResourcesRetriever) this + : Mappers.fromOwnerReference(); + + AssociatedSecondaryResourceIdentifier associatedSecondary = + (this instanceof AssociatedSecondaryResourceIdentifier) + ? (AssociatedSecondaryResourceIdentifier) this + : (r) -> ResourceID.fromResource(r); + + return InformerConfiguration.from(context, resourceType()) + .withPrimaryResourcesRetriever(associatedPrimaries) + .withAssociatedSecondaryResourceIdentifier( + (AssociatedSecondaryResourceIdentifier

) associatedSecondary) + .build(); + } + + public KubernetesDependentResource withInformerEventSource( + InformerEventSource informerEventSource) { this.informerEventSource = informerEventSource; return this; } @@ -69,7 +91,6 @@ public Optional getResource(P primaryResource) { return informerEventSource.getAssociated(primaryResource); } - public KubernetesDependentResource setClient(KubernetesClient client) { this.client = client; return this; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java index 3d4c3ddae4..9a94fed2f2 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java @@ -44,7 +44,7 @@ public List prepareEventSources(EventSourceContext

context) { List sources = new ArrayList<>(configured.size() + 5); configured.forEach(dependent -> { - final var dependentResourceController = from(dependent,context.getClient()); + final var dependentResourceController = from(dependent, context.getClient()); dependents.add(dependentResourceController); dependentResourceController.eventSource(context) .ifPresent(es -> sources.add((EventSource) es)); @@ -84,14 +84,15 @@ private void initContextIfNeeded(P resource, Context context) { } } - private DependentResourceController from(DependentResourceConfiguration config, KubernetesClient client) { + private DependentResourceController from(DependentResourceConfiguration config, + KubernetesClient client) { try { final var dependentResource = (DependentResource) config.getDependentResourceClass().getConstructor() .newInstance(); if (config instanceof KubernetesDependentResourceConfiguration) { if (dependentResource instanceof KubernetesDependentResource) { - ((KubernetesDependentResource)dependentResource).setClient(client); + ((KubernetesDependentResource) dependentResource).setClient(client); } return new KubernetesDependentResourceController(dependentResource, (KubernetesDependentResourceConfiguration) config); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java index abbba556fb..8f1cb6a165 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java @@ -45,9 +45,8 @@ public KubernetesDependentResourceController(DependentResource delegate, @Override public Optional eventSource(EventSourceContext

context) { - var client = context.getClient(); var informer = new InformerEventSource<>(configuration, context); - ((KubernetesDependentResource)delegate).setInformerEventSource(informer); + ((KubernetesDependentResource) delegate).withInformerEventSource(informer); return this.eventSource(context); } diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java index 6a9848692c..b21acd4cc4 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java @@ -14,7 +14,6 @@ public class TomcatDependentResource extends KubernetesDependentResource implements PrimaryResourcesRetriever, - // todo discuss these kind of implementations, since cannot be used in standalone mode AssociatedSecondaryResourceIdentifier, EventSourceContextAware { private ResourceCache primaryCache; From ba619e5d463f450bcd327a7312de6dcc05a081d3 Mon Sep 17 00:00:00 2001 From: csviri Date: Tue, 8 Feb 2022 13:48:41 +0100 Subject: [PATCH 04/25] fix: 1 IT --- ...KubernetesDependentResourceController.java | 2 +- ...formerEventSourceTestCustomReconciler.java | 72 ++++++++++--------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java index 8f1cb6a165..3b7ce19c5b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java @@ -47,7 +47,7 @@ public KubernetesDependentResourceController(DependentResource delegate, public Optional eventSource(EventSourceContext

context) { var informer = new InformerEventSource<>(configuration, context); ((KubernetesDependentResource) delegate).withInformerEventSource(informer); - return this.eventSource(context); + return super.eventSource(context); } @Override diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java index b244a6293c..ab1f0f7f24 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java @@ -1,23 +1,19 @@ package io.javaoperatorsdk.operator.sample.informereventsource; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; +import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.javaoperatorsdk.operator.api.config.dependent.Dependent; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; -import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; -import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; -import io.javaoperatorsdk.operator.sample.informereventsource.InformerEventSourceTestCustomReconciler.ConfigMapDR; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; @@ -25,10 +21,11 @@ * Copies the config map value from spec into status. The main purpose is to test and demonstrate * sample usage of InformerEventSource */ -@ControllerConfiguration(finalizerName = NO_FINALIZER, - dependents = @Dependent(resourceType = ConfigMap.class, type = ConfigMapDR.class)) +@ControllerConfiguration(finalizerName = NO_FINALIZER) public class InformerEventSourceTestCustomReconciler - implements Reconciler { + implements Reconciler, + KubernetesClientAware, + EventSourceInitializer { private static final Logger LOGGER = LoggerFactory.getLogger(InformerEventSourceTestCustomReconciler.class); @@ -37,30 +34,27 @@ public class InformerEventSourceTestCustomReconciler public static final String TARGET_CONFIG_MAP_KEY = "targetStatus"; public static final String MISSING_CONFIG_MAP = "Missing Config Map"; + private KubernetesClient kubernetesClient; private final AtomicInteger numberOfExecutions = new AtomicInteger(0); - public static class ConfigMapDR - extends KubernetesDependentResource - implements - PrimaryResourcesRetriever { - private final PrimaryResourcesRetriever retriever = Mappers.fromAnnotation( - RELATED_RESOURCE_NAME); + @Override + public List prepareEventSources( + EventSourceContext context) { - @Override - public Set associatedPrimaryResources(ConfigMap dependentResource) { - return retriever.associatedPrimaryResources(dependentResource); - } + InformerConfiguration config = + InformerConfiguration.from(context, ConfigMap.class) + .withPrimaryResourcesRetriever(Mappers.fromAnnotation(RELATED_RESOURCE_NAME)) + .build(); - @Override - protected ConfigMap desired(InformerEventSourceTestCustomResource primary, Context context) { - return null; - } + return List.of(new InformerEventSource<>(config, context)); + // + // return List.of(new InformerEventSource<>(kubernetesClient, ConfigMap.class, + // Mappers.fromAnnotation(RELATED_RESOURCE_NAME))); } @Override public UpdateControl reconcile( - InformerEventSourceTestCustomResource resource, - Context context) { + InformerEventSourceTestCustomResource resource, Context context) { numberOfExecutions.incrementAndGet(); resource.setStatus(new InformerEventSourceTestCustomResourceStatus()); @@ -81,4 +75,14 @@ public UpdateControl reconcile( public int getNumberOfExecutions() { return numberOfExecutions.get(); } + + @Override + public KubernetesClient getKubernetesClient() { + return null; + } + + @Override + public void setKubernetesClient(KubernetesClient kubernetesClient) { + this.kubernetesClient = kubernetesClient; + } } From dfa2388cfb9f4813098e05dc5f04c58d8d934cb1 Mon Sep 17 00:00:00 2001 From: csviri Date: Tue, 8 Feb 2022 14:24:31 +0100 Subject: [PATCH 05/25] fix: format --- ...formerEventSourceTestCustomReconciler.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java index ab1f0f7f24..30a5979514 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java @@ -1,5 +1,12 @@ package io.javaoperatorsdk.operator.sample.informereventsource; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; @@ -8,12 +15,6 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; @@ -24,8 +25,8 @@ @ControllerConfiguration(finalizerName = NO_FINALIZER) public class InformerEventSourceTestCustomReconciler implements Reconciler, - KubernetesClientAware, - EventSourceInitializer { + KubernetesClientAware, + EventSourceInitializer { private static final Logger LOGGER = LoggerFactory.getLogger(InformerEventSourceTestCustomReconciler.class); @@ -48,8 +49,8 @@ public List prepareEventSources( return List.of(new InformerEventSource<>(config, context)); // - // return List.of(new InformerEventSource<>(kubernetesClient, ConfigMap.class, - // Mappers.fromAnnotation(RELATED_RESOURCE_NAME))); + // return List.of(new InformerEventSource<>(kubernetesClient, ConfigMap.class, + // Mappers.fromAnnotation(RELATED_RESOURCE_NAME))); } @Override From 1ad4a1247579a629bdf77683b6878e68df3938e4 Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 9 Feb 2022 08:59:24 +0100 Subject: [PATCH 06/25] fix: IT wip --- .../operator/ReconcilerUtils.java | 27 +++++++ .../api/config/ConfigurationService.java | 4 +- .../operator/api/reconciler/Constants.java | 5 ++ .../dependent/AbstractDependentResource.java | 4 +- .../reconciler/dependent/DesiredSupplier.java | 10 +++ .../KubernetesDependentResource.java | 44 +++++++++++- ...KubernetesDependentResourceController.java | 2 +- .../operator/ReconcilerUtilsTest.java | 44 ++++++++++++ .../StandaloneDependentResourceIT.java | 4 ++ ...formerEventSourceTestCustomReconciler.java | 3 - ...StandaloneDependentTestCustomResource.java | 16 +++++ ...loneDependentTestCustomResourceStatus.java | 5 ++ .../StandaloneDependentTestReconciler.java | 72 +++++++++++++++++++ .../TestCustomResourceSpec.java | 37 ++++++++++ .../sample/SchemaDependentResource.java | 5 ++ 15 files changed, 272 insertions(+), 10 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredSupplier.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResourceStatus.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/TestCustomResourceSpec.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java index e3a6da1e5a..63de88d1fb 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java @@ -1,5 +1,7 @@ package io.javaoperatorsdk.operator; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Locale; import io.fabric8.kubernetes.api.model.HasMetadata; @@ -8,6 +10,10 @@ import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import com.fasterxml.jackson.core.JsonProcessingException; + +import static io.javaoperatorsdk.operator.api.reconciler.Constants.OBJECT_MAPPER; + @SuppressWarnings("rawtypes") public class ReconcilerUtils { @@ -98,4 +104,25 @@ public static String getDefaultReconcilerName(String reconcilerClassName) { } return reconcilerClassName.toLowerCase(Locale.ROOT); } + + public static boolean specsEqual(HasMetadata r1, HasMetadata r2) { + try { + var c1json = OBJECT_MAPPER.writeValueAsString(getSpec(r1)); + var c2json = OBJECT_MAPPER.writeValueAsString(getSpec(r2)); + return OBJECT_MAPPER.readTree(c1json).equals(OBJECT_MAPPER.readTree(c2json)); + } catch (JsonProcessingException e) { + throw new IllegalStateException(e); + } + } + + // will be replaced with: https://github.com/fabric8io/kubernetes-client/issues/3816 + public static Object getSpec(HasMetadata resource) { + try { + Method getSpecMethod = resource.getClass().getMethod("getSpec"); + return getSpecMethod.invoke(resource); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java index 2e4679efd3..ba4ea1cde1 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java @@ -13,11 +13,13 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import static io.javaoperatorsdk.operator.api.reconciler.Constants.OBJECT_MAPPER; + /** An interface from which to retrieve configuration information. */ public interface ConfigurationService { Cloner DEFAULT_CLONER = new Cloner() { - private final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + @Override public HasMetadata clone(HasMetadata object) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java index 85b3a00807..56dfdae3ea 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java @@ -1,6 +1,11 @@ package io.javaoperatorsdk.operator.api.reconciler; +import com.fasterxml.jackson.databind.ObjectMapper; + public final class Constants { + // Shared object mapper across app + public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + public static final String EMPTY_STRING = ""; public static final String WATCH_CURRENT_NAMESPACE = "JOSDK_WATCH_CURRENT"; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index 9e7b7064e8..fe5c0cd269 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -21,9 +21,7 @@ public void reconcile(P primary, Context context) { protected abstract R desired(P primary, Context context); - protected boolean match(R actual, R target, Context context) { - return actual.equals(target); - } + protected abstract boolean match(R actual, R target, Context context); protected abstract R create(R target, Context context); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredSupplier.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredSupplier.java new file mode 100644 index 0000000000..b93d75950b --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredSupplier.java @@ -0,0 +1,10 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +import io.javaoperatorsdk.operator.api.reconciler.Context; + +@FunctionalInterface +public interface DesiredSupplier { + + R getDesired(P primary, Context context); + +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index 1871276cd5..8c551b7b43 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -4,6 +4,8 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.OperatorException; +import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; @@ -14,12 +16,14 @@ import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; -public abstract class KubernetesDependentResource +// todo owned: owner reference setting +public class KubernetesDependentResource extends AbstractDependentResource { private KubernetesClient client; private boolean manageDelete; private InformerEventSource informerEventSource; + private DesiredSupplier desiredSupplier = null; public KubernetesDependentResource() { this(null, false); @@ -34,13 +38,30 @@ public KubernetesDependentResource(KubernetesClient client, boolean manageDelete this.manageDelete = manageDelete; } + @Override + protected R desired(P primary, Context context) { + if (desiredSupplier != null) { + return desiredSupplier.getDesired(primary, context); + } else { + throw new OperatorException( + "No DesiredSupplier provided. Either provide one or override this method"); + } + } + + @Override + protected boolean match(R actual, R target, Context context) { + return ReconcilerUtils.specsEqual(actual, target); + } + @Override protected R create(R target, Context context) { + // todo implement here https://github.com/java-operator-sdk/java-operator-sdk/issues/870 return client.resource(target).createOrReplace(); } @Override protected R update(R actual, R target, Context context) { + // todo implement here https://github.com/java-operator-sdk/java-operator-sdk/issues/870 // todo map annotation and labels ? return client.resource(target).createOrReplace(); } @@ -72,7 +93,7 @@ private InformerConfiguration initInformerConfiguration(EventSourceContext .build(); } - public KubernetesDependentResource withInformerEventSource( + public KubernetesDependentResource setInformerEventSource( InformerEventSource informerEventSource) { this.informerEventSource = informerEventSource; return this; @@ -95,4 +116,23 @@ public KubernetesDependentResource setClient(KubernetesClient client) { this.client = client; return this; } + + public KubernetesDependentResource setDesiredSupplier( + DesiredSupplier desiredSupplier) { + this.desiredSupplier = desiredSupplier; + return this; + } + + public KubernetesDependentResource setManageDelete(boolean manageDelete) { + this.manageDelete = manageDelete; + return this; + } + + public boolean isManageDelete() { + return manageDelete; + } + + public DesiredSupplier getDesiredSupplier() { + return desiredSupplier; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java index 3b7ce19c5b..d46301bdff 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java @@ -46,7 +46,7 @@ public KubernetesDependentResourceController(DependentResource delegate, @Override public Optional eventSource(EventSourceContext

context) { var informer = new InformerEventSource<>(configuration, context); - ((KubernetesDependentResource) delegate).withInformerEventSource(informer); + ((KubernetesDependentResource) delegate).setInformerEventSource(informer); return super.eventSource(context); } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java index d46936b3d5..7bc5185bab 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java @@ -3,6 +3,10 @@ import org.junit.jupiter.api.Test; import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DeploymentSpec; import io.javaoperatorsdk.operator.api.reconciler.Constants; import io.javaoperatorsdk.operator.sample.simple.TestCustomReconciler; import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; @@ -11,6 +15,7 @@ import static io.javaoperatorsdk.operator.ReconcilerUtils.getDefaultNameFor; import static io.javaoperatorsdk.operator.ReconcilerUtils.getDefaultReconcilerName; import static io.javaoperatorsdk.operator.ReconcilerUtils.isFinalizerValid; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -39,4 +44,43 @@ void defaultFinalizerShouldWork() { void noFinalizerMarkerShouldWork() { assertTrue(isFinalizerValid(Constants.NO_FINALIZER)); } + + + @Test + void comparesArbitrarySpecsOfObjects() { + var d1 = createTestDeployment(); + var d2 = createTestDeployment(); + + assertThat(ReconcilerUtils.specsEqual(d1, d2)).isTrue(); + } + + @Test + void comparesArbitraryDifferentSpecsOfObjects() { + var d1 = createTestDeployment(); + var d2 = createTestDeployment(); + d2.getSpec().getTemplate().getSpec().setHostname("otherhost"); + + assertThat(ReconcilerUtils.specsEqual(d1, d2)).isFalse(); + } + + @Test + void getsSpecWithReflection() { + Deployment deployment = new Deployment(); + deployment.setSpec(new DeploymentSpec()); + deployment.getSpec().setReplicas(5); + + DeploymentSpec spec = (DeploymentSpec) ReconcilerUtils.getSpec(deployment); + assertThat(spec.getReplicas()).isEqualTo(5); + } + + private Deployment createTestDeployment() { + Deployment deployment = new Deployment(); + deployment.setSpec(new DeploymentSpec()); + deployment.getSpec().setReplicas(5); + PodTemplateSpec podTemplateSpec = new PodTemplateSpec(); + deployment.getSpec().setTemplate(podTemplateSpec); + podTemplateSpec.setSpec(new PodSpec()); + podTemplateSpec.getSpec().setHostname("localhost"); + return deployment; + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java new file mode 100644 index 0000000000..16afa9b173 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java @@ -0,0 +1,4 @@ +package io.javaoperatorsdk.operator.dependent; + +public class StandaloneDependentResourceIT { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java index 30a5979514..f1142218c7 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java @@ -48,9 +48,6 @@ public List prepareEventSources( .build(); return List.of(new InformerEventSource<>(config, context)); - // - // return List.of(new InformerEventSource<>(kubernetesClient, ConfigMap.class, - // Mappers.fromAnnotation(RELATED_RESOURCE_NAME))); } @Override diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResource.java new file mode 100644 index 0000000000..c03e22d655 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResource.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.operator.sample.standalonedependent; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Kind; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("sdt") +public class StandaloneDependentTestCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResourceStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResourceStatus.java new file mode 100644 index 0000000000..5f12f1ef72 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResourceStatus.java @@ -0,0 +1,5 @@ +package io.javaoperatorsdk.operator.sample.standalonedependent; + +public class StandaloneDependentTestCustomResourceStatus { + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java new file mode 100644 index 0000000000..78f9310588 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java @@ -0,0 +1,72 @@ +package io.javaoperatorsdk.operator.sample.standalonedependent; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DesiredSupplier; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; +import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; + +@ControllerConfiguration(finalizerName = NO_FINALIZER) +public class StandaloneDependentTestReconciler + implements Reconciler, + EventSourceInitializer, + TestExecutionInfoProvider, + KubernetesClientAware { + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + private KubernetesClient kubernetesClient; + + KubernetesDependentResource configMapDependent; + + + public StandaloneDependentTestReconciler() { + configMapDependent = new KubernetesDependentResource(); + configMapDependent.setDesiredSupplier(new DesiredSupplier() { + @Override + public ConfigMap getDesired(StandaloneDependentTestCustomResource primary, Context context) { + return null; + } + }); + } + + @Override + public List prepareEventSources( + EventSourceContext context) { + return List.of(configMapDependent.eventSource(context).get()); + } + + @Override + public UpdateControl reconcile( + StandaloneDependentTestCustomResource resource, Context context) { + numberOfExecutions.addAndGet(1); + + configMapDependent.reconcile(resource,context); + return UpdateControl.noUpdate(); + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + + @Override + public void setKubernetesClient(KubernetesClient kubernetesClient) { + this.kubernetesClient = kubernetesClient; + configMapDependent.setClient(kubernetesClient); + } + + @Override + public KubernetesClient getKubernetesClient() { + return this.kubernetesClient; + } + + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/TestCustomResourceSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/TestCustomResourceSpec.java new file mode 100644 index 0000000000..2ad2f02d40 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/TestCustomResourceSpec.java @@ -0,0 +1,37 @@ +package io.javaoperatorsdk.operator.sample.standalonedependent; + +import java.util.Objects; + +public class TestCustomResourceSpec { + + private String value; + + public String getValue() { + return value; + } + + public TestCustomResourceSpec setValue(String value) { + this.value = value; + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TestCustomResourceSpec that = (TestCustomResourceSpec) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return "TestCustomResourceSpec{" + + "value='" + value + '\'' + + '}'; + } +} diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java index 9082fa9248..e6df3456fc 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java @@ -47,6 +47,11 @@ public Schema desired(MySQLSchema primary, Context context) { } } + @Override + protected boolean match(Schema actual, Schema target, Context context) { + return actual.equals(target); + } + @Override protected Schema create(Schema target, Context context) { return null; From 4b089c12b4fbef1be301c414d470437e0164090a Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 9 Feb 2022 13:02:59 +0100 Subject: [PATCH 07/25] fix: wip --- .../operator/ReconcilerUtils.java | 16 +++++ .../dependent/AbstractDependentResource.java | 8 +-- .../KubernetesDependentResource.java | 59 ++++++++----------- .../dependent/ObservedResource.java | 19 ------ ...StandaloneKubernetesDependentResource.java | 48 +++++++++++++++ .../operator/ReconcilerUtilsTest.java | 19 +++++- .../StandaloneDependentResourceIT.java | 44 +++++++++++++- .../StandaloneDependentTestReconciler.java | 40 +++++++------ .../TestCustomResourceSpec.java | 37 ------------ .../standalonedependent/nginx-deployment.yaml | 19 ++++++ .../sample/SchemaDependentResource.java | 4 +- 11 files changed, 199 insertions(+), 114 deletions(-) delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ObservedResource.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java delete mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/TestCustomResourceSpec.java create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/standalonedependent/nginx-deployment.yaml diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java index 63de88d1fb..411901f0ed 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java @@ -6,6 +6,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.OwnerReference; import io.javaoperatorsdk.operator.api.reconciler.Constants; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; @@ -106,6 +107,10 @@ public static String getDefaultReconcilerName(String reconcilerClassName) { } public static boolean specsEqual(HasMetadata r1, HasMetadata r2) { + return getSpec(r1).equals(getSpec(r2)); + } + + public static boolean specsSame(HasMetadata r1, HasMetadata r2) { try { var c1json = OBJECT_MAPPER.writeValueAsString(getSpec(r1)); var c2json = OBJECT_MAPPER.writeValueAsString(getSpec(r2)); @@ -125,4 +130,15 @@ public static Object getSpec(HasMetadata resource) { } } + public static void addOwnerReference(HasMetadata resource, HasMetadata owner) { + OwnerReference ownerReference = new OwnerReference(); + ownerReference.setName(owner.getMetadata().getName()); + ownerReference.setKind(owner.getKind()); + ownerReference.setApiVersion(owner.getApiVersion()); + ownerReference.setBlockOwnerDeletion(true); + ownerReference.setController(false); + ownerReference.setUid(owner.getMetadata().getUid()); + resource.getMetadata().getOwnerReferences().add(ownerReference); + } + } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index fe5c0cd269..55d093b039 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -11,10 +11,10 @@ public void reconcile(P primary, Context context) { var actual = getResource(primary); var desired = desired(primary, context); if (actual.isEmpty()) { - create(desired, context); + create(desired,primary, context); } else { if (!match(actual.get(), desired, context)) { - update(actual.get(), desired, context); + update(actual.get(), desired, primary, context); } } } @@ -23,9 +23,9 @@ public void reconcile(P primary, Context context) { protected abstract boolean match(R actual, R target, Context context); - protected abstract R create(R target, Context context); + protected abstract R create(R target,P primary, Context context); // the actual needed to copy/preserve new labels or annotations - protected abstract R update(R actual, R target, Context context); + protected abstract R update(R actual, R target, P primary, Context context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index 8c551b7b43..3cd03d1c5b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -17,34 +17,25 @@ import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; // todo owned: owner reference setting -public class KubernetesDependentResource +public abstract class KubernetesDependentResource extends AbstractDependentResource { private KubernetesClient client; - private boolean manageDelete; + private boolean explicitDelete = false; + private boolean owned = true; private InformerEventSource informerEventSource; - private DesiredSupplier desiredSupplier = null; public KubernetesDependentResource() { - this(null, false); + this(null); } public KubernetesDependentResource(KubernetesClient client) { - this(client, false); - } - - public KubernetesDependentResource(KubernetesClient client, boolean manageDelete) { this.client = client; - this.manageDelete = manageDelete; } - @Override - protected R desired(P primary, Context context) { - if (desiredSupplier != null) { - return desiredSupplier.getDesired(primary, context); - } else { - throw new OperatorException( - "No DesiredSupplier provided. Either provide one or override this method"); + protected void postProcessDesired(R desired, P primary) { + if (owned) { + ReconcilerUtils.addOwnerReference(desired,primary); } } @@ -54,15 +45,17 @@ protected boolean match(R actual, R target, Context context) { } @Override - protected R create(R target, Context context) { - // todo implement here https://github.com/java-operator-sdk/java-operator-sdk/issues/870 - return client.resource(target).createOrReplace(); + protected R create(R target,P primary, Context context) { + postProcessDesired(target,primary); + Class targetClass = (Class) target.getClass(); + var res = client.resources(targetClass).create(target); + return res; + } @Override - protected R update(R actual, R target, Context context) { - // todo implement here https://github.com/java-operator-sdk/java-operator-sdk/issues/870 - // todo map annotation and labels ? + protected R update(R actual, R target,P primary, Context context) { + postProcessDesired(target,primary); return client.resource(target).createOrReplace(); } @@ -101,7 +94,7 @@ public KubernetesDependentResource setInformerEventSource( @Override public void delete(P primary, Context context) { - if (manageDelete) { + if (explicitDelete) { var resource = getResource(primary); resource.ifPresent(r -> client.resource(r).delete()); } @@ -117,22 +110,22 @@ public KubernetesDependentResource setClient(KubernetesClient client) { return this; } - public KubernetesDependentResource setDesiredSupplier( - DesiredSupplier desiredSupplier) { - this.desiredSupplier = desiredSupplier; + + public KubernetesDependentResource setExplicitDelete(boolean explicitDelete) { + this.explicitDelete = explicitDelete; return this; } - public KubernetesDependentResource setManageDelete(boolean manageDelete) { - this.manageDelete = manageDelete; - return this; + public boolean isExplicitDelete() { + return explicitDelete; } - public boolean isManageDelete() { - return manageDelete; + public boolean isOwned() { + return owned; } - public DesiredSupplier getDesiredSupplier() { - return desiredSupplier; + public KubernetesDependentResource setOwned(boolean owned) { + this.owned = owned; + return this; } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ObservedResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ObservedResource.java deleted file mode 100644 index 99478dd43b..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ObservedResource.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.javaoperatorsdk.operator.api.reconciler.dependent; - -import java.util.Optional; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.processing.event.source.EventSource; - -// todo resource: resource which we don't manage just aware of, and needs it for input -// -public interface ObservedResource { - - default Optional initEventSource(EventSourceContext

context) { - return Optional.empty(); - } - - Optional getResource(); - -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java new file mode 100644 index 0000000000..48b2ad99df --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java @@ -0,0 +1,48 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.OperatorException; +import io.javaoperatorsdk.operator.api.reconciler.Context; + +public class StandaloneKubernetesDependentResource + extends KubernetesDependentResource { + + private DesiredSupplier desiredSupplier = null; + private Class resourceType; + + public StandaloneKubernetesDependentResource() { + } + + public StandaloneKubernetesDependentResource(KubernetesClient client, DesiredSupplier desiredSupplier, + Class resourceType) { + super(client); + this.desiredSupplier = desiredSupplier; + this.resourceType = resourceType; + } + + @Override + protected R desired(P primary, Context context) { + if (desiredSupplier != null) { + return desiredSupplier.getDesired(primary, context); + } else { + throw new OperatorException( + "No DesiredSupplier provided. Either provide one or override this method"); + } + } + + public KubernetesDependentResource setDesiredSupplier( + DesiredSupplier desiredSupplier) { + this.desiredSupplier = desiredSupplier; + return this; + } + + public StandaloneKubernetesDependentResource setResourceType(Class resourceType) { + this.resourceType = resourceType; + return this; + } + + public Class resourceType() { + return resourceType; + } +} diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java index 7bc5185bab..46afa8dcfe 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java @@ -51,7 +51,7 @@ void comparesArbitrarySpecsOfObjects() { var d1 = createTestDeployment(); var d2 = createTestDeployment(); - assertThat(ReconcilerUtils.specsEqual(d1, d2)).isTrue(); + assertThat(ReconcilerUtils.specsSame(d1, d2)).isTrue(); } @Test @@ -60,6 +60,23 @@ void comparesArbitraryDifferentSpecsOfObjects() { var d2 = createTestDeployment(); d2.getSpec().getTemplate().getSpec().setHostname("otherhost"); + assertThat(ReconcilerUtils.specsSame(d1, d2)).isFalse(); + } + + @Test + void equalsSpecObject() { + var d1 = createTestDeployment(); + var d2 = createTestDeployment(); + + assertThat(ReconcilerUtils.specsEqual(d1, d2)).isTrue(); + } + + @Test + void equalArbitraryDifferentSpecsOfObjects() { + var d1 = createTestDeployment(); + var d2 = createTestDeployment(); + d2.getSpec().getTemplate().getSpec().setHostname("otherhost"); + assertThat(ReconcilerUtils.specsEqual(d1, d2)).isFalse(); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java index 16afa9b173..7c1213407d 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java @@ -1,4 +1,46 @@ package io.javaoperatorsdk.operator.dependent; -public class StandaloneDependentResourceIT { +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; +import io.javaoperatorsdk.operator.junit.OperatorExtension; +import io.javaoperatorsdk.operator.sample.standalonedependent.StandaloneDependentTestCustomResource; +import io.javaoperatorsdk.operator.sample.standalonedependent.StandaloneDependentTestReconciler; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.time.Duration; + +import static org.awaitility.Awaitility.await; + +class StandaloneDependentResourceIT { + + public static final String DEPENDENT_TEST_NAME = "dependent-test1"; + @RegisterExtension + OperatorExtension operator = + OperatorExtension.builder() + .withConfigurationService(DefaultConfigurationService.instance()) + .withReconciler(new StandaloneDependentTestReconciler()) + .build(); + + @Test + void dependentResourceManagesDeployment() { + StandaloneDependentTestCustomResource customResource = + new StandaloneDependentTestCustomResource(); + customResource.setMetadata(new ObjectMeta()); + customResource.getMetadata().setName(DEPENDENT_TEST_NAME); + operator.create(StandaloneDependentTestCustomResource.class, customResource); + + + await() + .atMost(Duration.ofSeconds(55)) + .until( + () -> { + StandaloneDependentTestReconciler reconciler = + (StandaloneDependentTestReconciler) operator.getReconcilers().get(0); + + return reconciler.getNumberOfExecutions() > 3; + }); + + System.out.println("test print"); + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java index 78f9310588..096bc9b2e7 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java @@ -1,16 +1,17 @@ package io.javaoperatorsdk.operator.sample.standalonedependent; -import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.utils.Serialization; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DesiredSupplier; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.StandaloneKubernetesDependentResource; import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; +import java.io.IOException; +import java.io.InputStream; import java.util.List; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; @@ -25,22 +26,22 @@ public class StandaloneDependentTestReconciler private final AtomicInteger numberOfExecutions = new AtomicInteger(0); private KubernetesClient kubernetesClient; - KubernetesDependentResource configMapDependent; - + StandaloneKubernetesDependentResource configMapDependent; public StandaloneDependentTestReconciler() { - configMapDependent = new KubernetesDependentResource(); - configMapDependent.setDesiredSupplier(new DesiredSupplier() { - @Override - public ConfigMap getDesired(StandaloneDependentTestCustomResource primary, Context context) { - return null; - } - }); + configMapDependent = new StandaloneKubernetesDependentResource<>(); + configMapDependent.setResourceType(Deployment.class); + configMapDependent.setDesiredSupplier( + (primary, context) -> { + Deployment deployment = loadYaml(Deployment.class, "nginx-deployment.yaml"); + deployment.getMetadata().setName(primary.getMetadata().getName()); + return deployment; + }); } @Override public List prepareEventSources( - EventSourceContext context) { + EventSourceContext context) { return List.of(configMapDependent.eventSource(context).get()); } @@ -48,8 +49,7 @@ public List prepareEventSources( public UpdateControl reconcile( StandaloneDependentTestCustomResource resource, Context context) { numberOfExecutions.addAndGet(1); - - configMapDependent.reconcile(resource,context); + configMapDependent.reconcile(resource, context); return UpdateControl.noUpdate(); } @@ -68,5 +68,11 @@ public KubernetesClient getKubernetesClient() { return this.kubernetesClient; } - + private T loadYaml(Class clazz, String yaml) { + try (InputStream is = getClass().getResourceAsStream(yaml)) { + return Serialization.unmarshal(is, clazz); + } catch (IOException ex) { + throw new IllegalStateException("Cannot find yaml on classpath: " + yaml); + } + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/TestCustomResourceSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/TestCustomResourceSpec.java deleted file mode 100644 index 2ad2f02d40..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/TestCustomResourceSpec.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.javaoperatorsdk.operator.sample.standalonedependent; - -import java.util.Objects; - -public class TestCustomResourceSpec { - - private String value; - - public String getValue() { - return value; - } - - public TestCustomResourceSpec setValue(String value) { - this.value = value; - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TestCustomResourceSpec that = (TestCustomResourceSpec) o; - return Objects.equals(value, that.value); - } - - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public String toString() { - return "TestCustomResourceSpec{" + - "value='" + value + '\'' + - '}'; - } -} diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/standalonedependent/nginx-deployment.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/standalonedependent/nginx-deployment.yaml new file mode 100644 index 0000000000..573b1b7a06 --- /dev/null +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/standalonedependent/nginx-deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 +kind: Deployment +metadata: + name: "" +spec: + selector: + matchLabels: + app: "test-dependent" + replicas: 1 + template: + metadata: + labels: + app: "test-dependent" + spec: + containers: + - name: nginx + image: nginx:1.17.0 + ports: + - containerPort: 80 diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java index e6df3456fc..a480888812 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java @@ -53,12 +53,12 @@ protected boolean match(Schema actual, Schema target, Context context) { } @Override - protected Schema create(Schema target, Context context) { + protected Schema create(Schema target, MySQLSchema mySQLSchema, Context context) { return null; } @Override - protected Schema update(Schema actual, Schema target, Context context) { + protected Schema update(Schema actual, Schema target, MySQLSchema mySQLSchema, Context context) { return null; } From b3edc690faaa35ab62cc3128a36e2a7cd2e2ddf7 Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 9 Feb 2022 14:45:57 +0100 Subject: [PATCH 08/25] fix: IT test standalone resource --- .../dependent/AbstractDependentResource.java | 4 +- .../KubernetesDependentResource.java | 32 +++++--- ...StandaloneKubernetesDependentResource.java | 76 +++++++++---------- .../StandaloneDependentResourceIT.java | 36 +++++---- ...StandaloneDependentTestCustomResource.java | 1 - .../StandaloneDependentTestReconciler.java | 32 ++++---- .../standalonedependent/nginx-deployment.yaml | 2 + .../sample/DeploymentDependentResource.java | 4 - .../sample/ServiceDependentResource.java | 4 +- 9 files changed, 105 insertions(+), 86 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index 55d093b039..ea8b8bc06b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -11,7 +11,7 @@ public void reconcile(P primary, Context context) { var actual = getResource(primary); var desired = desired(primary, context); if (actual.isEmpty()) { - create(desired,primary, context); + create(desired, primary, context); } else { if (!match(actual.get(), desired, context)) { update(actual.get(), desired, primary, context); @@ -23,7 +23,7 @@ public void reconcile(P primary, Context context) { protected abstract boolean match(R actual, R target, Context context); - protected abstract R create(R target,P primary, Context context); + protected abstract R create(R target, P primary, Context context); // the actual needed to copy/preserve new labels or annotations protected abstract R update(R actual, R target, P primary, Context context); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index 3cd03d1c5b..e65584a370 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -2,9 +2,11 @@ import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -20,6 +22,8 @@ public abstract class KubernetesDependentResource extends AbstractDependentResource { + private static final Logger log = LoggerFactory.getLogger(KubernetesDependentResource.class); + private KubernetesClient client; private boolean explicitDelete = false; private boolean owned = true; @@ -35,28 +39,36 @@ public KubernetesDependentResource(KubernetesClient client) { protected void postProcessDesired(R desired, P primary) { if (owned) { - ReconcilerUtils.addOwnerReference(desired,primary); + ReconcilerUtils.addOwnerReference(desired, primary); } } @Override protected boolean match(R actual, R target, Context context) { + // todo handle this more smart: deployment created is updated with defaults, won't be equal + // use the created to compare from that point? or just compare the non null values from target + // for deployment? return ReconcilerUtils.specsEqual(actual, target); } @Override - protected R create(R target,P primary, Context context) { - postProcessDesired(target,primary); + protected R create(R target, P primary, Context context) { + log.debug("Creating target resource with type: " + + "{}, with id: {}", target.getClass(), ResourceID.fromResource(target)); + postProcessDesired(target, primary); Class targetClass = (Class) target.getClass(); - var res = client.resources(targetClass).create(target); - return res; - + return client.resources(targetClass).inNamespace(target.getMetadata().getNamespace()) + .create(target); } @Override - protected R update(R actual, R target,P primary, Context context) { - postProcessDesired(target,primary); - return client.resource(target).createOrReplace(); + protected R update(R actual, R target, P primary, Context context) { + log.debug("Updating target resource with type: {}, with id: {}", target.getClass(), + ResourceID.fromResource(target)); + postProcessDesired(target, primary); + Class targetClass = (Class) target.getClass(); + return client.resources(targetClass).inNamespace(target.getMetadata().getNamespace()) + .replace(target); } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java index 48b2ad99df..836c0bc389 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java @@ -6,43 +6,43 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; public class StandaloneKubernetesDependentResource - extends KubernetesDependentResource { - - private DesiredSupplier desiredSupplier = null; - private Class resourceType; - - public StandaloneKubernetesDependentResource() { - } - - public StandaloneKubernetesDependentResource(KubernetesClient client, DesiredSupplier desiredSupplier, - Class resourceType) { - super(client); - this.desiredSupplier = desiredSupplier; - this.resourceType = resourceType; - } - - @Override - protected R desired(P primary, Context context) { - if (desiredSupplier != null) { - return desiredSupplier.getDesired(primary, context); - } else { - throw new OperatorException( - "No DesiredSupplier provided. Either provide one or override this method"); - } - } - - public KubernetesDependentResource setDesiredSupplier( - DesiredSupplier desiredSupplier) { - this.desiredSupplier = desiredSupplier; - return this; - } - - public StandaloneKubernetesDependentResource setResourceType(Class resourceType) { - this.resourceType = resourceType; - return this; - } - - public Class resourceType() { - return resourceType; + extends KubernetesDependentResource { + + private DesiredSupplier desiredSupplier = null; + private Class resourceType; + + public StandaloneKubernetesDependentResource() {} + + public StandaloneKubernetesDependentResource(KubernetesClient client, + DesiredSupplier desiredSupplier, + Class resourceType) { + super(client); + this.desiredSupplier = desiredSupplier; + this.resourceType = resourceType; + } + + @Override + protected R desired(P primary, Context context) { + if (desiredSupplier != null) { + return desiredSupplier.getDesired(primary, context); + } else { + throw new OperatorException( + "No DesiredSupplier provided. Either provide one or override this method"); } + } + + public KubernetesDependentResource setDesiredSupplier( + DesiredSupplier desiredSupplier) { + this.desiredSupplier = desiredSupplier; + return this; + } + + public StandaloneKubernetesDependentResource setResourceType(Class resourceType) { + this.resourceType = resourceType; + return this; + } + + public Class resourceType() { + return resourceType; + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java index 7c1213407d..39cf78d155 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java @@ -1,21 +1,24 @@ package io.javaoperatorsdk.operator.dependent; +import java.time.Duration; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.apps.Deployment; import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; import io.javaoperatorsdk.operator.junit.OperatorExtension; import io.javaoperatorsdk.operator.sample.standalonedependent.StandaloneDependentTestCustomResource; import io.javaoperatorsdk.operator.sample.standalonedependent.StandaloneDependentTestReconciler; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import java.time.Duration; import static org.awaitility.Awaitility.await; class StandaloneDependentResourceIT { - public static final String DEPENDENT_TEST_NAME = "dependent-test1"; - @RegisterExtension + public static final String DEPENDENT_TEST_NAME = "dependent-test1"; + + @RegisterExtension OperatorExtension operator = OperatorExtension.builder() .withConfigurationService(DefaultConfigurationService.instance()) @@ -28,19 +31,26 @@ void dependentResourceManagesDeployment() { new StandaloneDependentTestCustomResource(); customResource.setMetadata(new ObjectMeta()); customResource.getMetadata().setName(DEPENDENT_TEST_NAME); - operator.create(StandaloneDependentTestCustomResource.class, customResource); - + var createdCR = operator.create(StandaloneDependentTestCustomResource.class, customResource); await() - .atMost(Duration.ofSeconds(55)) + .pollInterval(Duration.ofMillis(300)) + .atMost(Duration.ofSeconds(50)) .until( () -> { StandaloneDependentTestReconciler reconciler = (StandaloneDependentTestReconciler) operator.getReconcilers().get(0); - - return reconciler.getNumberOfExecutions() > 3; + var deployment = + operator + .getKubernetesClient() + .resources(Deployment.class) + .inNamespace(createdCR.getMetadata().getNamespace()) + .withName(DEPENDENT_TEST_NAME) + .get(); + return deployment != null + && deployment.getStatus() != null + && deployment.getStatus().getReadyReplicas() != null + && deployment.getStatus().getReadyReplicas() > 0; }); - - System.out.println("test print"); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResource.java index c03e22d655..3e6737c83c 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestCustomResource.java @@ -3,7 +3,6 @@ import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.model.annotation.Group; -import io.fabric8.kubernetes.model.annotation.Kind; import io.fabric8.kubernetes.model.annotation.ShortNames; import io.fabric8.kubernetes.model.annotation.Version; diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java index 096bc9b2e7..54a63c1c7e 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java @@ -1,5 +1,10 @@ package io.javaoperatorsdk.operator.sample.standalonedependent; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Objects; + import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.utils.Serialization; @@ -7,34 +12,34 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.StandaloneKubernetesDependentResource; import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; -import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; - -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; @ControllerConfiguration(finalizerName = NO_FINALIZER) public class StandaloneDependentTestReconciler implements Reconciler, - EventSourceInitializer, - TestExecutionInfoProvider, - KubernetesClientAware { + EventSourceInitializer, + KubernetesClientAware { - private final AtomicInteger numberOfExecutions = new AtomicInteger(0); private KubernetesClient kubernetesClient; StandaloneKubernetesDependentResource configMapDependent; public StandaloneDependentTestReconciler() { - configMapDependent = new StandaloneKubernetesDependentResource<>(); + configMapDependent = new StandaloneKubernetesDependentResource<>() { + @Override + protected boolean match(Deployment actual, Deployment target, Context context) { + return Objects.equals(actual.getSpec().getReplicas(), target.getSpec().getReplicas()) && + actual.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + .equals(target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); + } + }; configMapDependent.setResourceType(Deployment.class); configMapDependent.setDesiredSupplier( (primary, context) -> { Deployment deployment = loadYaml(Deployment.class, "nginx-deployment.yaml"); deployment.getMetadata().setName(primary.getMetadata().getName()); + deployment.getMetadata().setNamespace(primary.getMetadata().getNamespace()); return deployment; }); } @@ -48,15 +53,10 @@ public List prepareEventSources( @Override public UpdateControl reconcile( StandaloneDependentTestCustomResource resource, Context context) { - numberOfExecutions.addAndGet(1); configMapDependent.reconcile(resource, context); return UpdateControl.noUpdate(); } - public int getNumberOfExecutions() { - return numberOfExecutions.get(); - } - @Override public void setKubernetesClient(KubernetesClient kubernetesClient) { this.kubernetesClient = kubernetesClient; diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/standalonedependent/nginx-deployment.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/standalonedependent/nginx-deployment.yaml index 573b1b7a06..cea0f3c9d6 100644 --- a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/standalonedependent/nginx-deployment.yaml +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/standalonedependent/nginx-deployment.yaml @@ -3,6 +3,8 @@ kind: Deployment metadata: name: "" spec: + progressDeadlineSeconds: 600 + revisionHistoryLimit: 10 selector: matchLabels: app: "test-dependent" diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index 52fa1ad689..dc81e301ba 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -16,10 +16,6 @@ public DeploymentDependentResource(KubernetesClient client) { super(client); } - public DeploymentDependentResource(KubernetesClient client, boolean manageDelete) { - super(client, manageDelete); - } - @Override public Deployment desired(Tomcat tomcat, Context context) { Deployment deployment = TomcatReconciler.loadYaml(Deployment.class, "deployment.yaml"); diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java index f84825bcca..ca6b96151f 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java @@ -9,8 +9,8 @@ public class ServiceDependentResource extends KubernetesDependentResource { - public ServiceDependentResource(KubernetesClient client, boolean manageDelete) { - super(client, manageDelete); + public ServiceDependentResource(KubernetesClient client) { + super(client); } @Override From 7b73814db9e5fe3439336bbc92be1370e819bf9d Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 9 Feb 2022 15:14:33 +0100 Subject: [PATCH 09/25] fix: refactor mysql sample --- .../sample/SchemaDependentResource.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java index a480888812..28bbfbe61d 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java @@ -30,11 +30,21 @@ public Optional eventSource(EventSourceContext context @Override public Schema desired(MySQLSchema primary, Context context) { + return new Schema(primary.getMetadata().getName(), primary.getSpec().getEncoding()); + } + + @Override + protected boolean match(Schema actual, Schema target, Context context) { + return actual.equals(target); + } + + @Override + protected Schema create(Schema target, MySQLSchema mySQLSchema, Context context) { try (Connection connection = getConnection()) { final var schema = SchemaService.createSchemaAndRelatedUser( connection, - primary.getMetadata().getName(), - primary.getSpec().getEncoding(), + target.getName(), + target.getCharacterSet(), context.getMandatory(MySQLSchemaReconciler.MYSQL_SECRET_USERNAME, String.class), context.getMandatory(MySQLSchemaReconciler.MYSQL_SECRET_PASSWORD, String.class)); @@ -47,19 +57,9 @@ public Schema desired(MySQLSchema primary, Context context) { } } - @Override - protected boolean match(Schema actual, Schema target, Context context) { - return actual.equals(target); - } - - @Override - protected Schema create(Schema target, MySQLSchema mySQLSchema, Context context) { - return null; - } - @Override protected Schema update(Schema actual, Schema target, MySQLSchema mySQLSchema, Context context) { - return null; + throw new IllegalStateException("Target schema should not be changed: " + mySQLSchema); } private Connection getConnection() throws SQLException { From 76a6dc6d80383601dc1fb8c3e318f663fb44aa06 Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 9 Feb 2022 15:45:42 +0100 Subject: [PATCH 10/25] fix: wip --- .../operator/sample/DeploymentDependentResource.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index dc81e301ba..707b4138a8 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -51,9 +51,7 @@ private String tomcatImage(Tomcat tomcat) { @Override public boolean match(Deployment fetched, Deployment target, Context context) { - // todo compare spec - return true; - // return fetched.getSpec().getTemplate().getSpec().getContainers().stream() - // .findFirst().map(c -> tomcatImage(tomcat).equals(c.getImage())).orElse(false); + return fetched.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + .equals(target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); } } From 2d3289bca67603c5ccd253857bb641eabbcb11e9 Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 9 Feb 2022 16:18:54 +0100 Subject: [PATCH 11/25] fix: merged next --- .../operator/sample/DeploymentDependentResource.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index 707b4138a8..b82391b050 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -51,7 +51,7 @@ private String tomcatImage(Tomcat tomcat) { @Override public boolean match(Deployment fetched, Deployment target, Context context) { - return fetched.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() - .equals(target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); + return fetched.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + .equals(target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); } } From 850a2ff3d694b718f68850f0b2876103ad60b348 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 10 Feb 2022 09:29:14 +0100 Subject: [PATCH 12/25] fix: tomcat e2e tests --- .../sample/DeploymentDependentResource.java | 3 +- .../sample/ServiceDependentResource.java | 3 +- .../sample/TomcatDependentResource.java | 47 ------------------- 3 files changed, 2 insertions(+), 51 deletions(-) delete mode 100644 sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index b82391b050..c4bf531a61 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -12,8 +12,7 @@ public class DeploymentDependentResource extends KubernetesDependentResource { - public DeploymentDependentResource(KubernetesClient client) { - super(client); + public DeploymentDependentResource() { } @Override diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java index ca6b96151f..41ca0502ae 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java @@ -9,8 +9,7 @@ public class ServiceDependentResource extends KubernetesDependentResource { - public ServiceDependentResource(KubernetesClient client) { - super(client); + public ServiceDependentResource() { } @Override diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java deleted file mode 100644 index b21acd4cc4..0000000000 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatDependentResource.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.javaoperatorsdk.operator.sample; - -import java.util.Set; -import java.util.stream.Collectors; - -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; -import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; -import io.javaoperatorsdk.operator.processing.event.source.EventSourceContextAware; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; -import io.javaoperatorsdk.operator.processing.event.source.ResourceCache; - -public class TomcatDependentResource extends KubernetesDependentResource - implements PrimaryResourcesRetriever, - AssociatedSecondaryResourceIdentifier, EventSourceContextAware { - - private ResourceCache primaryCache; - - @Override - public void initWith(EventSourceContext context) { - this.primaryCache = context.getPrimaryCache(); - } - - @Override - public Set associatedPrimaryResources(Tomcat t) { - // To create an event to a related WebApp resource and trigger the reconciliation - // we need to find which WebApp this Tomcat custom resource is related to. - // To find the related customResourceId of the WebApp resource we traverse the cache to - // and identify it based on naming convention. - return primaryCache - .list(webApp -> webApp.getSpec().getTomcat().equals(t.getMetadata().getName())) - .map(ResourceID::fromResource) - .collect(Collectors.toSet()); - } - - @Override - public ResourceID associatedSecondaryID(Webapp primary) { - return new ResourceID(primary.getSpec().getTomcat(), primary.getMetadata().getNamespace()); - } - - @Override - protected Tomcat desired(Webapp primary, Context context) { - return null; - } -} From 68a2619d93ca41cd39177255e504bac3aeb808fd Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 10 Feb 2022 09:37:09 +0100 Subject: [PATCH 13/25] fix: format --- .../operator/sample/DeploymentDependentResource.java | 4 +--- .../operator/sample/ServiceDependentResource.java | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index c4bf531a61..b681ccf6b6 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -3,7 +3,6 @@ import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependent; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; @@ -12,8 +11,7 @@ public class DeploymentDependentResource extends KubernetesDependentResource { - public DeploymentDependentResource() { - } + public DeploymentDependentResource() {} @Override public Deployment desired(Tomcat tomcat, Context context) { diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java index 41ca0502ae..16a6aaff2e 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java @@ -3,14 +3,12 @@ import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; public class ServiceDependentResource extends KubernetesDependentResource { - public ServiceDependentResource() { - } + public ServiceDependentResource() {} @Override public Service desired(Tomcat tomcat, Context context) { From 73c76dcbcccd285ebb5092f20c54207fdacf9758 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 10 Feb 2022 10:36:05 +0100 Subject: [PATCH 14/25] fix: wip --- .../sample/MySQLSchemaReconciler.java | 32 ++-------------- .../sample/SchemaDependentResource.java | 3 +- .../sample/SecretDependentResource.java | 38 +++++++++++++++++++ .../sample/MySQLSchemaOperatorE2E.java | 4 +- 4 files changed, 46 insertions(+), 31 deletions(-) create mode 100644 sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java index 44ee0ff9e7..98426d3a2f 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java @@ -19,8 +19,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.RetryInfo; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; -import io.javaoperatorsdk.operator.sample.MySQLSchemaReconciler.SecretDependentResource; import io.javaoperatorsdk.operator.sample.schema.Schema; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; @@ -39,10 +37,10 @@ public class MySQLSchemaReconciler private static final String SECRET_FORMAT = "%s-secret"; private static final String USERNAME_FORMAT = "%s-user"; - protected static final String MYSQL_SECRET_NAME = "mysql.secret.name"; - protected static final String MYSQL_SECRET_USERNAME = "mysql.secret.user.name"; - protected static final String MYSQL_SECRET_PASSWORD = "mysql.secret.user.password"; - protected static final String MYSQL_DB_CONFIG = "mysql.db.config"; + public static final String MYSQL_SECRET_NAME = "mysql.secret.name"; + public static final String MYSQL_SECRET_USERNAME = "mysql.secret.user.name"; + public static final String MYSQL_SECRET_PASSWORD = "mysql.secret.user.password"; + public static final String MYSQL_DB_CONFIG = "mysql.db.config"; protected static final String BUILT_SCHEMA = "built schema"; static final Logger log = LoggerFactory.getLogger(MySQLSchemaReconciler.class); @@ -52,28 +50,6 @@ public MySQLSchemaReconciler(MySQLDbConfig mysqlDbConfig) { this.mysqlDbConfig = mysqlDbConfig; } - public static class SecretDependentResource - extends KubernetesDependentResource { - - private static String encode(String value) { - return Base64.getEncoder().encodeToString(value.getBytes()); - } - - @Override - public Secret desired(MySQLSchema schema, Context context) { - return new SecretBuilder() - .withNewMetadata() - .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) - .withNamespace(schema.getMetadata().getNamespace()) - .endMetadata() - .addToData("MYSQL_USERNAME", encode( - context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) - .addToData("MYSQL_PASSWORD", encode( - context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) - .build(); - } - } - @SuppressWarnings("rawtypes") @Override public void injectInto(EventSourceContext context) { diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java index 28bbfbe61d..957f0b34ff 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java @@ -81,6 +81,7 @@ public void delete(MySQLSchema primary, Context context) { } } + // todo this should read the resource from event source? @Override public Optional getResource(MySQLSchema primaryResource) { try (Connection connection = getConnection()) { @@ -88,7 +89,7 @@ public Optional getResource(MySQLSchema primaryResource) { SchemaService.getSchema(connection, primaryResource.getMetadata().getName()).orElse(null); return Optional.ofNullable(schema); } catch (SQLException e) { - throw new RuntimeException("Error while trying to delete Schema", e); + throw new RuntimeException("Error while trying read Schema", e); } } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java new file mode 100644 index 0000000000..030b632db7 --- /dev/null +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java @@ -0,0 +1,38 @@ +package io.javaoperatorsdk.operator.sample; + +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.event.ResourceID; + +import java.util.Base64; + +import static io.javaoperatorsdk.operator.sample.MySQLSchemaReconciler.*; + +public class SecretDependentResource + extends KubernetesDependentResource { + + private static String encode(String value) { + return Base64.getEncoder().encodeToString(value.getBytes()); + } + + @Override + public Secret desired(MySQLSchema schema, Context context) { + return new SecretBuilder() + .withNewMetadata() + .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) + .withNamespace(schema.getMetadata().getNamespace()) + .endMetadata() + .addToData("MYSQL_USERNAME", encode( + context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) + .addToData("MYSQL_PASSWORD", encode( + context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) + .build(); + } + + @Override + protected boolean match(Secret actual, Secret target, Context context) { + return ResourceID.fromResource(actual).equals(ResourceID.fromResource(target)); + } +} \ No newline at end of file diff --git a/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java b/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java index 6049627f94..7317e90939 100644 --- a/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java +++ b/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java @@ -113,8 +113,8 @@ public void test() throws IOException { log.info("Creating test MySQLSchema object: {}", testSchema); client.resource(testSchema).createOrReplace(); - log.info("Waiting 5 minutes for expected resources to be created and updated"); - await().atMost(1, MINUTES).ignoreExceptions().untilAsserted(() -> { + log.info("Waiting 2 minutes for expected resources to be created and updated"); + await().atMost(2, MINUTES).ignoreExceptions().untilAsserted(() -> { MySQLSchema updatedSchema = client.resources(MySQLSchema.class).inNamespace(operator.getNamespace()) .withName(testSchema.getMetadata().getName()).get(); From 64b7148b9194cd3a261ce2db9f914078f6c02599 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 10 Feb 2022 10:48:21 +0100 Subject: [PATCH 15/25] fix: secret handling --- .../sample/MySQLSchemaReconciler.java | 4 +- .../sample/SecretDependentResource.java | 60 +++++++++++-------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java index 98426d3a2f..9051f1182a 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java @@ -34,8 +34,8 @@ public class MySQLSchemaReconciler implements Reconciler, ErrorStatusHandler, ContextInitializer, EventSourceContextInjector { - private static final String SECRET_FORMAT = "%s-secret"; - private static final String USERNAME_FORMAT = "%s-user"; + public static final String SECRET_FORMAT = "%s-secret"; + public static final String USERNAME_FORMAT = "%s-user"; public static final String MYSQL_SECRET_NAME = "mysql.secret.name"; public static final String MYSQL_SECRET_USERNAME = "mysql.secret.user.name"; diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java index 030b632db7..9c26a00035 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java @@ -5,34 +5,42 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import java.util.Base64; import static io.javaoperatorsdk.operator.sample.MySQLSchemaReconciler.*; -public class SecretDependentResource - extends KubernetesDependentResource { - - private static String encode(String value) { - return Base64.getEncoder().encodeToString(value.getBytes()); - } - - @Override - public Secret desired(MySQLSchema schema, Context context) { - return new SecretBuilder() - .withNewMetadata() - .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) - .withNamespace(schema.getMetadata().getNamespace()) - .endMetadata() - .addToData("MYSQL_USERNAME", encode( - context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) - .addToData("MYSQL_PASSWORD", encode( - context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) - .build(); - } - - @Override - protected boolean match(Secret actual, Secret target, Context context) { - return ResourceID.fromResource(actual).equals(ResourceID.fromResource(target)); - } -} \ No newline at end of file +public class SecretDependentResource extends KubernetesDependentResource + implements AssociatedSecondaryResourceIdentifier { + + private static String encode(String value) { + return Base64.getEncoder().encodeToString(value.getBytes()); + } + + @Override + public Secret desired(MySQLSchema schema, Context context) { + return new SecretBuilder() + .withNewMetadata() + .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) + .withNamespace(schema.getMetadata().getNamespace()) + .endMetadata() + .addToData( + "MYSQL_USERNAME", encode(context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) + .addToData( + "MYSQL_PASSWORD", encode(context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) + .build(); + } + + @Override + protected boolean match(Secret actual, Secret target, Context context) { + return ResourceID.fromResource(actual).equals(ResourceID.fromResource(target)); + } + + @Override + public ResourceID associatedSecondaryID(MySQLSchema primary) { + return new ResourceID( + String.format(SECRET_FORMAT, primary.getMetadata().getName()), + primary.getMetadata().getNamespace()); + } +} From a3c71192d4d488f01ae1b3959e3fad70a0432b82 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 10 Feb 2022 10:50:48 +0100 Subject: [PATCH 16/25] fix: formaty --- .../operator/sample/MySQLSchemaReconciler.java | 2 -- .../operator/sample/SecretDependentResource.java | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java index 9051f1182a..62ebfad921 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java @@ -1,6 +1,5 @@ package io.javaoperatorsdk.operator.sample; -import java.util.Base64; import java.util.Optional; import org.apache.commons.lang3.RandomStringUtils; @@ -8,7 +7,6 @@ import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.Secret; -import io.fabric8.kubernetes.api.model.SecretBuilder; import io.javaoperatorsdk.operator.api.config.dependent.Dependent; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ContextInitializer; diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java index 9c26a00035..e516ec6e3e 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java @@ -1,5 +1,7 @@ package io.javaoperatorsdk.operator.sample; +import java.util.Base64; + import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretBuilder; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -7,8 +9,6 @@ import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; -import java.util.Base64; - import static io.javaoperatorsdk.operator.sample.MySQLSchemaReconciler.*; public class SecretDependentResource extends KubernetesDependentResource From c22c295082e1cc3186efe2991127773c0bedf79d Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 10 Feb 2022 15:45:11 +0100 Subject: [PATCH 17/25] fix: web page migrated to dependent resources --- .../operator/ReconcilerUtils.java | 12 - .../KubernetesDependentResource.java | 23 +- ...StandaloneKubernetesDependentResource.java | 47 +++- .../StandaloneDependentTestReconciler.java | 23 +- .../sample/SecretDependentResource.java | 8 + .../sample/MySQLSchemaOperatorE2E.java | 2 +- sample-operators/webpage/pom.xml | 5 + .../operator/sample/WebPageReconciler.java | 256 +++++++++--------- 8 files changed, 209 insertions(+), 167 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java index 411901f0ed..5e583b7ca0 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java @@ -6,7 +6,6 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.fabric8.kubernetes.api.model.OwnerReference; import io.javaoperatorsdk.operator.api.reconciler.Constants; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; @@ -130,15 +129,4 @@ public static Object getSpec(HasMetadata resource) { } } - public static void addOwnerReference(HasMetadata resource, HasMetadata owner) { - OwnerReference ownerReference = new OwnerReference(); - ownerReference.setName(owner.getMetadata().getName()); - ownerReference.setKind(owner.getKind()); - ownerReference.setApiVersion(owner.getApiVersion()); - ownerReference.setBlockOwnerDeletion(true); - ownerReference.setController(false); - ownerReference.setUid(owner.getMetadata().getUid()); - resource.getMetadata().getOwnerReferences().add(ownerReference); - } - } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index e65584a370..f971124e2e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -24,7 +24,7 @@ public abstract class KubernetesDependentResource informerEventSource; @@ -39,7 +39,7 @@ public KubernetesDependentResource(KubernetesClient client) { protected void postProcessDesired(R desired, P primary) { if (owned) { - ReconcilerUtils.addOwnerReference(desired, primary); + desired.addOwnerReference(primary); } } @@ -84,20 +84,27 @@ public Optional eventSource(EventSourceContext

context) { private InformerConfiguration initInformerConfiguration(EventSourceContext

context) { PrimaryResourcesRetriever associatedPrimaries = (this instanceof PrimaryResourcesRetriever) ? (PrimaryResourcesRetriever) this - : Mappers.fromOwnerReference(); + : getDefaultPrimaryResourcesRetriever(); - AssociatedSecondaryResourceIdentifier associatedSecondary = + AssociatedSecondaryResourceIdentifier

associatedSecondary = (this instanceof AssociatedSecondaryResourceIdentifier) - ? (AssociatedSecondaryResourceIdentifier) this - : (r) -> ResourceID.fromResource(r); + ? (AssociatedSecondaryResourceIdentifier

) this + : getDefaultAssociatedSecondaryResourceIdentifier(); return InformerConfiguration.from(context, resourceType()) .withPrimaryResourcesRetriever(associatedPrimaries) - .withAssociatedSecondaryResourceIdentifier( - (AssociatedSecondaryResourceIdentifier

) associatedSecondary) + .withAssociatedSecondaryResourceIdentifier(associatedSecondary) .build(); } + protected AssociatedSecondaryResourceIdentifier

getDefaultAssociatedSecondaryResourceIdentifier() { + return (r) -> ResourceID.fromResource(r); + } + + protected PrimaryResourcesRetriever getDefaultPrimaryResourcesRetriever() { + return Mappers.fromOwnerReference(); + } + public KubernetesDependentResource setInformerEventSource( InformerEventSource informerEventSource) { this.informerEventSource = informerEventSource; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java index 836c0bc389..8359f163dc 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java @@ -4,18 +4,28 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; +import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; +import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; +// todo shorter name public class StandaloneKubernetesDependentResource extends KubernetesDependentResource { - private DesiredSupplier desiredSupplier = null; - private Class resourceType; + private final DesiredSupplier desiredSupplier; + private final Class resourceType; + private AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier = + (r) -> ResourceID.fromResource(r); + private PrimaryResourcesRetriever primaryResourcesRetriever = Mappers.fromOwnerReference(); - public StandaloneKubernetesDependentResource() {} + public StandaloneKubernetesDependentResource( + Class resourceType, DesiredSupplier desiredSupplier) { + this(null, resourceType, desiredSupplier); + } - public StandaloneKubernetesDependentResource(KubernetesClient client, - DesiredSupplier desiredSupplier, - Class resourceType) { + public StandaloneKubernetesDependentResource( + KubernetesClient client, Class resourceType, DesiredSupplier desiredSupplier) { super(client); this.desiredSupplier = desiredSupplier; this.resourceType = resourceType; @@ -31,18 +41,29 @@ protected R desired(P primary, Context context) { } } - public KubernetesDependentResource setDesiredSupplier( - DesiredSupplier desiredSupplier) { - this.desiredSupplier = desiredSupplier; + public Class resourceType() { + return resourceType; + } + + public StandaloneKubernetesDependentResource setAssociatedSecondaryResourceIdentifier( + AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier) { + this.associatedSecondaryResourceIdentifier = associatedSecondaryResourceIdentifier; return this; } - public StandaloneKubernetesDependentResource setResourceType(Class resourceType) { - this.resourceType = resourceType; + public StandaloneKubernetesDependentResource setPrimaryResourcesRetriever( + PrimaryResourcesRetriever primaryResourcesRetriever) { + this.primaryResourcesRetriever = primaryResourcesRetriever; return this; } - public Class resourceType() { - return resourceType; + @Override + protected AssociatedSecondaryResourceIdentifier

getDefaultAssociatedSecondaryResourceIdentifier() { + return this.associatedSecondaryResourceIdentifier; + } + + @Override + protected PrimaryResourcesRetriever getDefaultPrimaryResourcesRetriever() { + return this.primaryResourcesRetriever; } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java index 54a63c1c7e..695cc30a31 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java @@ -26,22 +26,21 @@ public class StandaloneDependentTestReconciler StandaloneKubernetesDependentResource configMapDependent; public StandaloneDependentTestReconciler() { - configMapDependent = new StandaloneKubernetesDependentResource<>() { - @Override - protected boolean match(Deployment actual, Deployment target, Context context) { - return Objects.equals(actual.getSpec().getReplicas(), target.getSpec().getReplicas()) && - actual.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() - .equals(target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); - } - }; - configMapDependent.setResourceType(Deployment.class); - configMapDependent.setDesiredSupplier( - (primary, context) -> { + configMapDependent = + new StandaloneKubernetesDependentResource<>(Deployment.class, (primary, context) -> { Deployment deployment = loadYaml(Deployment.class, "nginx-deployment.yaml"); deployment.getMetadata().setName(primary.getMetadata().getName()); deployment.getMetadata().setNamespace(primary.getMetadata().getNamespace()); return deployment; - }); + }) { + @Override + protected boolean match(Deployment actual, Deployment target, Context context) { + return Objects.equals(actual.getSpec().getReplicas(), target.getSpec().getReplicas()) && + actual.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + .equals( + target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); + } + }; } @Override diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java index e516ec6e3e..4f6bd1759c 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java @@ -32,6 +32,14 @@ public Secret desired(MySQLSchema schema, Context context) { .build(); } + // An alternative would be to override reconcile() method and exclude the update part. + @Override + protected Secret update(Secret actual, Secret target, MySQLSchema primary, Context context) { + throw new IllegalStateException( + "Secret should not be updated. Secret: " + target + " for custom resource: " + + primary); + } + @Override protected boolean match(Secret actual, Secret target, Context context) { return ResourceID.fromResource(actual).equals(ResourceID.fromResource(target)); diff --git a/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java b/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java index 7317e90939..0c1be5efc0 100644 --- a/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java +++ b/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java @@ -29,7 +29,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.notNullValue; -public class MySQLSchemaOperatorE2E { +class MySQLSchemaOperatorE2E { final static Logger log = LoggerFactory.getLogger(MySQLSchemaOperatorE2E.class); diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 566ec8b314..40101a7413 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -40,6 +40,11 @@ crd-generator-apt provided + + org.awaitility + awaitility + compile + diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java index e02c438417..28d6ed3037 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java @@ -2,9 +2,8 @@ import java.io.IOException; import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import java.time.Duration; +import java.util.*; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -13,22 +12,40 @@ import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.dsl.Resource; -import io.fabric8.kubernetes.client.dsl.RollableScalableResource; -import io.fabric8.kubernetes.client.dsl.ServiceResource; import io.fabric8.kubernetes.client.utils.Serialization; import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.StandaloneKubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; -@ControllerConfiguration -public class WebPageReconciler implements Reconciler, ErrorStatusHandler { +import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; +import static org.awaitility.Awaitility.await; + +@ControllerConfiguration(finalizerName = NO_FINALIZER) +public class WebPageReconciler + implements Reconciler, ErrorStatusHandler, EventSourceInitializer { private final Logger log = LoggerFactory.getLogger(getClass()); private final KubernetesClient kubernetesClient; + private StandaloneKubernetesDependentResource configMapDR; + private StandaloneKubernetesDependentResource deploymentDR; + private StandaloneKubernetesDependentResource serviceDR; + public WebPageReconciler(KubernetesClient kubernetesClient) { this.kubernetesClient = kubernetesClient; + createDependentResources(kubernetesClient); + } + + @Override + public List prepareEventSources(EventSourceContext context) { + List eventSources = new ArrayList<>(3); + configMapDR.eventSource(context).ifPresent(es -> eventSources.add(es)); + deploymentDR.eventSource(context).ifPresent(es -> eventSources.add(es)); + serviceDR.eventSource(context).ifPresent(es -> eventSources.add(es)); + return eventSources; } @Override @@ -37,81 +54,14 @@ public UpdateControl reconcile(WebPage webPage, Context context) { throw new ErrorSimulationException("Simulating error"); } - String ns = webPage.getMetadata().getNamespace(); - String configMapName = configMapName(webPage); - String deploymentName = deploymentName(webPage); - - Map data = new HashMap<>(); - data.put("index.html", webPage.getSpec().getHtml()); - - ConfigMap htmlConfigMap = - new ConfigMapBuilder() - .withMetadata( - new ObjectMetaBuilder() - .withName(configMapName) - .withNamespace(ns) - .build()) - .withData(data) - .build(); - - Deployment deployment = loadYaml(Deployment.class, "deployment.yaml"); - deployment.getMetadata().setName(deploymentName); - deployment.getMetadata().setNamespace(ns); - deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName); - - deployment - .getSpec() - .getTemplate() - .getMetadata() - .getLabels() - .put("app", deploymentName); - deployment - .getSpec() - .getTemplate() - .getSpec() - .getVolumes() - .get(0) - .setConfigMap( - new ConfigMapVolumeSourceBuilder().withName(configMapName).build()); - - Service service = loadYaml(Service.class, "service.yaml"); - service.getMetadata().setName(serviceName(webPage)); - service.getMetadata().setNamespace(ns); - service.getSpec().setSelector(deployment.getSpec().getTemplate().getMetadata().getLabels()); - - ConfigMap existingConfigMap = - kubernetesClient - .configMaps() - .inNamespace(htmlConfigMap.getMetadata().getNamespace()) - .withName(htmlConfigMap.getMetadata().getName()) - .get(); - - log.info("Creating or updating ConfigMap {} in {}", htmlConfigMap.getMetadata().getName(), ns); - kubernetesClient.configMaps().inNamespace(ns).createOrReplace(htmlConfigMap); - log.info("Creating or updating Deployment {} in {}", deployment.getMetadata().getName(), ns); - kubernetesClient.apps().deployments().inNamespace(ns).createOrReplace(deployment); - - if (kubernetesClient.services().inNamespace(ns).withName(service.getMetadata().getName()) - .get() == null) { - log.info("Creating Service {} in {}", service.getMetadata().getName(), ns); - kubernetesClient.services().inNamespace(ns).createOrReplace(service); - } - - if (existingConfigMap != null) { - if (!StringUtils.equals( - existingConfigMap.getData().get("index.html"), - htmlConfigMap.getData().get("index.html"))) { - log.info("Restarting pods because HTML has changed in {}", ns); - kubernetesClient - .pods() - .inNamespace(ns) - .withLabel("app", deploymentName(webPage)) - .delete(); - } - } + configMapDR.reconcile(webPage, context); + deploymentDR.reconcile(webPage, context); + serviceDR.reconcile(webPage, context); WebPageStatus status = new WebPageStatus(); - status.setHtmlConfigMap(htmlConfigMap.getMetadata().getName()); + + waitUntilConfigMapAvailable(webPage); + status.setHtmlConfigMap(configMapDR.getResource(webPage).get().getMetadata().getName()); status.setAreWeGood("Yes!"); status.setErrorMessage(null); webPage.setStatus(status); @@ -119,41 +69,112 @@ public UpdateControl reconcile(WebPage webPage, Context context) { return UpdateControl.updateStatus(webPage); } - @Override - public DeleteControl cleanup(WebPage nginx, Context context) { - log.info("Cleaning up for: {}", nginx.getMetadata().getName()); - - log.info("Deleting ConfigMap {}", configMapName(nginx)); - Resource configMap = - kubernetesClient - .configMaps() - .inNamespace(nginx.getMetadata().getNamespace()) - .withName(configMapName(nginx)); - if (configMap.get() != null) { - configMap.delete(); - } + // todo after implemented we can remove this method: + // https://github.com/java-operator-sdk/java-operator-sdk/issues/924 + private void waitUntilConfigMapAvailable(WebPage webPage) { + await().atMost(Duration.ofSeconds(5)).until(() -> configMapDR.getResource(webPage).isPresent()); + } - log.info("Deleting Deployment {}", deploymentName(nginx)); - RollableScalableResource deployment = - kubernetesClient - .apps() - .deployments() - .inNamespace(nginx.getMetadata().getNamespace()) - .withName(deploymentName(nginx)); - if (deployment.get() != null) { - deployment.cascading(true).delete(); - } + @Override + public Optional updateErrorStatus( + WebPage resource, RetryInfo retryInfo, RuntimeException e) { + resource.getStatus().setErrorMessage("Error: " + e.getMessage()); + return Optional.of(resource); + } - log.info("Deleting Service {}", serviceName(nginx)); - ServiceResource service = - kubernetesClient - .services() - .inNamespace(nginx.getMetadata().getNamespace()) - .withName(serviceName(nginx)); - if (service.get() != null) { - service.delete(); - } - return DeleteControl.defaultDelete(); + private void createDependentResources(KubernetesClient client) { + this.configMapDR = + new StandaloneKubernetesDependentResource<>( + client, + ConfigMap.class, + (WebPage webPage, Context context) -> { + Map data = new HashMap<>(); + data.put("index.html", webPage.getSpec().getHtml()); + return new ConfigMapBuilder() + .withMetadata( + new ObjectMetaBuilder() + .withName(configMapName(webPage)) + .withNamespace(webPage.getMetadata().getNamespace()) + .build()) + .withData(data) + .build(); + }) { + @Override + protected boolean match(ConfigMap actual, ConfigMap target, Context context) { + return StringUtils.equals( + actual.getData().get("index.html"), target.getData().get("index.html")); + } + + @Override + protected ConfigMap update( + ConfigMap actual, ConfigMap target, WebPage primary, Context context) { + var cm = super.update(actual, target, primary, context); + var ns = actual.getMetadata().getNamespace(); + log.info("Restarting pods because HTML has changed in {}", ns); + kubernetesClient + .pods() + .inNamespace(ns) + .withLabel("app", deploymentName(primary)) + .delete(); + return cm; + } + }; + configMapDR.setAssociatedSecondaryResourceIdentifier( + primary -> new ResourceID(configMapName(primary), primary.getMetadata().getNamespace())); + + this.deploymentDR = + new StandaloneKubernetesDependentResource<>( + client, + Deployment.class, + (webPage, context) -> { + var deploymentName = deploymentName(webPage); + Deployment deployment = loadYaml(Deployment.class, "deployment.yaml"); + deployment.getMetadata().setName(deploymentName); + deployment.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); + deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName); + + deployment + .getSpec() + .getTemplate() + .getMetadata() + .getLabels() + .put("app", deploymentName); + deployment + .getSpec() + .getTemplate() + .getSpec() + .getVolumes() + .get(0) + .setConfigMap( + new ConfigMapVolumeSourceBuilder().withName(configMapName(webPage)).build()); + return deployment; + }) { + @Override + protected boolean match(Deployment actual, Deployment target, Context context) { + // todo comparator + return true; + } + }; + + this.serviceDR = + new StandaloneKubernetesDependentResource<>( + client, + Service.class, + (webPage, context) -> { + Service service = loadYaml(Service.class, "service.yaml"); + service.getMetadata().setName(serviceName(webPage)); + service.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); + Map labels = new HashMap<>(); + labels.put("app", deploymentName(webPage)); + service.getSpec().setSelector(labels); + return service; + }) { + + protected boolean match(Service actual, Service target, Context context) { + // todo comparator + return true; + } + }; } private static String configMapName(WebPage nginx) { @@ -175,11 +196,4 @@ private T loadYaml(Class clazz, String yaml) { throw new IllegalStateException("Cannot find yaml on classpath: " + yaml); } } - - @Override - public Optional updateErrorStatus(WebPage resource, RetryInfo retryInfo, - RuntimeException e) { - resource.getStatus().setErrorMessage("Error: " + e.getMessage()); - return Optional.of(resource); - } } From 3251067542650cf9c52eb636a0ebef28029644c9 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 10 Feb 2022 16:33:04 +0100 Subject: [PATCH 18/25] fix: comment to revisit informer setting --- .../java/io/javaoperatorsdk/operator/ReconcilerUtils.java | 2 +- .../api/reconciler/dependent/KubernetesDependentResource.java | 4 ---- .../dependent/KubernetesDependentResourceController.java | 1 + .../processing/event/source/EventSourceContextAware.java | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java index 5e583b7ca0..b46bf0d222 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java @@ -25,7 +25,7 @@ private ReconcilerUtils() {} public static boolean isFinalizerValid(String finalizer) { // todo: use fabric8 method when 5.12 is released - // return HasMetadata.validateFinalizer(finalizer); +// return HasMetadata.validateFinalizer(finalizer); final var validator = new HasMetadata() { @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index f971124e2e..52c5dedc9c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -18,7 +18,6 @@ import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; -// todo owned: owner reference setting public abstract class KubernetesDependentResource extends AbstractDependentResource { @@ -45,9 +44,6 @@ protected void postProcessDesired(R desired, P primary) { @Override protected boolean match(R actual, R target, Context context) { - // todo handle this more smart: deployment created is updated with defaults, won't be equal - // use the created to compare from that point? or just compare the non null values from target - // for deployment? return ReconcilerUtils.specsEqual(actual, target); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java index d46301bdff..1ef55d66f0 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java @@ -46,6 +46,7 @@ public KubernetesDependentResourceController(DependentResource delegate, @Override public Optional eventSource(EventSourceContext

context) { var informer = new InformerEventSource<>(configuration, context); + // todo have this implemented with nicer abstractions ((KubernetesDependentResource) delegate).setInformerEventSource(informer); return super.eventSource(context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java index 39847f0f87..95042d0c41 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java @@ -3,7 +3,6 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -// todo do we really need this public interface EventSourceContextAware

{ void initWith(EventSourceContext

context); } From a3fb40fa4d74d455b542023c64f6458a443dcab7 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 10 Feb 2022 16:37:32 +0100 Subject: [PATCH 19/25] fix: addressed issues from PR --- .../operator/ReconcilerUtils.java | 16 +--------------- .../api/config/ConfigurationService.java | 4 +--- .../operator/api/reconciler/Constants.java | 5 ----- .../operator/ReconcilerUtilsTest.java | 18 ------------------ 4 files changed, 2 insertions(+), 41 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java index b46bf0d222..6f4e19692b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java @@ -10,10 +10,6 @@ import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import com.fasterxml.jackson.core.JsonProcessingException; - -import static io.javaoperatorsdk.operator.api.reconciler.Constants.OBJECT_MAPPER; - @SuppressWarnings("rawtypes") public class ReconcilerUtils { @@ -25,7 +21,7 @@ private ReconcilerUtils() {} public static boolean isFinalizerValid(String finalizer) { // todo: use fabric8 method when 5.12 is released -// return HasMetadata.validateFinalizer(finalizer); + // return HasMetadata.validateFinalizer(finalizer); final var validator = new HasMetadata() { @Override @@ -109,16 +105,6 @@ public static boolean specsEqual(HasMetadata r1, HasMetadata r2) { return getSpec(r1).equals(getSpec(r2)); } - public static boolean specsSame(HasMetadata r1, HasMetadata r2) { - try { - var c1json = OBJECT_MAPPER.writeValueAsString(getSpec(r1)); - var c2json = OBJECT_MAPPER.writeValueAsString(getSpec(r2)); - return OBJECT_MAPPER.readTree(c1json).equals(OBJECT_MAPPER.readTree(c2json)); - } catch (JsonProcessingException e) { - throw new IllegalStateException(e); - } - } - // will be replaced with: https://github.com/fabric8io/kubernetes-client/issues/3816 public static Object getSpec(HasMetadata resource) { try { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java index ba4ea1cde1..2e4679efd3 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java @@ -13,13 +13,11 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import static io.javaoperatorsdk.operator.api.reconciler.Constants.OBJECT_MAPPER; - /** An interface from which to retrieve configuration information. */ public interface ConfigurationService { Cloner DEFAULT_CLONER = new Cloner() { - + private final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Override public HasMetadata clone(HasMetadata object) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java index 56dfdae3ea..85b3a00807 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java @@ -1,11 +1,6 @@ package io.javaoperatorsdk.operator.api.reconciler; -import com.fasterxml.jackson.databind.ObjectMapper; - public final class Constants { - // Shared object mapper across app - public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - public static final String EMPTY_STRING = ""; public static final String WATCH_CURRENT_NAMESPACE = "JOSDK_WATCH_CURRENT"; diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java index 46afa8dcfe..be82caa36b 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java @@ -45,24 +45,6 @@ void noFinalizerMarkerShouldWork() { assertTrue(isFinalizerValid(Constants.NO_FINALIZER)); } - - @Test - void comparesArbitrarySpecsOfObjects() { - var d1 = createTestDeployment(); - var d2 = createTestDeployment(); - - assertThat(ReconcilerUtils.specsSame(d1, d2)).isTrue(); - } - - @Test - void comparesArbitraryDifferentSpecsOfObjects() { - var d1 = createTestDeployment(); - var d2 = createTestDeployment(); - d2.getSpec().getTemplate().getSpec().setHostname("otherhost"); - - assertThat(ReconcilerUtils.specsSame(d1, d2)).isFalse(); - } - @Test void equalsSpecObject() { var d1 = createTestDeployment(); From 7843bbce4912c4ce7aa354e45662d995bb4d58d4 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 10 Feb 2022 16:39:09 +0100 Subject: [PATCH 20/25] fix: comments from PR --- .../operator/sample/MySQLSchemaReconciler.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java index 62ebfad921..63c37ac3d7 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java @@ -32,14 +32,14 @@ public class MySQLSchemaReconciler implements Reconciler, ErrorStatusHandler, ContextInitializer, EventSourceContextInjector { - public static final String SECRET_FORMAT = "%s-secret"; - public static final String USERNAME_FORMAT = "%s-user"; - - public static final String MYSQL_SECRET_NAME = "mysql.secret.name"; - public static final String MYSQL_SECRET_USERNAME = "mysql.secret.user.name"; - public static final String MYSQL_SECRET_PASSWORD = "mysql.secret.user.password"; - public static final String MYSQL_DB_CONFIG = "mysql.db.config"; - protected static final String BUILT_SCHEMA = "built schema"; + static final String SECRET_FORMAT = "%s-secret"; + static final String USERNAME_FORMAT = "%s-user"; + + static final String MYSQL_SECRET_NAME = "mysql.secret.name"; + static final String MYSQL_SECRET_USERNAME = "mysql.secret.user.name"; + static final String MYSQL_SECRET_PASSWORD = "mysql.secret.user.password"; + static final String MYSQL_DB_CONFIG = "mysql.db.config"; + static final String BUILT_SCHEMA = "built schema"; static final Logger log = LoggerFactory.getLogger(MySQLSchemaReconciler.class); private final MySQLDbConfig mysqlDbConfig; From d8513212a1371e52d8e4425059a107362f94d13c Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Thu, 10 Feb 2022 18:25:02 +0100 Subject: [PATCH 21/25] refactor: remove unneeded code --- .../dependent/StandaloneDependentResourceIT.java | 2 -- .../InformerEventSourceTestCustomReconciler.java | 14 -------------- 2 files changed, 16 deletions(-) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java index 39cf78d155..20c0f20b80 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/StandaloneDependentResourceIT.java @@ -38,8 +38,6 @@ void dependentResourceManagesDeployment() { .atMost(Duration.ofSeconds(50)) .until( () -> { - StandaloneDependentTestReconciler reconciler = - (StandaloneDependentTestReconciler) operator.getReconcilers().get(0); var deployment = operator .getKubernetesClient() diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java index f1142218c7..d61aa7f0f2 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java @@ -8,10 +8,8 @@ import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; @@ -25,7 +23,6 @@ @ControllerConfiguration(finalizerName = NO_FINALIZER) public class InformerEventSourceTestCustomReconciler implements Reconciler, - KubernetesClientAware, EventSourceInitializer { private static final Logger LOGGER = @@ -35,7 +32,6 @@ public class InformerEventSourceTestCustomReconciler public static final String TARGET_CONFIG_MAP_KEY = "targetStatus"; public static final String MISSING_CONFIG_MAP = "Missing Config Map"; - private KubernetesClient kubernetesClient; private final AtomicInteger numberOfExecutions = new AtomicInteger(0); @Override @@ -73,14 +69,4 @@ public UpdateControl reconcile( public int getNumberOfExecutions() { return numberOfExecutions.get(); } - - @Override - public KubernetesClient getKubernetesClient() { - return null; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.kubernetesClient = kubernetesClient; - } } From 816757c01b3a5d906b2376c788c38e79ef4fb199 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Thu, 10 Feb 2022 18:39:12 +0100 Subject: [PATCH 22/25] refactor: minor --- .../dependent/StandaloneKubernetesDependentResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java index 8359f163dc..896795e8f2 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java @@ -16,7 +16,7 @@ public class StandaloneKubernetesDependentResource desiredSupplier; private final Class resourceType; private AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier = - (r) -> ResourceID.fromResource(r); + ResourceID::fromResource; private PrimaryResourcesRetriever primaryResourcesRetriever = Mappers.fromOwnerReference(); public StandaloneKubernetesDependentResource( From 5e25afabf5b9a9a95d903a49ccce6452495e3c5f Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Thu, 10 Feb 2022 20:36:46 +0100 Subject: [PATCH 23/25] refactor: better type safety, avoid duplicating configuration --- .../KubernetesDependentResource.java | 6 +++- .../DependentResourceController.java | 22 ++++++++------ .../dependent/DependentResourceManager.java | 11 +++++-- ...KubernetesDependentResourceController.java | 29 +++++++++---------- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index 52c5dedc9c..09aeccc61a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -47,6 +47,7 @@ protected boolean match(R actual, R target, Context context) { return ReconcilerUtils.specsEqual(actual, target); } + @SuppressWarnings("unchecked") @Override protected R create(R target, P primary, Context context) { log.debug("Creating target resource with type: " + @@ -57,6 +58,7 @@ protected R create(R target, P primary, Context context) { .create(target); } + @SuppressWarnings("unchecked") @Override protected R update(R actual, R target, P primary, Context context) { log.debug("Updating target resource with type: {}, with id: {}", target.getClass(), @@ -67,6 +69,7 @@ protected R update(R actual, R target, P primary, Context context) { .replace(target); } + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public Optional eventSource(EventSourceContext

context) { if (informerEventSource != null) { @@ -77,6 +80,7 @@ public Optional eventSource(EventSourceContext

context) { return Optional.of(informerEventSource); } + @SuppressWarnings("unchecked") private InformerConfiguration initInformerConfiguration(EventSourceContext

context) { PrimaryResourcesRetriever associatedPrimaries = (this instanceof PrimaryResourcesRetriever) ? (PrimaryResourcesRetriever) this @@ -94,7 +98,7 @@ private InformerConfiguration initInformerConfiguration(EventSourceContext } protected AssociatedSecondaryResourceIdentifier

getDefaultAssociatedSecondaryResourceIdentifier() { - return (r) -> ResourceID.fromResource(r); + return ResourceID::fromResource; } protected PrimaryResourcesRetriever getDefaultPrimaryResourcesRetriever() { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java index b694b2296c..e49a55a73a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java @@ -2,9 +2,6 @@ import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -14,17 +11,20 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; @Ignore -public class DependentResourceController> +public class DependentResourceController, D extends DependentResource> implements DependentResource { - private static final Logger log = LoggerFactory.getLogger(DependentResourceController.class); - - protected final DependentResource delegate; + private final D delegate; private final C configuration; - public DependentResourceController(DependentResource delegate, C configuration) { + public DependentResourceController(D delegate, C configuration) { this.delegate = delegate; - this.configuration = configuration; + this.configuration = initConfiguration(delegate, configuration); + } + + protected C initConfiguration(D delegate, C configuration) { + // default implementation just returns the specified one + return configuration; } @Override @@ -53,6 +53,10 @@ public C getConfiguration() { return configuration; } + protected D delegate() { + return delegate; + } + @Override public void reconcile(P resource, Context context) { delegate.reconcile(resource, context); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java index 9a94fed2f2..ac791526fc 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java @@ -92,10 +92,15 @@ private DependentResourceController from(DependentResourceConfiguration config, .newInstance(); if (config instanceof KubernetesDependentResourceConfiguration) { if (dependentResource instanceof KubernetesDependentResource) { - ((KubernetesDependentResource) dependentResource).setClient(client); + final var kubeDependentResource = (KubernetesDependentResource) dependentResource; + kubeDependentResource.setClient(client); + return new KubernetesDependentResourceController(kubeDependentResource, + (KubernetesDependentResourceConfiguration) config); + } else { + throw new IllegalArgumentException("A " + + KubernetesDependentResourceConfiguration.class.getCanonicalName() + + " must be associated to a " + KubernetesDependentResource.class.getCanonicalName()); } - return new KubernetesDependentResourceController(dependentResource, - (KubernetesDependentResourceConfiguration) config); } else { return new DependentResourceController(dependentResource, config); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java index 1ef55d66f0..733460ef31 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java @@ -7,7 +7,6 @@ import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.Ignore; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -16,14 +15,19 @@ @Ignore public class KubernetesDependentResourceController - extends DependentResourceController> { + extends + DependentResourceController, KubernetesDependentResource> { - private final KubernetesDependentResourceConfiguration configuration; + public KubernetesDependentResourceController(KubernetesDependentResource delegate, + KubernetesDependentResourceConfiguration configuration) { + super(delegate, configuration); + } @SuppressWarnings("unchecked") - public KubernetesDependentResourceController(DependentResource delegate, + @Override + protected KubernetesDependentResourceConfiguration initConfiguration( + KubernetesDependentResource delegate, KubernetesDependentResourceConfiguration configuration) { - super(delegate, configuration); // todo: check if we can validate that types actually match properly final var associatedPrimaries = (delegate instanceof PrimaryResourcesRetriever) @@ -38,22 +42,15 @@ public KubernetesDependentResourceController(DependentResource delegate, .withPrimaryResourcesRetriever(associatedPrimaries) .withAssociatedSecondaryResourceIdentifier(associatedSecondary) .build(); - this.configuration = - KubernetesDependentResourceConfiguration.from(augmented, configuration.isOwned(), - configuration.getDependentResourceClass()); + return KubernetesDependentResourceConfiguration.from(augmented, configuration.isOwned(), + configuration.getDependentResourceClass()); } @Override public Optional eventSource(EventSourceContext

context) { - var informer = new InformerEventSource<>(configuration, context); + var informer = new InformerEventSource<>(getConfiguration(), context); // todo have this implemented with nicer abstractions - ((KubernetesDependentResource) delegate).setInformerEventSource(informer); + delegate().setInformerEventSource(informer); return super.eventSource(context); } - - @Override - public Optional getResource(P primaryResource) { - return delegate.getResource(primaryResource); - } - } From da62a1257c69a53c50dd34d171000f6ecb822467 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 11 Feb 2022 08:24:22 +0100 Subject: [PATCH 24/25] fix: null check --- .../dependent/StandaloneKubernetesDependentResource.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java index 8359f163dc..8eade391fd 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java @@ -2,7 +2,6 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; @@ -33,12 +32,7 @@ public StandaloneKubernetesDependentResource( @Override protected R desired(P primary, Context context) { - if (desiredSupplier != null) { - return desiredSupplier.getDesired(primary, context); - } else { - throw new OperatorException( - "No DesiredSupplier provided. Either provide one or override this method"); - } + return desiredSupplier.getDesired(primary, context); } public Class resourceType() { From 7840238d2068dbcc810c83522951f5e1a1cfb64f Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 11 Feb 2022 10:00:13 +0100 Subject: [PATCH 25/25] fix: naming --- .../reconciler/dependent/KubernetesDependentResource.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index 09aeccc61a..e8a4a6779e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -36,7 +36,7 @@ public KubernetesDependentResource(KubernetesClient client) { this.client = client; } - protected void postProcessDesired(R desired, P primary) { + protected void beforeCreateOrUpdate(R desired, P primary) { if (owned) { desired.addOwnerReference(primary); } @@ -52,7 +52,7 @@ protected boolean match(R actual, R target, Context context) { protected R create(R target, P primary, Context context) { log.debug("Creating target resource with type: " + "{}, with id: {}", target.getClass(), ResourceID.fromResource(target)); - postProcessDesired(target, primary); + beforeCreateOrUpdate(target, primary); Class targetClass = (Class) target.getClass(); return client.resources(targetClass).inNamespace(target.getMetadata().getNamespace()) .create(target); @@ -63,7 +63,7 @@ protected R create(R target, P primary, Context context) { protected R update(R actual, R target, P primary, Context context) { log.debug("Updating target resource with type: {}, with id: {}", target.getClass(), ResourceID.fromResource(target)); - postProcessDesired(target, primary); + beforeCreateOrUpdate(target, primary); Class targetClass = (Class) target.getClass(); return client.resources(targetClass).inNamespace(target.getMetadata().getNamespace()) .replace(target);