Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/hugo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ jobs:
with:
submodules: recursive
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Build test-index-processor and generate test documentation
run: |
./mvnw clean install -DskipTests -pl test-index-processor
./mvnw process-test-classes -DskipTests -pl operator-framework
- name: Setup Pages
id: pages
uses: actions/configure-pages@v5
Expand Down
68 changes: 68 additions & 0 deletions operator-framework/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@
<artifactId>kube-api-test-client-inject</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>test-index-processor</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<optional>true</optional>
</dependency>
</dependencies>

<build>
Expand All @@ -106,6 +113,23 @@
</compilerArgs>
</configuration>
</execution>
<!-- Enable annotation processing for test compilation to generate samples.md -->
<execution>
<id>default-testCompile</id>
<goals>
<goal>testCompile</goal>
</goals>
<phase>test-compile</phase>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>test-index-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
Expand Down Expand Up @@ -138,6 +162,50 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-samples-to-docs</id>
<goals>
<goal>copy-resources</goal>
</goals>
<phase>process-test-classes</phase>
<configuration>
<outputDirectory>${project.basedir}/../docs/content/en/docs/testindex</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/generated-test-sources/test-annotations</directory>
<includes>
<include>samples.md</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>rename-samples-to-index</id>
<goals>
<goal>run</goal>
</goals>
<phase>process-test-classes</phase>
<configuration>
<target>
<move failonerror="false" file="${project.basedir}/../docs/content/en/docs/testindex/samples.md" tofile="${project.basedir}/../docs/content/en/docs/testindex/_index.md"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.slf4j.LoggerFactory;

import io.fabric8.kubernetes.api.model.ConfigMap;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.baseapi.simple.TestCustomResource;
import io.javaoperatorsdk.operator.baseapi.simple.TestReconciler;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
Expand All @@ -18,6 +19,13 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Concurrent Reconciliation of Multiple Resources",
description =
"Demonstrates the operator's ability to handle concurrent reconciliation of multiple"
+ " resources. The test creates, updates, and deletes many resources simultaneously to"
+ " verify proper handling of concurrent operations, ensuring thread safety and correct"
+ " resource state management under load.")
class ConcurrencyIT {
public static final int NUMBER_OF_RESOURCES_CREATED = 50;
public static final int NUMBER_OF_RESOURCES_DELETED = 30;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@
import org.slf4j.LoggerFactory;

import io.fabric8.kubernetes.api.model.Service;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.dependent.standalonedependent.StandaloneDependentResourceIT;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Cleanup handler for built-in Kubernetes resources",
description =
"Demonstrates how to implement cleanup handlers (finalizers) for built-in Kubernetes"
+ " resources like Service and Pod. These resources don't use generation the same way"
+ " as custom resources, so this sample shows the proper approach to handle their"
+ " lifecycle and cleanup logic.")
class BuiltInResourceCleanerIT {

private static final Logger log = LoggerFactory.getLogger(BuiltInResourceCleanerIT.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,22 @@
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.RegisteredController;
import io.javaoperatorsdk.operator.api.reconciler.Constants;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Dynamically Changing Watched Namespaces",
description =
"Demonstrates how to dynamically change the set of namespaces that an operator watches at"
+ " runtime. This feature allows operators to add or remove namespaces from their watch"
+ " list, including switching between specific namespaces and watching all namespaces."
+ " The test verifies that resources in newly added namespaces are reconciled and"
+ " resources in removed namespaces are no longer watched.")
class ChangeNamespaceIT {

public static final String TEST_RESOURCE_NAME_1 = "test1";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Implementing Cleanup Logic with Cleaner Interface",
description =
"Demonstrates how to implement cleanup logic for custom resources using the Cleaner"
+ " interface. When a reconciler implements Cleaner, the framework automatically adds a"
+ " finalizer to resources and calls the cleanup method when the resource is deleted."
+ " This pattern is useful for cleaning up external resources or performing custom"
+ " deletion logic. The test verifies finalizer handling, cleanup execution, and the"
+ " ability to reschedule cleanup operations.")
class CleanerForReconcilerIT {

public static final String TEST_RESOURCE_NAME = "cleaner-for-reconciler-test1";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@

import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

import static io.javaoperatorsdk.operator.IntegrationTestConstants.GARBAGE_COLLECTION_TIMEOUT_SECONDS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Cluster-scoped resource reconciliation",
description =
"Demonstrates how to reconcile cluster-scoped custom resources (non-namespaced). This"
+ " test shows CRUD operations on cluster-scoped resources and verifies that"
+ " dependent resources are created, updated, and properly cleaned up when the"
+ " primary resource is deleted.")
class ClusterScopedResourceIT {

public static final String TEST_NAME = "test1";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@

import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

import static io.javaoperatorsdk.operator.baseapi.createupdateeventfilter.CreateUpdateEventFilterTestReconciler.CONFIG_MAP_TEST_DATA_KEY;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Event filtering for create and update operations",
description =
"Shows how to configure event filters on informer event sources to control which create and"
+ " update events trigger reconciliation. This is useful for preventing unnecessary"
+ " reconciliation loops when dependent resources are modified by the controller"
+ " itself.")
class CreateUpdateInformerEventSourceEventFilterIT {

@RegisterExtension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,21 @@
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.DeploymentSpec;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

import static io.javaoperatorsdk.operator.baseapi.deployment.DeploymentReconciler.STATUS_MESSAGE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Reconciling Non-Custom Kubernetes Resources with Status Updates",
description =
"Demonstrates how to reconcile standard Kubernetes resources (like Deployments) instead of"
+ " custom resources, and how to update their status subresource. This pattern is"
+ " useful when building operators that manage native Kubernetes resources rather than"
+ " custom resource definitions. The test verifies that the operator can watch,"
+ " reconcile, and update the status of a Deployment resource.")
class KubernetesResourceStatusUpdateIT {

@RegisterExtension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.processing.retry.GenericRetry;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Error Status Handler for Failed Reconciliations",
description =
"Demonstrates how to implement error status handlers that update resource status when"
+ " reconciliations fail. The test verifies that error messages are properly recorded"
+ " in the resource status after each failed retry attempt. This provides visibility"
+ " into reconciliation failures and helps with debugging operator issues.")
class ErrorStatusHandlerIT {

public static final int MAX_RETRY_ATTEMPTS = 3;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.support.TestUtils;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Custom Event Source for Periodic Reconciliation",
description =
"Demonstrates how to implement custom event sources that trigger reconciliation on a"
+ " periodic basis. The test verifies that reconciliations are triggered at regular"
+ " intervals by a timer-based event source. This enables operators to perform periodic"
+ " checks or updates independent of resource changes.")
class EventSourceIT {

@RegisterExtension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

import static io.javaoperatorsdk.operator.baseapi.filter.FilterTestReconciler.CONFIG_MAP_FILTER_VALUE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Filtering Events for Primary and Secondary Resources",
description =
"Demonstrates how to implement event filters for both primary custom resources and"
+ " secondary dependent resources. The test verifies that resource updates matching"
+ " specific filter criteria are ignored and don't trigger reconciliation. This helps"
+ " reduce unnecessary reconciliation executions and improve operator efficiency.")
class FilterIT {

public static final String RESOURCE_NAME = "test1";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.dependent.generickubernetesresource.GenericKubernetesDependentSpec;
import io.javaoperatorsdk.operator.dependent.generickubernetesresource.GenericKubernetesDependentTestBase;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

@Sample(
tldr = "Working with GenericKubernetesResource for Dynamic Resource Types",
description =
"Demonstrates how to use GenericKubernetesResource to work with Kubernetes resources"
+ " dynamically without requiring compile-time type definitions. This approach is"
+ " useful when building operators that need to manage arbitrary Kubernetes resources"
+ " or when the resource types are not known at compile time. The test shows how to"
+ " handle generic resources as dependent resources in a reconciler.")
public class GenericKubernetesResourceHandlingIT
extends GenericKubernetesDependentTestBase<GenericKubernetesResourceHandlingCustomResource> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

import static io.javaoperatorsdk.operator.baseapi.gracefulstop.GracefulStopTestReconciler.RECONCILER_SLEEP;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Graceful Operator Shutdown with Reconciliation Timeout",
description =
"Demonstrates how to configure graceful shutdown behavior with reconciliation termination"
+ " timeouts. The test verifies that in-progress reconciliations are allowed to"
+ " complete when the operator stops. This ensures clean shutdown without interrupting"
+ " ongoing reconciliation work.")
public class GracefulStopIT {

public static final String TEST_1 = "test1";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.javaoperatorsdk.annotation.Sample;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;

import static io.javaoperatorsdk.operator.baseapi.informereventsource.InformerEventSourceTestCustomReconciler.MISSING_CONFIG_MAP;
Expand All @@ -17,6 +18,13 @@
import static org.assertj.core.api.Assertions.fail;
import static org.awaitility.Awaitility.await;

@Sample(
tldr = "Using Informer Event Source to Watch Secondary Resources",
description =
"Demonstrates how to use InformerEventSource to watch changes in secondary resources"
+ " (ConfigMaps) and trigger reconciliation when those resources are created, updated,"
+ " or deleted. The test verifies that the reconciler responds to ConfigMap changes and"
+ " updates the primary resource status accordingly.")
class InformerEventSourceIT {

public static final String RESOURCE_NAME = "informertestcr";
Expand Down
Loading