reconcile(MyService primary, Context context) {
// primary is the custom resource
// context contains information about the reconciliation
// Manual observed generation handling:
// 1. Get the current observed generation from the primary resource
// 2. Update the observed generation after reconciliation
// 3. Use it to determine if reconciliation is needed
// Example: Check if observed generation needs update
if (primary.getStatus() == null || primary.getStatus().getObservedGeneration() != primary.getMetadata().getGeneration()) {
// Perform reconciliation logic
// ...
// Update observed generation in status
primary.getStatus().setObservedGeneration(primary.getMetadata().getGeneration());
return UpdateControl.updateStatus(primary);
}
return UpdateControl.noUpdate();
}
@Override
public void onDeletion(MyService primary, Context context) {
// Cleanup logic if needed
}
}
```
--------------------------------
### EventSourceInitializer Interface Example
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/migration/v2-migration.md
Demonstrates the EventSourceInitializer interface, which is responsible for preparing and returning a list of EventSource implementations for the controller to register.
```java
public interface EventSourceInitializer> {
/**
* Initializes and returns the event sources to be registered with the controller.
*
* @param context the context object containing information about the current reconciliation
* @return a list of EventSource implementations
*/
List prepareEventSources(C context);
}
```
--------------------------------
### Example User Data in JSON
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/blog/news/etcd-as-app-db.md
This JSON object represents a typical user structure. It demonstrates the format and fields that might be stored. Note that this example contains sensitive information and its size (approx. 0.5 KB) is relevant to ETCD's data size limitations.
```json
{
"username": "myname",
"enabled": true,
"email": "myname@test.com",
"firstName": "MyFirstName",
"lastName": "MyLastName",
"credentials": [
{
"type": "password",
"value": "test"
},
{
"type": "token",
"value": "oidc"
}
],
"realmRoles": [
"user",
"viewer",
"admin"
],
"clientRoles": {
"account": [
"view-profile",
"change-group",
"manage-account"
]
}
}
```
--------------------------------
### WebPageReconciler Example
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/glossary/_index.md
Illustrates a basic reconciler implementation without advanced features like Dependent Resources or Workflows. It serves as an example of the low-level API.
```java
package io.javaoperatorsdk.operator.sample;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
public class WebPageReconciler implements Reconciler {
@Override
public UpdateControl reconcile(WebPage webPage, Context context) {
// ... reconciliation logic ...
return UpdateControl.updateStatus(webPage);
}
}
```
--------------------------------
### WebPageManagedDependentsReconciler Example
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/glossary/_index.md
Demonstrates how to implement reconciliation logic using Dependent Resources and Workflows, which are higher-level abstractions provided by the Java Operator SDK.
```java
package io.javaoperatorsdk.operator.sample;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
public class WebPageManagedDependentsReconciler implements Reconciler {
@Override
public UpdateControl reconcile(WebPage webPage, Context context) {
// ... reconciliation logic using dependent resources and workflows ...
return UpdateControl.updateStatus(webPage);
}
}
```
--------------------------------
### Configure InformerEventSource with InformerConfiguration
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/migration/v3-migration.md
In v3, InformerEventSource constructor arguments are moved to InformerConfiguration. This example shows how to configure an InformerEventSource using the new configuration object.
```java
eventSourceInitializer.registerEventSource(new InformerEventSource(new WebPageCustomResourceController(), InformerConfiguration.from(new InformerConfiguration("webpage"))));
```
--------------------------------
### Event Class Example
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/migration/v2-migration.md
Demonstrates the simplified Event class, which event sources now produce when an event occurs. It encapsulates the resource and its associated ResourceID.
```java
public final class Event {
private final ResourceID resourceID;
private final Object event;
public Event(ResourceID resourceID, Object event) {
this.resourceID = resourceID;
this.event = event;
}
public ResourceID getResourceID() { return resourceID; }
public Object getEvent() { return event; }
}
```
--------------------------------
### External State Tracking with Bulk Dependent Resources
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/dependent-resource-and-workflows/dependent-resources.md
When combining bulk and external state tracking, a separate state-tracking resource is created for each bulk dependent resource. This example illustrates the concept, though no direct code is provided.
--------------------------------
### Configure KubernetesDependentResource with @Configured
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/operations/configuration.md
This example shows how to annotate a KubernetesDependentResource with @Configured to enable custom configuration via annotations. It specifies the annotation class, configuration class, and converter.
```java
@Configured(
by = KubernetesDependent.class,
with = KubernetesDependentResourceConfig.class,
converter = KubernetesDependentConverter.class)
public abstract class KubernetesDependentResource
extends AbstractEventSourceHolderDependentResource>
implements ConfiguredDependentResource> {
// code omitted
}
```
--------------------------------
### Reconciler Interface Example
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/migration/v2-migration.md
Illustrates the new Reconciler interface, which replaces ResourceController. It shows the renamed reconcile and cleanup methods and the preparation of event sources.
```java
public interface Reconciler> extends EventSourceInitializer
{
/**
* The primary reconciliation logic. This method is called when a change is detected in the primary resource or any of the secondary resources.
*
* @param primaryResource the primary resource to reconcile
* @param context the context object containing information about the current reconciliation
* @return the desired state of the primary resource
*/
ResourceState
reconcile(P primaryResource, C context);
/**
* Cleans up resources associated with the primary resource. This method is called when the primary resource is deleted.
*
* @param primaryResource the primary resource to clean up
* @param context the context object containing information about the current cleanup
*/
void cleanup(P primaryResource, C context);
/**
* Initializes and returns the event sources to be registered with the controller.
*
* @param context the context object containing information about the current reconciliation
* @return a list of EventSource implementations
*/
@Override
default List prepareEventSources(C context) {
return Collections.emptyList();
}
}
```
--------------------------------
### Reconcile Deployment Resource with Java Operator SDK
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/features.md
Implement a reconciler for standard Kubernetes Deployment resources using the Java Operator SDK. This example shows the basic structure for a `Reconciler` implementation.
```java
public class DeploymentReconciler
implements Reconciler {
@Override
public UpdateControl reconcile(
Deployment resource, Context context) {
// omitted code
}
}
```
--------------------------------
### Customizing Matching Logic with Matcher Interface
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/dependent-resource-and-workflows/dependent-resources.md
Implement the Matcher interface to customize how the SDK determines if the actual dependent resource state matches the desired state. This example shows how to include annotations and labels in the matching process.
```java
public class MyDependentResource extends KubernetesDependentResource
implements Matcher {
// your implementation
public Result match(MyDependent actualResource, MyPrimary primary,
Context context) {
return GenericKubernetesResourceMatcher.match(this, actualResource, primary, context, true);
}
}
```
--------------------------------
### Operator and Reconciler Configuration with Custom Provider
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/blog/releases/v5-3-release.md
Construct the Operator and register reconcilers using a custom ConfigLoader. This example demonstrates applying both general operator configurations and reconciler-specific controller configurations.
```java
var configLoader = new ConfigLoader(new SmallRyeConfigProvider(smallRyeConfig));
Operator operator = new Operator(configLoader.applyConfigs());
operator.register(new MyReconciler(), configLoader.applyControllerConfigs(MyReconciler.NAME));
```
--------------------------------
### Multiple Dependent Resources with Informer Name Example
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/blog/releases/v5-release.md
Specifies a unique name for the informer when using multiple dependent resources of the same type with activation conditions to avoid informer registration conflicts.
```java
public class ConfigMapDependentResource1
extends KubernetesDependentResource {
public ConfigMapDependentResource1() {
super(ConfigMap.class);
setInformerName("configmap-dependent-resource-1"); // Unique informer name
}
@Override
protected void configureWith(MyService primary, Context context) {
// Configuration logic specific to this dependent resource
}
@Override
protected ConfigMap desired(MyService primary, Context context) {
// Desired state logic
return new ConfigMapBuilder()
.withNewMetadata()
.withName(primary.getMetadata().getName() + "-configmap-1")
.endMetadata()
.withData(Collections.singletonMap("key1", "value1"))
.build();
}
@Override
public Optional get(MyService primary, Context context) {
// Get logic
return Optional.ofNullable(getReconciler())
.flatMap(r -> r.get(primary, context))
.map(p -> p.getSecondaryResource(ConfigMap.class, ResourceID.fromName(primary.getMetadata().getName() + "-configmap-1")))
.orElse(Optional.empty());
}
}
```
--------------------------------
### Compose Multiple Config Sources with AggregatePriorityListConfigProvider
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/operations/configuration.md
Use AggregatePriorityListConfigProvider to define an ordered list of configuration providers, where the first provider to return a value wins. This example prioritizes environment variables, then system properties, and finally a YAML file.
```java
var configLoader = new ConfigLoader(
new AggregatePriorityListConfigProvider(List.of(
new EnvVarConfigProvider(), // highest priority
PropertiesConfigProvider.systemProperties(),
new YamlConfigProvider(Path.of("config/operator.yaml")) // lowest priority
)));
```
--------------------------------
### Install Operator into Cluster
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/sample-operators/tomcat-operator/README.md
Deploy the Tomcat Operator to your Kubernetes cluster using its YAML definition. Ensure CRDs are installed first.
```bash
kubectl apply -f k8s/operator.yaml
```
--------------------------------
### Full Build with Tests
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/AGENTS.md
Executes a clean build of the project including all tests. Use this for a complete verification of the codebase.
```bash
./mvnw clean install
```
--------------------------------
### Apply Sample Custom Resource (Shell Command)
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/sample-operators/webpage/README.md
Command to create a Webserver Custom Resource instance in your Kubernetes cluster.
```shell
kubectl apply -f k8s/webpage.yaml
```
--------------------------------
### Apply Code Formatting
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/AGENTS.md
Automatically formats the project's code according to the established style guidelines using the Spotless Maven plugin.
```bash
./mvnw spotless:apply
```
--------------------------------
### Create MicrometerMetricsV2 Instance
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/operations/metrics.md
Instantiate `MicrometerMetricsV2` using a `MeterRegistry`. This is the recommended micrometer-based implementation for metrics reporting.
```java
MeterRegistry registry;
Metrics metrics = MicrometerMetricsV2.newBuilder(registry).build();
```
--------------------------------
### Initialize MicrometerMetricsV2
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/blog/releases/v5-3-release.md
Instantiate MicrometerMetricsV2 with a MeterRegistry. Attach the metrics to the Operator. This implementation is designed for low cardinality.
```java
MeterRegistry registry; // initialize your registry
Metrics metrics = MicrometerMetricsV2.newBuilder(registry).build();
Operator operator = new Operator(client, o -> o.withMetrics(metrics));
```
--------------------------------
### Build Docker Image with Jib (Shell Command)
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/sample-operators/webpage/README.md
Builds a Docker image for the sample operator using Maven Jib. The JAR is built locally and then copied into the Docker image.
```shell
mvn jib:dockerBuild
```
--------------------------------
### ControllerConfiguration Annotation Example
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/migration/v2-migration.md
Shows the usage of the @ControllerConfiguration annotation, which replaces the @Controller annotation for configuring reconciler behavior.
```java
@ControllerConfiguration(labelSelector = "app=my-app", finalizerName = "my-app.example.com/finalizer")
public class MyServiceReconciler implements Reconciler {
// ... reconciler implementation ...
}
```
--------------------------------
### Bootstrap Operator with Default Configuration
Source: https://context7.com/operator-framework/java-operator-sdk/llms.txt
Instantiate the Operator class with default settings to register reconcilers and start the operator runtime.
```java
import io.javaoperatorsdk.operator.Operator;
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceOverrider;
public class MyOperatorMain {
public static void main(String[] args) {
// Option 1: Simple operator with defaults
Operator operator = new Operator();
operator.register(new MyAppReconciler());
operator.start();
```
--------------------------------
### Build Docker Compose Container
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/README.md
Builds the Docker container for running the documentation site locally.
```bash
docker-compose build
```
--------------------------------
### Troubleshoot Module Compatibility Error
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/README.md
This console output indicates a potential issue with the Hugo version. Ensure Hugo v0.110.0 or higher is installed.
```console
Error: Error building site: failed to extract shortcode: template for shortcode "blocks/cover" not found
```
--------------------------------
### Create Legacy MicrometerMetrics Instance
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/operations/metrics.md
Use this to create an instance of the legacy MicrometerMetrics implementation that behaves as it historically has. Ensure your MeterRegistry implementation is initialized.
```java
MeterRegistry registry; // initialize your registry implementation
Metrics metrics = MicrometerMetrics.newMicrometerMetricsBuilder(registry).build();
```
--------------------------------
### Check License Headers
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/AGENTS.md
Ensures all source files include the required Apache 2.0 license headers.
```bash
./mvnw -N license:check
```
--------------------------------
### Run Unit Tests
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/AGENTS.md
Executes all unit tests within the project. This is a quick way to verify individual components.
```bash
./mvnw test
```
--------------------------------
### Migrating Condition API Usage
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/migration/v4-3-migration.md
Example of how to access the secondary resource from the dependent resource in the new Condition API. This is used to migrate from the former API.
```java
dependentResource.getSecondaryResource(primary,context)
```
--------------------------------
### Load Operator Configuration with Default ConfigLoader
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/operations/configuration.md
This snippet demonstrates initializing an Operator using the default ConfigLoader, which automatically bridges environment variables and system properties to the operator's configuration. Environment variables take precedence over system properties.
```java
// uses env vars + system properties out of the box
Operator operator = new Operator(ConfigLoader.getDefault().applyConfigs());
```
--------------------------------
### Run Docker Compose Container
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/README.md
Runs the Docker container for the documentation site. Access the site at http://localhost:1313.
```bash
docker-compose up
```
--------------------------------
### ResourceID Class Example
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/migration/v2-migration.md
Illustrates the ResourceID class, used for addressing resources within event sources. It now uses a combination of name and namespace instead of UID.
```java
public final class ResourceID {
private final String name;
private final String namespace;
public ResourceID(String name, String namespace) {
this.name = name;
this.namespace = namespace;
}
public String getName() { return name; }
public String getNamespace() { return namespace; }
// equals and hashCode implementation based on name and namespace
}
```
--------------------------------
### Custom Target Secondary Resource ID Example
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/blog/releases/v5-release.md
Overrides the targetSecondaryResourceID method in KubernetesDependentResource to specify how to select a target resource when the desired state calculation is costly or unnecessary.
```java
public class MyConfigMapDependentResource
extends KubernetesDependentResource {
public MyConfigMapDependentResource() {
super(ConfigMap.class);
}
@Override
protected ResourceID targetSecondaryResourceID(MyService primary, Context context) {
// Example: Directly use a name from the primary resource
return ResourceID.fromName("my-configmap-" + primary.getMetadata().getName());
}
// ... other methods like createOrUpdate, get, delete ...
}
```
--------------------------------
### Migrate Event Source Initialization
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/migration/v3-migration.md
Use the utility method to easily migrate event source registration to a default name. This is useful when event sources are now registered with a name in v3.
```java
eventSourceInitializer.registerEventSource(new InformerEventSource(new WebPageCustomResourceController(), new InformerConfiguration("webpage")));
```
--------------------------------
### Reconcile with Server-Side Apply and Cache Read
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/reconciler.md
Use `context.resourceOperations().serverSideApply()` to update a resource and then immediately read the fresh resource from the cache using `context.getSecondaryResource()`. This pattern is useful when you need to ensure subsequent operations in the same reconciliation use the most up-to-date resource state.
```java
public UpdateControl reconcile(WebPage webPage, Context context) {
ConfigMap managedConfigMap = prepareConfigMap(webPage);
// filtering and caching update
context.resourceOperations().serverSideApply(managedConfigMap);
// fresh resource instantly available from our update in the cache
var upToDateResource = context.getSecondaryResource(ConfigMap.class);
makeStatusChanges(webPage);
// built in update methods by default use this feature
return UpdateControl.patchStatus(webPage);
}
```
--------------------------------
### Troubleshoot SCSS Processing Error
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/README.md
This console output suggests an issue with SCSS processing, likely due to an older Hugo version. Ensure the extended version of Hugo is installed.
```console
Error: TOCSS: failed to transform "scss/main.scss"
```
--------------------------------
### Configure CRD Generator Maven Plugin
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/blog/releases/v5-release.md
Configure the CRD generator Maven plugin by adding this stanza to your project's POM build configuration. This is required starting with v5.0.
```xml
io.fabric8
crd-generator-maven-plugin
${fabric8-client.version}
generate
```
--------------------------------
### Check Code Formatting
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/AGENTS.md
Verifies that the project's code adheres to the defined formatting standards using the Spotless Maven plugin.
```bash
./mvnw spotless:check
```
--------------------------------
### ConfigMap Dependent Resource Example
Source: https://context7.com/operator-framework/java-operator-sdk/llms.txt
Defines a dependent resource for managing a Kubernetes ConfigMap. Override the 'desired' method to specify the desired state of the ConfigMap, including its metadata and data.
```java
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.dependent.GarbageCollected;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
import java.util.Map;
@KubernetesDependent
public class ConfigMapDependentResource
extends CRUDKubernetesDependentResource
implements GarbageCollected {
public ConfigMapDependentResource() {
super(ConfigMap.class);
}
@Override
protected ConfigMap desired(MyApp primary, Context context) {
return new ConfigMapBuilder()
.withNewMetadata()
.withName(primary.getMetadata().getName() + "-config")
.withNamespace(primary.getMetadata().getNamespace())
.withLabels(Map.of(
"app", primary.getMetadata().getName(),
"managed-by", "myapp-operator"
))
.endMetadata()
.withData(Map.of(
"application.properties", buildConfig(primary),
"replicas", String.valueOf(primary.getSpec().getReplicas())
))
.build();
}
private String buildConfig(MyApp primary) {
return "app.name=" + primary.getSpec().getName() + "\n" +
"app.replicas=" + primary.getSpec().getReplicas();
}
}
```
--------------------------------
### Configure LinearRateLimiter with Annotation
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/docs/documentation/rate-limiting.md
Use the @RateLimited annotation on your Reconciler class to configure the default LinearRateLimiter. This example limits resources to a maximum of 2 reconciliations within a 3-second interval.
```java
@RateLimited(maxReconciliations = 2, within = 3, unit = TimeUnit.SECONDS)
@ControllerConfiguration
public class MyReconciler implements Reconciler {
}
```
--------------------------------
### Sequence Diagram for Read-Cache-After-Write Consistency
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/docs/content/en/blog/news/read-after-write-consistency.md
This diagram illustrates the flow of operations for achieving read-cache-after-write consistency, including updating a resource, caching it, and handling informer events.
```mermaid
sequenceDiagram
box rgba(50,108,229,0.1)
participant K8S as ⎈ Kubernetes API Server
end
box rgba(232,135,58,0.1)
participant R as Reconciler
end
box rgba(58,175,169,0.1)
participant I as Informer
participant IC as Informer Cache
participant TRC as Temporary Resource Cache
end
R->>K8S: 1. Update resource
K8S-->>R: Updated resource (with new resourceVersion)
R->>TRC: 2. Cache updated resource in TRC
I-)K8S: 3. Watch event (resource updated)
I->>TRC: On event: event resourceVersion ≥ TRC version?
alt Yes: event is up-to-date
I-->>TRC: Evict resource from TRC
else No: stale event
Note over TRC: TRC entry retained
end
R->>TRC: 4. Read resource from cache
alt Resource found in TRC
TRC-->>R: Return cached resource
else Not in TRC
R->>IC: Read from Informer Cache
IC-->>R: Return resource
end
```
--------------------------------
### Standalone Dependents Reconciler with Manual Workflow
Source: https://context7.com/operator-framework/java-operator-sdk/llms.txt
Implement a reconciler that manually controls the workflow of dependent resources. This example demonstrates building a workflow programmatically and invoking its reconcile and cleanup methods.
```java
import io.javaoperatorsdk.operator.api.reconciler.*;
import io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow;
import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowBuilder;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.apps.Deployment;
@ControllerConfiguration
public class StandaloneDependentsReconciler implements Reconciler, Cleaner {
private final ConfigMapDependentResource configMapDR;
private final DeploymentDependentResource deploymentDR;
private Workflow workflow;
public StandaloneDependentsReconciler() {
this.configMapDR = new ConfigMapDependentResource();
this.deploymentDR = new DeploymentDependentResource();
}
@Override
public java.util.List>
prepareEventSources(EventSourceContext context) {
// Build workflow programmatically
this.workflow = new WorkflowBuilder()
.addDependentResource(configMapDR)
.addDependentResource(deploymentDR)
.dependsOn(configMapDR)
.build();
// Return event sources from dependent resources
return java.util.List.of(
configMapDR.eventSource(context).orElseThrow(),
deploymentDR.eventSource(context).orElseThrow()
);
}
@Override
public UpdateControl reconcile(MyApp resource, Context context) {
// Manual workflow invocation
var result = workflow.reconcile(resource, context);
// Check for errors
if (result.erroredDependentsExist()) {
var errors = result.getErroredDependents();
errors.forEach((dr, exception) ->
System.err.println("Error in " + dr.name() + ": " + exception.getMessage())
);
resource.getStatus().setState("Error");
return UpdateControl.patchStatus(resource);
}
// Get secondary resources for status
var configMap = context.getSecondaryResource(ConfigMap.class);
var deployment = context.getSecondaryResource(Deployment.class);
if (configMap.isPresent() && deployment.isPresent()) {
int readyReplicas = deployment.get().getStatus() != null
? deployment.get().getStatus().getReadyReplicas() != null
? deployment.get().getStatus().getReadyReplicas()
: 0
: 0;
resource.getStatus().setState(
readyReplicas >= resource.getSpec().getReplicas() ? "Ready" : "Scaling"
);
} else {
resource.getStatus().setState("Provisioning");
}
return UpdateControl.patchStatus(resource);
}
@Override
public DeleteControl cleanup(MyApp resource, Context context) {
// Cleanup workflow handles deletion in reverse order
workflow.cleanup(resource, context);
return DeleteControl.defaultDelete();
}
}
```
--------------------------------
### Build Docker Image
Source: https://github.com/operator-framework/java-operator-sdk/blob/main/sample-operators/tomcat-operator/README.md
Build the operator's Docker image using Maven and Jib. This command produces an image that can be pushed to a registry.
```bash
mvn install jib:dockerBuild
```