From 519444d52e708e1b5a2e704b6da3eafc83af31ca Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 13 Jan 2023 09:53:23 +0100 Subject: [PATCH 1/3] docs: fix missing references and wording on dependent resources --- delme.json | 28 +++++++++++++++++++++++ docs/documentation/dependent-resources.md | 12 ++++++---- tarraform.hcl | 4 ++++ 3 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 delme.json create mode 100644 tarraform.hcl diff --git a/delme.json b/delme.json new file mode 100644 index 0000000000..d95c3bc0ab --- /dev/null +++ b/delme.json @@ -0,0 +1,28 @@ +{ + "version": 4, + "terraform_version": "1.2.3", + "serial": 1, + "lineage": "86545604-7463-4aa5-e9e8-a2a221de98d2", + "outputs": {}, + "resources": [ + { + "mode": "managed", + "type": "aws_instance", + "name": "example", + "provider": "provider[\"registry.terraform.io/...\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "ami": "ami-0fb653ca2d3203ac1", + "availability_zone": "us-east-2b", + "id": "i-0bc4bbe5b84387543", + "instance_state": "running", + "instance_type": "t2.micro", + "(...)": "(truncated)" + } + } + ] + } + ] +} diff --git a/docs/documentation/dependent-resources.md b/docs/documentation/dependent-resources.md index 28faa991b9..5b5301b544 100644 --- a/docs/documentation/dependent-resources.md +++ b/docs/documentation/dependent-resources.md @@ -76,18 +76,20 @@ also use the declarative support with your own implementations as we shall see l they support by implementing trait interfaces. This design has been selected to express the fact that not all secondary resources are completely under the control of the primary reconciler: some dependent resources are only ever created or updated for example and we needed a way to let +some dependent resources are only ever created or updated for example and we needed a way to let JOSDK know when that is the case. We therefore provide trait interfaces: `Creator`, `Updater` and `Deleter` to express that the `DependentResource` implementation will provide custom functionality to create, update and delete its associated secondary resources, respectively. If these traits are not implemented then parts of the logic described above is never triggered: if your implementation doesn't implement `Creator`, for example, `AbstractDependentResource` will -never try to create the associated secondary resource, even if it doesn't exist. It is +never try to create the associated secondary resource, even if it doesn't exist. It is event possible to not implement any of these traits and therefore create read-only dependent resources that will trigger your reconciler whenever a user interacts with them but that are never -modified by your reconciler itself. +modified by your reconciler itself - however notice that read only dependent resource rarely makes sense, +usually that means that it is enough to register an event source for the target resource. + -[`AbstractSimpleDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java) -and [`KubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java) +All subclasses of [`AbstractDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/5d7bb45057dcf6f0e539cccd71b567dd2f396de7/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java) sub-classes can also implement the [`Matcher`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/Matcher.java) interface to customize how the SDK decides whether or not the actual state of the dependent @@ -129,7 +131,7 @@ JOSDK takes care of everything else using default implementations that you can o need more precise control of what's going on. We also provide implementations that make it very easy to cache -(`AbstractCachingDependentResource`) or make it easy to poll for changes in external +(`AbstractExternalDependentResource`) or make it easy to poll for changes in external resources (`PollingDependentResource`, `PerResourcePollingDependentResource`). All the provided implementations can be found in the `io/javaoperatorsdk/operator/processing/dependent` package of the `operator-framework-core` module. diff --git a/tarraform.hcl b/tarraform.hcl new file mode 100644 index 0000000000..78b49da52e --- /dev/null +++ b/tarraform.hcl @@ -0,0 +1,4 @@ +resource "aws_instance" "example" { + ami = "ami-0fb653ca2d3203ac1" + instance_type = "t2.micro" +} From 07082807f26051dec29a0df64ec59e512154811b Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 18 Jan 2023 16:11:04 +0100 Subject: [PATCH 2/3] remove files added by mistake --- delme.json | 28 ---------------------------- tarraform.hcl | 4 ---- 2 files changed, 32 deletions(-) delete mode 100644 delme.json delete mode 100644 tarraform.hcl diff --git a/delme.json b/delme.json deleted file mode 100644 index d95c3bc0ab..0000000000 --- a/delme.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "version": 4, - "terraform_version": "1.2.3", - "serial": 1, - "lineage": "86545604-7463-4aa5-e9e8-a2a221de98d2", - "outputs": {}, - "resources": [ - { - "mode": "managed", - "type": "aws_instance", - "name": "example", - "provider": "provider[\"registry.terraform.io/...\"]", - "instances": [ - { - "schema_version": 1, - "attributes": { - "ami": "ami-0fb653ca2d3203ac1", - "availability_zone": "us-east-2b", - "id": "i-0bc4bbe5b84387543", - "instance_state": "running", - "instance_type": "t2.micro", - "(...)": "(truncated)" - } - } - ] - } - ] -} diff --git a/tarraform.hcl b/tarraform.hcl deleted file mode 100644 index 78b49da52e..0000000000 --- a/tarraform.hcl +++ /dev/null @@ -1,4 +0,0 @@ -resource "aws_instance" "example" { - ami = "ami-0fb653ca2d3203ac1" - instance_type = "t2.micro" -} From cb40c852fada01fed918180c103b675c3a04c8ac Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Wed, 18 Jan 2023 16:33:41 +0100 Subject: [PATCH 3/3] docs: improve wording, fix typos --- docs/documentation/dependent-resources.md | 320 ++++++++++++---------- 1 file changed, 173 insertions(+), 147 deletions(-) diff --git a/docs/documentation/dependent-resources.md b/docs/documentation/dependent-resources.md index 5b5301b544..85aebc66e4 100644 --- a/docs/documentation/dependent-resources.md +++ b/docs/documentation/dependent-resources.md @@ -76,21 +76,20 @@ also use the declarative support with your own implementations as we shall see l they support by implementing trait interfaces. This design has been selected to express the fact that not all secondary resources are completely under the control of the primary reconciler: some dependent resources are only ever created or updated for example and we needed a way to let -some dependent resources are only ever created or updated for example and we needed a way to let JOSDK know when that is the case. We therefore provide trait interfaces: `Creator`, `Updater` and `Deleter` to express that the `DependentResource` implementation will provide custom functionality to create, update and delete its associated secondary resources, respectively. If these traits are not implemented then parts of the logic described above is never triggered: if your implementation doesn't implement `Creator`, for example, `AbstractDependentResource` will -never try to create the associated secondary resource, even if it doesn't exist. It is event +never try to create the associated secondary resource, even if it doesn't exist. It is even possible to not implement any of these traits and therefore create read-only dependent resources that will trigger your reconciler whenever a user interacts with them but that are never -modified by your reconciler itself - however notice that read only dependent resource rarely makes sense, -usually that means that it is enough to register an event source for the target resource. - +modified by your reconciler itself - however note that read-only dependent resources rarely make +sense, as it is usually simpler to register an event source for the target resource. -All subclasses of [`AbstractDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/5d7bb45057dcf6f0e539cccd71b567dd2f396de7/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java) -sub-classes can also implement +All subclasses +of [`AbstractDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java) +can also implement the [`Matcher`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/Matcher.java) interface to customize how the SDK decides whether or not the actual state of the dependent matches the desired state. This makes it convenient to use these abstract base classes for your @@ -102,7 +101,7 @@ and [`GenericKubernetesResourceMatcher`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java) implementations, respectively. If you want to provide custom logic, you only need your `DependentResource` implementation to implement the `Matcher` interface as below, which shows -how to customize the default matching logic for Kubernetes resource to also consider annotations +how to customize the default matching logic for Kubernetes resources to also consider annotations and labels, which are ignored by default: ```java @@ -123,16 +122,16 @@ JOSDK also offers several other convenient implementations building on top of `AbstractDependentResource` that you can use as starting points for your own implementations. One such implementation is the `KubernetesDependentResource` class that makes it really easy to work -with Kubernetes-native resources. In this case, you usually only need to provide an -implementation for the `desired` method to tell JOSDK what the desired state of your secondary -resource should be based on the specified primary resource state. +with Kubernetes-native resources. In this case, you usually only need to provide an implementation +for the `desired` method to tell JOSDK what the desired state of your secondary resource should +be based on the specified primary resource state. JOSDK takes care of everything else using default implementations that you can override in case you need more precise control of what's going on. -We also provide implementations that make it very easy to cache -(`AbstractExternalDependentResource`) or make it easy to poll for changes in external -resources (`PollingDependentResource`, `PerResourcePollingDependentResource`). All the provided +We also provide implementations that make it easy to cache +(`AbstractExternalDependentResource`) or poll for changes in external resources +(`PollingDependentResource`, `PerResourcePollingDependentResource`). All the provided implementations can be found in the `io/javaoperatorsdk/operator/processing/dependent` package of the `operator-framework-core` module. @@ -200,26 +199,25 @@ instances are managed by JOSDK, an example of which can be seen below: ```java @ControllerConfiguration( - labelSelector = SELECTOR, - dependents = { - @Dependent(type = ConfigMapDependentResource.class), - @Dependent(type = DeploymentDependentResource.class), - @Dependent(type = ServiceDependentResource.class) - }) + labelSelector = SELECTOR, + dependents = { + @Dependent(type = ConfigMapDependentResource.class), + @Dependent(type = DeploymentDependentResource.class), + @Dependent(type = ServiceDependentResource.class) + }) public class WebPageManagedDependentsReconciler - implements Reconciler, ErrorStatusHandler { + implements Reconciler, ErrorStatusHandler { - // omitted code + // omitted code - @Override - public UpdateControl reconcile(WebPage webPage, Context context) - throws Exception { + @Override + public UpdateControl reconcile(WebPage webPage, Context context) { - final var name = context.getSecondaryResource(ConfigMap.class).orElseThrow() - .getMetadata().getName(); - webPage.setStatus(createStatus(name)); - return UpdateControl.patchStatus(webPage); - } + final var name = context.getSecondaryResource(ConfigMap.class).orElseThrow() + .getMetadata().getName(); + webPage.setStatus(createStatus(name)); + return UpdateControl.patchStatus(webPage); + } } ``` @@ -231,84 +229,83 @@ sample [here](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/s ## Standalone Dependent Resources It is also possible to wire dependent resources programmatically. In practice this means that the -developer is responsible to initializing and managing and calling `reconcile` method. However, -this gives possibility for developers to fully customize the process for reconciliation. Use -standalone dependent resources for cases when managed does not fit. +developer is responsible for initializing and managing the dependent resources as well as calling +their `reconcile` method. However, this makes it possible for developers to fully customize the +reconciliation process. Standalone dependent resources should be used in cases when the managed use +case does not fit. -Note that [Workflows](https://javaoperatorsdk.io/docs/workflows) support also standalone -mode using standalone resources. +Note that [Workflows](https://javaoperatorsdk.io/docs/workflows) also can be invoked from standalone +resources. -The sample is similar to one above it just performs additional checks, and conditionally creates -an `Ingress`: -(Note that now this condition creation is also possible with Workflows) +The following sample is similar to the one above, simply performing additional checks, and +conditionally creating an `Ingress`: ```java @ControllerConfiguration public class WebPageStandaloneDependentsReconciler - implements Reconciler, ErrorStatusHandler, - EventSourceInitializer { - - private KubernetesDependentResource configMapDR; - private KubernetesDependentResource deploymentDR; - private KubernetesDependentResource serviceDR; - private KubernetesDependentResource ingressDR; - - public WebPageStandaloneDependentsReconciler(KubernetesClient kubernetesClient) { - // 1. - createDependentResources(kubernetesClient); - } - - @Override - public List prepareEventSources(EventSourceContext context) { - // 2. - return List.of( - configMapDR.initEventSource(context), - deploymentDR.initEventSource(context), - serviceDR.initEventSource(context)); - } - - @Override - public UpdateControl reconcile(WebPage webPage, Context context) - throws Exception { - - // 3. - if (!isValidHtml(webPage.getHtml())) { - return UpdateControl.patchStatus(setInvalidHtmlErrorMessage(webPage)); - } - - // 4. - configMapDR.reconcile(webPage, context); - deploymentDR.reconcile(webPage, context); - serviceDR.reconcile(webPage, context); - - // 5. - if (Boolean.TRUE.equals(webPage.getSpec().getExposed())) { - ingressDR.reconcile(webPage, context); - } else { - ingressDR.delete(webPage, context); - } - - // 6. - webPage.setStatus( - createStatus(configMapDR.getResource(webPage).orElseThrow().getMetadata().getName())); - return UpdateControl.patchStatus(webPage); - } - - private void createDependentResources(KubernetesClient client) { - this.configMapDR = new ConfigMapDependentResource(); - this.deploymentDR = new DeploymentDependentResource(); - this.serviceDR = new ServiceDependentResource(); - this.ingressDR = new IngressDependentResource(); - - Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> { - dr.setKubernetesClient(client); - dr.configureWith(new KubernetesDependentResourceConfig() - .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR)); - }); - } - - // omitted code + implements Reconciler, ErrorStatusHandler, + EventSourceInitializer { + + private KubernetesDependentResource configMapDR; + private KubernetesDependentResource deploymentDR; + private KubernetesDependentResource serviceDR; + private KubernetesDependentResource ingressDR; + + public WebPageStandaloneDependentsReconciler(KubernetesClient kubernetesClient) { + // 1. + createDependentResources(kubernetesClient); + } + + @Override + public List prepareEventSources(EventSourceContext context) { + // 2. + return List.of( + configMapDR.initEventSource(context), + deploymentDR.initEventSource(context), + serviceDR.initEventSource(context)); + } + + @Override + public UpdateControl reconcile(WebPage webPage, Context context) { + + // 3. + if (!isValidHtml(webPage.getHtml())) { + return UpdateControl.patchStatus(setInvalidHtmlErrorMessage(webPage)); + } + + // 4. + configMapDR.reconcile(webPage, context); + deploymentDR.reconcile(webPage, context); + serviceDR.reconcile(webPage, context); + + // 5. + if (Boolean.TRUE.equals(webPage.getSpec().getExposed())) { + ingressDR.reconcile(webPage, context); + } else { + ingressDR.delete(webPage, context); + } + + // 6. + webPage.setStatus( + createStatus(configMapDR.getResource(webPage).orElseThrow().getMetadata().getName())); + return UpdateControl.patchStatus(webPage); + } + + private void createDependentResources(KubernetesClient client) { + this.configMapDR = new ConfigMapDependentResource(); + this.deploymentDR = new DeploymentDependentResource(); + this.serviceDR = new ServiceDependentResource(); + this.ingressDR = new IngressDependentResource(); + + Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> { + dr.setKubernetesClient(client); + dr.configureWith(new KubernetesDependentResourceConfig() + .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR)); + }); + } + + // omitted code } ``` @@ -331,6 +328,9 @@ See the full source code of sample [here](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java) . +Note also the Workflows feature makes it possible to also support this conditional creation use +case in managed dependent resources. + ## Telling JOSDK how to find which secondary resources are associated with a given primary resource [`KubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java) @@ -343,77 +343,103 @@ See sample in one of the integration tests [here](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java#L25-L25) . -## Multiple Dependent Resources of Same Type +## Multiple Dependent Resources of Same Type -In case there are multiple dependent resource of same type, the dependent resource implementation needs to know which -resource is it related to, since there will be multiple instances also in caches. -For that it should have a [resource discriminator](https://github.com/java-operator-sdk/java-operator-sdk/blob/f5ffcfb6f546d79b4bab04ea503c8bad9d6acce6/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceDiscriminator.java) -. Where resource discriminator uniquely identifies the target resource of a dependent resource. For managed -Kubernetes dependent resource the annotation can be used to set a discriminator: +When dealing with multiple dependent resources of same type, the dependent resource implementation +needs to know which specific resource should be targeted when reconciling a given dependent +resource, since there will be multiple instances of that type which could possibly be used, each +associated with the same primary resource. In order to do this, JOSDK relies on the +[resource discriminator](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceDiscriminator.java) +concept. Resource discriminators uniquely identify the target resource of a dependent resource. +In the managed Kubernetes dependent resources case, the discriminator can be declaratively set +using the `@KubernetesDependent` annotation: + +```java -``` @KubernetesDependent(resourceDiscriminator = ConfigMap1Discriminator.class) public class MultipleManagedDependentResourceConfigMap1 { //... } ``` -Dependent resources has the capability to provide event sources. In case there are multiple dependent of the same type -either the provided event sources should track different resources (in other words the tracked resources by different -event sources should be distinct) or should share a common dependent resource. +Dependent resources usually also provide event sources. When dealing with multiple dependents of +the same type, one needs to decide whether these dependent resources should track the same +resources and therefore share a common event source, or, to the contrary, track completely +separate resources, in which case using separate event sources is advised. + +Dependents can therefore reuse existing, named event sources by referring to their name. In the +declarative case, assuming a `configMapSource` `EventSource` has already been declared, this +would look as follows: -To use a dedicated event source defined in a `EventSourceInitializer` use its name to set it for a dependent resource -to be used: ``` - @Dependent(type = MultipleManagedDependentResourceConfigMap1.class, - useEventSourceWithName = CONFIG_MAP_EVENT_SOURCE), + @Dependent(type = MultipleManagedDependentResourceConfigMap1.class, + useEventSourceWithName = "configMapSource") ``` -A sample is provided as an integration test both for [managed](https://github.com/java-operator-sdk/java-operator-sdk/blob/a7a77b013ec296a0d29f66a2d7dae72197f6f056/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleManagedDependentSameTypeIT.java) -and for [standalone mode](https://github.com/java-operator-sdk/java-operator-sdk/blob/f5ffcfb6f546d79b4bab04ea503c8bad9d6acce6/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleDependentResourceIT.java) +A sample is provided as an integration test both +for [managed](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleManagedDependentSameTypeIT.java) +and +for [standalone](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleDependentResourceIT.java) +cases. ## Bulk Dependent Resources -There are cases when the number of certain resource type changes dynamically for example based on spec of -the custom resource. These cases are covered by bulk custom resources. To have a resource in "bulk mode" it should -extend the same base classes as other resources, thus `AbstractDependentResource` and it's subclasses and in addition -to that implement the [`BulkDependetResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/f5ffcfb6f546d79b4bab04ea503c8bad9d6acce6/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResource.java) +So far, all the cases we've considered were dealing with situations where the number of +dependent resources needed to reconcile the state expressed by the primary resource is known +when writing the code for the operator. There are, however, cases where the number of dependent +resources to be created depends on information found in the primary resource. + +These cases are covered by the "bulk" dependent resources feature. To create such dependent +resources, your implementation should extend `AbstractDependentResource` (at least indirectly) and +implement the +[`BulkDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResource.java) interface. -Various examples are provided as [integration tests](https://github.com/java-operator-sdk/java-operator-sdk/tree/f5ffcfb6f546d79b4bab04ea503c8bad9d6acce6/operator-framework/src/test/java/io/javaoperatorsdk/operator/bulkdependent) +Various examples are provided +as [integration tests](https://github.com/java-operator-sdk/java-operator-sdk/tree/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/bulkdependent) . -To see how to add conditions on a bulk dependent resource [see integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/ad8759856cc59380ea4b0973478daa1140ec93e7/operator-framework/src/test/java/io/javaoperatorsdk/operator/bulkdependent/BulkDependentWithConditionIT.java). - -## Dependent Resources with Explicit State - -For cases when an external (non-Kubernetes) resource generates an ID during creation and from that point -this resource is addressed using this ID special support is provided. A typical example would a GitHub Pull request, -when created, a new ID is generated for it, and from that time in the URL that ID is used to access the PR. -For these cases those IDs are usually stored in a ConfigMap, Secret or a dedicated CustomResource, and accessed -either during reconciliation or by the event source. - -To create a dependent resource that covers such case the [`AbstractExternalDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/f5ffcfb6f546d79b4bab04ea503c8bad9d6acce6/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java) -needs to be extended and the [`DependentResourceWithExplicitState`](https://github.com/java-operator-sdk/java-operator-sdk/blob/f5ffcfb6f546d79b4bab04ea503c8bad9d6acce6/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceWithExplicitState.java) -interface implemented. Note that most of the out-of-the-box dependent resources for external resources, like the -`PollingDependentResource` or the `PerResourcePollingDependentResource` already extends -`AbstractExternalDependentResource`. - -See [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/f5ffcfb6f546d79b4bab04ea503c8bad9d6acce6/operator-framework/src/test/java/io/javaoperatorsdk/operator/ExternalStateDependentIT.java#L8-L8) +To see how bulk dependent resources interact with workflow conditions, please refer to this +[integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/bulkdependent/BulkDependentWithConditionIT.java). + +## External State Tracking Dependent Resources + +It is sometimes necessary for a controller to track external (i.e. non-Kubernetes) state to +properly manage some dependent resources. For example, your controller might need to track the +state of a REST API resource, which, after being created, would be refer to by its identifier. +Such identifier would need to be tracked by your controller to properly retrieve the state of +the associated resource and/or assess if such a resource exists. While there are several ways to +support this use case, we recommend storing such information in a dedicated Kubernetes resources +(usually a `ConfigMap` or a `Secret`), so that it can be manipulated with common Kubernetes +mechanisms. + +This particular use case is supported by the +[`AbstractExternalDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java) +class that you can extend to suit your needs, as well as implement the +[`DependentResourceWithExplicitState`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceWithExplicitState.java) +interface. Note that most of the JOSDK-provided dependent resource implementations such as +`PollingDependentResource` or `PerResourcePollingDependentResource` already extends +`AbstractExternalDependentResource`, thus supporting external state tracking out of the box. + +See [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/ExternalStateDependentIT.java) as a sample. -For a better understanding it might be worth to study a [sample implementation](https://github.com/java-operator-sdk/java-operator-sdk/blob/f5ffcfb6f546d79b4bab04ea503c8bad9d6acce6/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/externalstate/ExternalStateReconciler.java) +For a better understanding it might be worth to study +a [sample implementation](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/externalstate/ExternalStateReconciler.java) without dependent resources. -See also [docs for managing](/docs/patterns-best-practices#managing-state) state in general. +Please also refer to the [docs](/docs/patterns-best-practices#managing-state) for managing state in +general. -## Combining Bulk and Explicit State Dependent Resources +## Combining Bulk and External State Tracking Dependent Resources -The bulk and the and explicit state dependent resource features can be combined. In that case for each external resource -that is created a separate resource with the state will be created too. For example if there are three external resources created -there will be three related config maps (assuming config maps are used), one for each external resource. +Both bulk and external state tracking features can be combined. In that +case, a separate, state-tracking resource will be created for each bulk dependent resource +created. For example, if three bulk dependent resources associated with external state are created, +three associated `ConfigMaps` (assuming `ConfigMaps` are used as a state-tracking resource) will +also be created, one per dependent resource. -See [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/f5ffcfb6f546d79b4bab04ea503c8bad9d6acce6/operator-framework/src/test/java/io/javaoperatorsdk/operator/ExternalStateBulkIT.java) +See [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/ExternalStateBulkIT.java) as a sample. ## Other Dependent Resource Features @@ -440,5 +466,5 @@ as a sample. practice in general) - so for example if there are two config map dependents, either there should be a shared event source between them, or a label selector on the event sources to select only the relevant events, see - in [related integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/cd8d7e94f9d3f5d9f28dddbbb10f692546c22c9c/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource1.java#L15-L15) + in [related integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource1.java) .