diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/KubernetesClientAware.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/KubernetesClientAware.java
index 0e787753a5..2a28813c35 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/KubernetesClientAware.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/KubernetesClientAware.java
@@ -4,4 +4,6 @@
public interface KubernetesClientAware {
void setKubernetesClient(KubernetesClient kubernetesClient);
+
+ KubernetesClient getKubernetesClient();
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java
index 233deb020d..32606a5ebd 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java
@@ -156,6 +156,11 @@ public void setKubernetesClient(KubernetesClient kubernetesClient) {
this.client = kubernetesClient;
}
+ @Override
+ public KubernetesClient getKubernetesClient() {
+ return client;
+ }
+
@Override
protected R desired(P primary, Context
context) {
return super.desired(primary, context);
diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml
index 93e32953c3..f91cd7ee8a 100644
--- a/sample-operators/webpage/pom.xml
+++ b/sample-operators/webpage/pom.xml
@@ -10,7 +10,7 @@
2.2.0-SNAPSHOT
- webpage
+ sample-webpage-operator
Operator SDK - Samples - WebPage
Provisions an nginx Webserver based on a CRD with give html
jar
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java
new file mode 100644
index 0000000000..8cacd49765
--- /dev/null
+++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java
@@ -0,0 +1,65 @@
+package io.javaoperatorsdk.operator.sample;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUKubernetesDependentResource;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper;
+
+import static io.javaoperatorsdk.operator.sample.Utils.configMapName;
+import static io.javaoperatorsdk.operator.sample.Utils.deploymentName;
+
+// this annotation only activates when using managed dependents and is not otherwise needed
+@KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR)
+class ConfigMapDependentResource extends CRUKubernetesDependentResource
+ implements PrimaryToSecondaryMapper {
+
+ private static final Logger log = LoggerFactory.getLogger(ConfigMapDependentResource.class);
+
+ public ConfigMapDependentResource() {
+ super(ConfigMap.class);
+ }
+
+ @Override
+ protected ConfigMap desired(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
+ public ConfigMap update(ConfigMap actual, ConfigMap target, WebPage primary,
+ Context context) {
+ var res = super.update(actual, target, primary, context);
+ var ns = actual.getMetadata().getNamespace();
+ log.info("Restarting pods because HTML has changed in {}",
+ ns);
+ getKubernetesClient()
+ .pods()
+ .inNamespace(ns)
+ .withLabel("app", deploymentName(primary))
+ .delete();
+ return res;
+ }
+
+ @Override
+ public ResourceID associatedSecondaryID(WebPage primary) {
+ return new ResourceID(configMapName(primary), primary.getMetadata().getNamespace());
+ }
+}
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java
new file mode 100644
index 0000000000..0fd907f245
--- /dev/null
+++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java
@@ -0,0 +1,45 @@
+package io.javaoperatorsdk.operator.sample;
+
+import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
+
+import static io.javaoperatorsdk.operator.ReconcilerUtils.loadYaml;
+import static io.javaoperatorsdk.operator.sample.Utils.configMapName;
+import static io.javaoperatorsdk.operator.sample.Utils.deploymentName;
+
+// this annotation only activates when using managed dependents and is not otherwise needed
+@KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR)
+class DeploymentDependentResource extends CRUDKubernetesDependentResource {
+
+ public DeploymentDependentResource() {
+ super(Deployment.class);
+ }
+
+ @Override
+ protected Deployment desired(WebPage webPage, Context context) {
+ var deploymentName = deploymentName(webPage);
+ Deployment deployment = loadYaml(Deployment.class, getClass(), "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;
+ }
+}
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ErrorSimulationException.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ErrorSimulationException.java
index e2d3f3c1dd..94efc05baa 100644
--- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ErrorSimulationException.java
+++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ErrorSimulationException.java
@@ -1,6 +1,6 @@
package io.javaoperatorsdk.operator.sample;
-public class ErrorSimulationException extends RuntimeException {
+public class ErrorSimulationException extends Exception {
public ErrorSimulationException(String message) {
super(message);
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java
new file mode 100644
index 0000000000..cb06ab594b
--- /dev/null
+++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java
@@ -0,0 +1,33 @@
+package io.javaoperatorsdk.operator.sample;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import io.fabric8.kubernetes.api.model.Service;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
+
+import static io.javaoperatorsdk.operator.ReconcilerUtils.loadYaml;
+import static io.javaoperatorsdk.operator.sample.Utils.deploymentName;
+import static io.javaoperatorsdk.operator.sample.Utils.serviceName;
+
+// this annotation only activates when using managed dependents and is not otherwise needed
+@KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR)
+class ServiceDependentResource extends CRUDKubernetesDependentResource {
+
+ public ServiceDependentResource() {
+ super(Service.class);
+ }
+
+ @Override
+ protected Service desired(WebPage webPage, Context context) {
+ Service service = loadYaml(Service.class, getClass(), "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;
+ }
+}
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java
new file mode 100644
index 0000000000..f08c78f5db
--- /dev/null
+++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java
@@ -0,0 +1,40 @@
+package io.javaoperatorsdk.operator.sample;
+
+import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl;
+
+public class Utils {
+
+ private Utils() {}
+
+ static WebPageStatus createStatus(String configMapName) {
+ WebPageStatus status = new WebPageStatus();
+ status.setHtmlConfigMap(configMapName);
+ status.setAreWeGood(true);
+ status.setErrorMessage(null);
+ return status;
+ }
+
+ static String configMapName(WebPage nginx) {
+ return nginx.getMetadata().getName() + "-html";
+ }
+
+ static String deploymentName(WebPage nginx) {
+ return nginx.getMetadata().getName();
+ }
+
+ static String serviceName(WebPage webPage) {
+ return webPage.getMetadata().getName();
+ }
+
+ static ErrorStatusUpdateControl handleError(WebPage resource, Exception e) {
+ resource.getStatus().setErrorMessage("Error: " + e.getMessage());
+ return ErrorStatusUpdateControl.updateStatus(resource);
+ }
+
+ static void simulateErrorIfRequested(WebPage webPage) throws ErrorSimulationException {
+ if (webPage.getSpec().getHtml().contains("error")) {
+ // special case just to showcase error if doing a demo
+ throw new ErrorSimulationException("Simulating error");
+ }
+ }
+}
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageManagedDependentsReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageManagedDependentsReconciler.java
new file mode 100644
index 0000000000..f257893f8c
--- /dev/null
+++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageManagedDependentsReconciler.java
@@ -0,0 +1,48 @@
+package io.javaoperatorsdk.operator.sample;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
+import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler;
+import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl;
+import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
+import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
+
+import static io.javaoperatorsdk.operator.sample.Utils.createStatus;
+import static io.javaoperatorsdk.operator.sample.Utils.handleError;
+import static io.javaoperatorsdk.operator.sample.Utils.simulateErrorIfRequested;
+import static io.javaoperatorsdk.operator.sample.WebPageManagedDependentsReconciler.SELECTOR;
+
+/**
+ * Shows how to implement a reconciler with managed dependent resources.
+ */
+@ControllerConfiguration(
+ labelSelector = SELECTOR,
+ dependents = {
+ @Dependent(type = ConfigMapDependentResource.class),
+ @Dependent(type = DeploymentDependentResource.class),
+ @Dependent(type = ServiceDependentResource.class)
+ })
+public class WebPageManagedDependentsReconciler
+ implements Reconciler, ErrorStatusHandler {
+
+ static final String SELECTOR = "managed";
+
+ @Override
+ public ErrorStatusUpdateControl updateErrorStatus(WebPage resource,
+ Context context, Exception e) {
+ return handleError(resource, e);
+ }
+
+ @Override
+ public UpdateControl reconcile(WebPage webPage, Context context)
+ throws Exception {
+ simulateErrorIfRequested(webPage);
+
+ final var name = context.getSecondaryResource(ConfigMap.class).orElseThrow()
+ .getMetadata().getName();
+ webPage.setStatus(createStatus(name));
+ return UpdateControl.updateStatus(webPage);
+ }
+}
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java
index 0277da8199..30958dbc84 100644
--- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java
+++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java
@@ -30,7 +30,7 @@ public static void main(String[] args) throws IOException {
if (WEBPAGE_RECONCILER_ENV_VALUE.equals(System.getenv(WEBPAGE_RECONCILER_ENV))) {
operator.register(new WebPageReconciler(client));
} else {
- operator.register(new WebPageReconcilerDependentResources(client));
+ operator.register(new WebPageStandaloneDependentsReconciler(client));
}
operator.installShutdownHook();
operator.start();
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 570f2ffb53..3d74dcb00b 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
@@ -8,16 +8,33 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import io.fabric8.kubernetes.api.model.*;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration;
-import io.javaoperatorsdk.operator.api.reconciler.*;
import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
+import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler;
+import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
+import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
+import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import static io.javaoperatorsdk.operator.sample.Utils.configMapName;
+import static io.javaoperatorsdk.operator.sample.Utils.createStatus;
+import static io.javaoperatorsdk.operator.sample.Utils.deploymentName;
+import static io.javaoperatorsdk.operator.sample.Utils.handleError;
+import static io.javaoperatorsdk.operator.sample.Utils.serviceName;
+import static io.javaoperatorsdk.operator.sample.Utils.simulateErrorIfRequested;
+
/** Shows how to implement reconciler using the low level api directly. */
@ControllerConfiguration(
labelSelector = WebPageReconciler.LOW_LEVEL_LABEL_KEY)
@@ -35,11 +52,9 @@ public WebPageReconciler(KubernetesClient kubernetesClient) {
this.kubernetesClient = kubernetesClient;
}
- InformerEventSource configMapEventSource;
-
@Override
public List prepareEventSources(EventSourceContext context) {
- configMapEventSource =
+ var configMapEventSource =
new InformerEventSource<>(InformerConfiguration.from(context, ConfigMap.class)
.withLabelSelector(LOW_LEVEL_LABEL_KEY)
.build(), context);
@@ -55,11 +70,11 @@ public List prepareEventSources(EventSourceContext context
}
@Override
- public UpdateControl reconcile(WebPage webPage, Context context) {
+ public UpdateControl reconcile(WebPage webPage, Context context)
+ throws Exception {
log.info("Reconciling web page: {}", webPage);
- if (webPage.getSpec().getHtml().contains("error")) {
- throw new ErrorSimulationException("Simulating error");
- }
+ simulateErrorIfRequested(webPage);
+
String ns = webPage.getMetadata().getNamespace();
String configMapName = configMapName(webPage);
String deploymentName = deploymentName(webPage);
@@ -107,14 +122,6 @@ public UpdateControl reconcile(WebPage webPage, Context contex
return UpdateControl.updateStatus(webPage);
}
- private WebPageStatus createStatus(String configMapName) {
- WebPageStatus status = new WebPageStatus();
- status.setHtmlConfigMap(configMapName);
- status.setAreWeGood(true);
- status.setErrorMessage(null);
- return status;
- }
-
private boolean match(Deployment desiredDeployment, Deployment deployment) {
if (deployment == null) {
return false;
@@ -196,22 +203,9 @@ public static Map lowLevelLabel() {
return labels;
}
- private static String configMapName(WebPage nginx) {
- return nginx.getMetadata().getName() + "-html";
- }
-
- private static String deploymentName(WebPage nginx) {
- return nginx.getMetadata().getName();
- }
-
- private static String serviceName(WebPage nginx) {
- return nginx.getMetadata().getName();
- }
-
@Override
public ErrorStatusUpdateControl updateErrorStatus(
WebPage resource, Context context, Exception e) {
- resource.getStatus().setErrorMessage("Error: " + e.getMessage());
- return ErrorStatusUpdateControl.updateStatus(resource);
+ return handleError(resource, e);
}
}
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java
deleted file mode 100644
index 7698c3a16d..0000000000
--- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package io.javaoperatorsdk.operator.sample;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
-import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder;
-import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
-import io.fabric8.kubernetes.api.model.Service;
-import io.fabric8.kubernetes.api.model.apps.Deployment;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.javaoperatorsdk.operator.api.reconciler.Context;
-import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
-import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler;
-import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl;
-import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
-import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
-import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
-import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
-import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
-import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUKubernetesDependentResource;
-import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource;
-import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfig;
-import io.javaoperatorsdk.operator.processing.event.ResourceID;
-import io.javaoperatorsdk.operator.processing.event.source.EventSource;
-import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper;
-
-import static io.javaoperatorsdk.operator.ReconcilerUtils.loadYaml;
-
-/**
- * Shows how to implement reconciler using standalone dependent resources.
- */
-@ControllerConfiguration(
- labelSelector = WebPageReconcilerDependentResources.DEPENDENT_RESOURCE_LABEL_SELECTOR)
-public class WebPageReconcilerDependentResources
- implements Reconciler, ErrorStatusHandler, EventSourceInitializer {
-
- public static final String DEPENDENT_RESOURCE_LABEL_SELECTOR = "!low-level";
- private static final Logger log =
- LoggerFactory.getLogger(WebPageReconcilerDependentResources.class);
- private final KubernetesClient kubernetesClient;
-
- private KubernetesDependentResource configMapDR;
- private KubernetesDependentResource deploymentDR;
- private KubernetesDependentResource serviceDR;
-
- public WebPageReconcilerDependentResources(KubernetesClient kubernetesClient) {
- this.kubernetesClient = kubernetesClient;
- createDependentResources(kubernetesClient);
- }
-
- @Override
- public List prepareEventSources(EventSourceContext context) {
- return List.of(
- configMapDR.initEventSource(context),
- deploymentDR.initEventSource(context),
- serviceDR.initEventSource(context));
- }
-
- @Override
- public UpdateControl reconcile(WebPage webPage, Context context) {
- if (webPage.getSpec().getHtml().contains("error")) {
- // special case just to showcase error if doing a demo
- throw new ErrorSimulationException("Simulating error");
- }
-
- configMapDR.reconcile(webPage, context);
- deploymentDR.reconcile(webPage, context);
- serviceDR.reconcile(webPage, context);
-
- webPage.setStatus(
- createStatus(configMapDR.getResource(webPage).orElseThrow().getMetadata().getName()));
- return UpdateControl.updateStatus(webPage);
- }
-
- private WebPageStatus createStatus(String configMapName) {
- WebPageStatus status = new WebPageStatus();
- status.setHtmlConfigMap(configMapName);
- status.setAreWeGood(true);
- status.setErrorMessage(null);
- return status;
- }
-
- @Override
- public ErrorStatusUpdateControl updateErrorStatus(
- WebPage resource, Context retryInfo, Exception e) {
- resource.getStatus().setErrorMessage("Error: " + e.getMessage());
- return ErrorStatusUpdateControl.updateStatus(resource);
- }
-
- private void createDependentResources(KubernetesClient client) {
- this.configMapDR = new ConfigMapDependentResource();
- this.configMapDR.setKubernetesClient(client);
- configMapDR.configureWith(new KubernetesDependentResourceConfig()
- .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR));
-
- this.deploymentDR =
- new CRUDKubernetesDependentResource<>(Deployment.class) {
-
- @Override
- protected Deployment desired(WebPage webPage, Context context) {
- var deploymentName = deploymentName(webPage);
- Deployment deployment = loadYaml(Deployment.class, getClass(), "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;
- }
- };
- deploymentDR.setKubernetesClient(client);
- deploymentDR.configureWith(new KubernetesDependentResourceConfig()
- .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR));
-
- this.serviceDR =
- new CRUDKubernetesDependentResource<>(Service.class) {
-
- @Override
- protected Service desired(WebPage webPage, Context context) {
- Service service = loadYaml(Service.class, getClass(), "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;
- }
- };
- serviceDR.setKubernetesClient(client);
- serviceDR.configureWith(new KubernetesDependentResourceConfig()
- .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR));
- }
-
- public static String configMapName(WebPage nginx) {
- return nginx.getMetadata().getName() + "-html";
- }
-
- public static String deploymentName(WebPage nginx) {
- return nginx.getMetadata().getName();
- }
-
- public static String serviceName(WebPage webPage) {
- return webPage.getMetadata().getName();
- }
-
- private class ConfigMapDependentResource
- extends CRUKubernetesDependentResource
- implements PrimaryToSecondaryMapper {
-
- public ConfigMapDependentResource() {
- super(ConfigMap.class);
- }
-
- @Override
- protected ConfigMap desired(WebPage webPage, Context context) {
- Map data = new HashMap<>();
- data.put("index.html", webPage.getSpec().getHtml());
- return new ConfigMapBuilder()
- .withMetadata(
- new ObjectMetaBuilder()
- .withName(WebPageReconcilerDependentResources.configMapName(webPage))
- .withNamespace(webPage.getMetadata().getNamespace())
- .build())
- .withData(data)
- .build();
- }
-
- @Override
- public ConfigMap update(ConfigMap actual, ConfigMap target, WebPage primary,
- Context context) {
- var res = 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 res;
- }
-
- @Override
- public ResourceID associatedSecondaryID(WebPage primary) {
- return new ResourceID(configMapName(primary), primary.getMetadata().getNamespace());
- }
- }
-}
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java
new file mode 100644
index 0000000000..180c6ade65
--- /dev/null
+++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java
@@ -0,0 +1,92 @@
+package io.javaoperatorsdk.operator.sample;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.Service;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
+import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler;
+import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
+import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
+import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfig;
+import io.javaoperatorsdk.operator.processing.event.source.EventSource;
+
+import static io.javaoperatorsdk.operator.sample.Utils.createStatus;
+import static io.javaoperatorsdk.operator.sample.Utils.handleError;
+import static io.javaoperatorsdk.operator.sample.Utils.simulateErrorIfRequested;
+
+/**
+ * Shows how to implement reconciler using standalone dependent resources.
+ */
+@ControllerConfiguration(
+ labelSelector = WebPageStandaloneDependentsReconciler.DEPENDENT_RESOURCE_LABEL_SELECTOR)
+public class WebPageStandaloneDependentsReconciler
+ implements Reconciler, ErrorStatusHandler, EventSourceInitializer {
+
+ public static final String DEPENDENT_RESOURCE_LABEL_SELECTOR = "!low-level";
+ private static final Logger log =
+ LoggerFactory.getLogger(WebPageStandaloneDependentsReconciler.class);
+
+ private KubernetesDependentResource configMapDR;
+ private KubernetesDependentResource deploymentDR;
+ private KubernetesDependentResource serviceDR;
+
+ public WebPageStandaloneDependentsReconciler(KubernetesClient kubernetesClient) {
+ createDependentResources(kubernetesClient);
+ }
+
+ @Override
+ public List prepareEventSources(EventSourceContext context) {
+ return List.of(
+ configMapDR.initEventSource(context),
+ deploymentDR.initEventSource(context),
+ serviceDR.initEventSource(context));
+ }
+
+ @Override
+ public UpdateControl reconcile(WebPage webPage, Context context)
+ throws Exception {
+ simulateErrorIfRequested(webPage);
+
+ configMapDR.reconcile(webPage, context);
+ deploymentDR.reconcile(webPage, context);
+ serviceDR.reconcile(webPage, context);
+
+ webPage.setStatus(
+ createStatus(configMapDR.getResource(webPage).orElseThrow().getMetadata().getName()));
+ return UpdateControl.updateStatus(webPage);
+ }
+
+ @Override
+ public ErrorStatusUpdateControl updateErrorStatus(
+ WebPage resource, Context retryInfo, Exception e) {
+ return handleError(resource, e);
+ }
+
+ private void createDependentResources(KubernetesClient client) {
+ this.configMapDR = new ConfigMapDependentResource();
+ this.configMapDR.setKubernetesClient(client);
+ configMapDR.configureWith(new KubernetesDependentResourceConfig()
+ .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR));
+
+ this.deploymentDR = new DeploymentDependentResource();
+ deploymentDR.setKubernetesClient(client);
+ deploymentDR.configureWith(new KubernetesDependentResourceConfig()
+ .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR));
+
+ this.serviceDR = new ServiceDependentResource();
+ serviceDR.setKubernetesClient(client);
+ serviceDR.configureWith(new KubernetesDependentResourceConfig()
+ .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR));
+ }
+}
diff --git a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java
index 092ad6f25a..65a3084989 100644
--- a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java
+++ b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java
@@ -20,7 +20,8 @@
import io.fabric8.kubernetes.client.LocalPortForward;
import io.javaoperatorsdk.operator.junit.AbstractOperatorExtension;
-import static io.javaoperatorsdk.operator.sample.WebPageReconcilerDependentResources.serviceName;
+import static io.javaoperatorsdk.operator.sample.Utils.deploymentName;
+import static io.javaoperatorsdk.operator.sample.Utils.serviceName;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
@@ -50,8 +51,7 @@ void testAddingWebPage() {
.until(
() -> {
var actual = operator().get(WebPage.class, TEST_PAGE);
- var deployment = operator().get(Deployment.class,
- WebPageReconcilerDependentResources.deploymentName(webPage));
+ var deployment = operator().get(Deployment.class, deploymentName(webPage));
return Boolean.TRUE.equals(actual.getStatus().getAreWeGood())
&& Objects.equals(deployment.getSpec().getReplicas(),
diff --git a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorDependentResourcesE2E.java b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorDependentResourcesE2E.java
index 3bfdd3f45b..df024b890a 100644
--- a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorDependentResourcesE2E.java
+++ b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorDependentResourcesE2E.java
@@ -18,7 +18,7 @@ public WebPageOperatorDependentResourcesE2E() throws FileNotFoundException {}
isLocal()
? OperatorExtension.builder()
.waitForNamespaceDeletion(false)
- .withReconciler(new WebPageReconcilerDependentResources(client))
+ .withReconciler(new WebPageStandaloneDependentsReconciler(client))
.build()
: E2EOperatorExtension.builder()
.waitForNamespaceDeletion(false)