From 362fa667a26965b4c95fbfc38b813938ba52f8cd Mon Sep 17 00:00:00 2001 From: Carles Arnal Date: Tue, 21 Jan 2025 15:39:18 +0100 Subject: [PATCH 1/3] Add replicas tests --- .../apicurio/registry/operator/it/ITBase.java | 46 ++++++++++ .../registry/operator/it/SmokeITTest.java | 57 +++++++----- .../operator/it/StudioSmokeITTest.java | 87 ++++++++----------- 3 files changed, 119 insertions(+), 71 deletions(-) diff --git a/operator/controller/src/test/java/io/apicurio/registry/operator/it/ITBase.java b/operator/controller/src/test/java/io/apicurio/registry/operator/it/ITBase.java index f46fcf3b4a..46abde619e 100644 --- a/operator/controller/src/test/java/io/apicurio/registry/operator/it/ITBase.java +++ b/operator/controller/src/test/java/io/apicurio/registry/operator/it/ITBase.java @@ -105,6 +105,52 @@ public void beforeEach(TestInfo testInfo) { // spotless:on } + protected static void checkDeploymentExists(ApicurioRegistry3 primary, String component, int replicas) { + await().ignoreExceptions().untilAsserted(() -> { + assertThat(client.apps().deployments() + .withName(primary.getMetadata().getName() + "-" + component + "-deployment").get() + .getStatus().getReadyReplicas()).isEqualTo(replicas); + }); + } + + protected static void checkDeploymentDoesNotExist(ApicurioRegistry3 primary, String component) { + await().ignoreExceptions().untilAsserted(() -> { + assertThat(client.apps().deployments() + .withName(primary.getMetadata().getName() + "-" + component + "-deployment").get()) + .isNull(); + }); + } + + protected static void checkServiceExists(ApicurioRegistry3 primary, String component) { + await().ignoreExceptions().untilAsserted(() -> { + assertThat(client.services() + .withName(primary.getMetadata().getName() + "-" + component + "-service").get()) + .isNotNull(); + }); + } + + protected static void checkServiceDoesNotExist(ApicurioRegistry3 primary, String component) { + await().ignoreExceptions().untilAsserted(() -> { + assertThat(client.services() + .withName(primary.getMetadata().getName() + "-" + component + "-service").get()).isNull(); + }); + } + + protected static void checkIngressExists(ApicurioRegistry3 primary, String component) { + await().ignoreExceptions().untilAsserted(() -> { + assertThat(client.network().v1().ingresses() + .withName(primary.getMetadata().getName() + "-" + component + "-ingress").get()) + .isNotNull(); + }); + } + + protected static void checkIngressDoesNotExist(ApicurioRegistry3 primary, String component) { + await().ignoreExceptions().untilAsserted(() -> { + assertThat(client.network().v1().ingresses() + .withName(primary.getMetadata().getName() + "-" + component + "-ingress").get()).isNull(); + }); + } + static KubernetesClient createK8sClient(String namespace) { return new KubernetesClientBuilder() .withConfig(new ConfigBuilder(Config.autoConfigure(null)).withNamespace(namespace).build()) diff --git a/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java b/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java index 8b85c851ce..e6e99a25b6 100644 --- a/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java +++ b/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java @@ -16,6 +16,8 @@ import java.net.URI; import static io.apicurio.registry.operator.api.v1.ContainerNames.REGISTRY_UI_CONTAINER_NAME; +import static io.apicurio.registry.operator.resource.ResourceFactory.COMPONENT_APP; +import static io.apicurio.registry.operator.resource.ResourceFactory.COMPONENT_UI; import static io.restassured.RestAssured.given; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; @@ -70,6 +72,34 @@ void smoke() { }); } + @Test + void replicas() { + var registry = ResourceFactory.deserialize("/k8s/examples/simple.apicurioregistry3.yaml", + ApicurioRegistry3.class); + + registry.getMetadata().setNamespace(namespace); + registry.getSpec().getApp().setHost(ingressManager.getIngressHost("app")); + registry.getSpec().getUi().setHost(ingressManager.getIngressHost("ui")); + + client.resource(registry).create(); + + // Verify first replica + checkDeploymentExists(registry, COMPONENT_APP, 1); + checkDeploymentExists(registry, COMPONENT_UI, 1); + + // Scale up + registry.getSpec().getApp().setReplicas(3); + registry.getSpec().getUi().setReplicas(3); + checkDeploymentExists(registry, COMPONENT_APP, 3); + checkDeploymentExists(registry, COMPONENT_UI, 3); + + // Scale down + registry.getSpec().getApp().setReplicas(2); + registry.getSpec().getUi().setReplicas(2); + checkDeploymentExists(registry, COMPONENT_APP, 2); + checkDeploymentExists(registry, COMPONENT_UI, 2); + } + @Test void testService() { @@ -82,15 +112,8 @@ void testService() { client.resource(registry).create(); // Wait for Services - await().ignoreExceptions().until(() -> { - assertThat(client.services().inNamespace(namespace) - .withName(registry.getMetadata().getName() + "-app-service").get().getSpec() - .getClusterIP()).isNotBlank(); - assertThat(client.services().inNamespace(namespace) - .withName(registry.getMetadata().getName() + "-ui-service").get().getSpec() - .getClusterIP()).isNotBlank(); - return true; - }); + checkServiceExists(registry, COMPONENT_APP); + checkServiceExists(registry, COMPONENT_UI); int appServicePort = portForwardManager .startPortForward(registry.getMetadata().getName() + "-app-service", 8080); @@ -123,12 +146,8 @@ void testIngress() { client.resource(registry).create(); // Wait for Ingresses - await().untilAsserted(() -> { - assertThat(client.network().v1().ingresses().inNamespace(namespace) - .withName(registry.getMetadata().getName() + "-app-ingress").get()).isNotNull(); - assertThat(client.network().v1().ingresses().inNamespace(namespace) - .withName(registry.getMetadata().getName() + "-ui-ingress").get()).isNotNull(); - }); + checkIngressExists(registry, COMPONENT_APP); + checkIngressExists(registry, COMPONENT_UI); await().ignoreExceptions().until(() -> { ingressManager.startHttpRequest(registry.getMetadata().getName() + "-app-ingress") @@ -155,12 +174,8 @@ void testEmptyHostDisablesIngress() { client.resource(registry).create(); // Wait for Ingresses - await().untilAsserted(() -> { - assertThat(client.network().v1().ingresses().inNamespace(namespace) - .withName(registry.getMetadata().getName() + "-app-ingress").get()).isNotNull(); - assertThat(client.network().v1().ingresses().inNamespace(namespace) - .withName(registry.getMetadata().getName() + "-ui-ingress").get()).isNotNull(); - }); + checkIngressExists(registry, COMPONENT_APP); + checkIngressExists(registry, COMPONENT_UI); // Check that REGISTRY_API_URL is set await().ignoreExceptions().untilAsserted(() -> { diff --git a/operator/controller/src/test/java/io/apicurio/registry/operator/it/StudioSmokeITTest.java b/operator/controller/src/test/java/io/apicurio/registry/operator/it/StudioSmokeITTest.java index 3fce034a3d..791879e857 100644 --- a/operator/controller/src/test/java/io/apicurio/registry/operator/it/StudioSmokeITTest.java +++ b/operator/controller/src/test/java/io/apicurio/registry/operator/it/StudioSmokeITTest.java @@ -12,7 +12,6 @@ import static io.apicurio.registry.operator.it.SmokeITTest.ingressDisabled; import static io.apicurio.registry.operator.resource.ResourceFactory.*; import static io.restassured.RestAssured.given; -import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; @QuarkusTest @@ -36,8 +35,8 @@ void smoke() { client.resource(simpleRegistry).create(); - checkDeploymentExists(simpleRegistry, COMPONENT_APP); - checkDeploymentExists(simpleRegistry, COMPONENT_UI); + checkDeploymentExists(simpleRegistry, COMPONENT_APP, 1); + checkDeploymentExists(simpleRegistry, COMPONENT_UI, 1); checkDeploymentDoesNotExist(simpleRegistry, COMPONENT_STUDIO_UI); checkServiceExists(simpleRegistry, COMPONENT_APP); @@ -52,9 +51,9 @@ void smoke() { simpleRegistry.getSpec().withStudioUi().setEnabled(true); client.resource(simpleRegistry).update(); - checkDeploymentExists(simpleRegistry, COMPONENT_APP); - checkDeploymentExists(simpleRegistry, COMPONENT_UI); - checkDeploymentExists(simpleRegistry, COMPONENT_STUDIO_UI); + checkDeploymentExists(simpleRegistry, COMPONENT_APP, 1); + checkDeploymentExists(simpleRegistry, COMPONENT_UI, 1); + checkDeploymentExists(simpleRegistry, COMPONENT_STUDIO_UI, 1); checkServiceExists(simpleRegistry, COMPONENT_APP); checkServiceExists(simpleRegistry, COMPONENT_UI); @@ -96,9 +95,9 @@ void smoke() { simpleRegistry.getSpec().getStudioUi().getIngress().setHost(null); client.resource(simpleRegistry).update(); - checkDeploymentExists(simpleRegistry, COMPONENT_APP); - checkDeploymentExists(simpleRegistry, COMPONENT_UI); - checkDeploymentExists(simpleRegistry, COMPONENT_STUDIO_UI); + checkDeploymentExists(simpleRegistry, COMPONENT_APP, 1); + checkDeploymentExists(simpleRegistry, COMPONENT_UI, 1); + checkDeploymentExists(simpleRegistry, COMPONENT_STUDIO_UI, 1); checkServiceExists(simpleRegistry, COMPONENT_APP); checkServiceExists(simpleRegistry, COMPONENT_UI); @@ -112,8 +111,8 @@ void smoke() { simpleRegistry.getSpec().getStudioUi().setEnabled(false); client.resource(simpleRegistry).update(); - checkDeploymentExists(simpleRegistry, COMPONENT_APP); - checkDeploymentExists(simpleRegistry, COMPONENT_UI); + checkDeploymentExists(simpleRegistry, COMPONENT_APP, 1); + checkDeploymentExists(simpleRegistry, COMPONENT_UI, 1); checkDeploymentDoesNotExist(simpleRegistry, COMPONENT_STUDIO_UI); checkServiceExists(simpleRegistry, COMPONENT_APP); @@ -125,49 +124,37 @@ void smoke() { checkIngressDoesNotExist(simpleRegistry, COMPONENT_STUDIO_UI); } - private static void checkDeploymentExists(ApicurioRegistry3 primary, String component) { - await().ignoreExceptions().untilAsserted(() -> { - assertThat(client.apps().deployments() - .withName(primary.getMetadata().getName() + "-" + component + "-deployment").get() - .getStatus().getReadyReplicas()).isEqualTo(1); - }); - } + /** + * Scenario: We want to check that the Studio component is not deployed by default unless the enabled + * field is set to true, and, when activated, the number of replicas is set to the value specified while + * checking that the basic Kubernetes resources are deployed as expected. We do not check Registry + * components in detail, because that's done in other tests. + */ + @Test + void replicas() { + var simpleRegistry = ResourceFactory.deserialize("/k8s/examples/simple.apicurioregistry3.yaml", + ApicurioRegistry3.class); - private static void checkDeploymentDoesNotExist(ApicurioRegistry3 primary, String component) { - await().ignoreExceptions().untilAsserted(() -> { - assertThat(client.apps().deployments() - .withName(primary.getMetadata().getName() + "-" + component + "-deployment").get()) - .isNull(); - }); - } + simpleRegistry.getMetadata().setNamespace(namespace); + simpleRegistry.getSpec().getApp().setHost(ingressManager.getIngressHost(COMPONENT_APP)); + simpleRegistry.getSpec().getUi().setHost(ingressManager.getIngressHost(COMPONENT_UI)); - private static void checkServiceExists(ApicurioRegistry3 primary, String component) { - await().ignoreExceptions().untilAsserted(() -> { - assertThat(client.services() - .withName(primary.getMetadata().getName() + "-" + component + "-service").get()) - .isNotNull(); - }); - } + client.resource(simpleRegistry).create(); - private static void checkServiceDoesNotExist(ApicurioRegistry3 primary, String component) { - await().ignoreExceptions().untilAsserted(() -> { - assertThat(client.services() - .withName(primary.getMetadata().getName() + "-" + component + "-service").get()).isNull(); - }); - } + // We start with one replica for Registry + checkDeploymentExists(simpleRegistry, COMPONENT_APP, 1); + checkDeploymentExists(simpleRegistry, COMPONENT_UI, 1); + checkDeploymentDoesNotExist(simpleRegistry, COMPONENT_STUDIO_UI); - private static void checkIngressExists(ApicurioRegistry3 primary, String component) { - await().ignoreExceptions().untilAsserted(() -> { - assertThat(client.network().v1().ingresses() - .withName(primary.getMetadata().getName() + "-" + component + "-ingress").get()) - .isNotNull(); - }); - } + // Now let's enable the Studio component and scale Registry to 3 replicas + simpleRegistry.getSpec().getStudioUi().setEnabled(true); + simpleRegistry.getSpec().getApp().setReplicas(3); + simpleRegistry.getSpec().getUi().setReplicas(3); + simpleRegistry.getSpec().getStudioUi().setReplicas(3); + client.resource(simpleRegistry).update(); - private static void checkIngressDoesNotExist(ApicurioRegistry3 primary, String component) { - await().ignoreExceptions().untilAsserted(() -> { - assertThat(client.network().v1().ingresses() - .withName(primary.getMetadata().getName() + "-" + component + "-ingress").get()).isNull(); - }); + checkDeploymentExists(simpleRegistry, COMPONENT_APP, 3); + checkDeploymentExists(simpleRegistry, COMPONENT_UI, 3); + checkDeploymentExists(simpleRegistry, COMPONENT_STUDIO_UI, 3); } } From fc4f132de0f70978a1e905715975af61d4c29577 Mon Sep 17 00:00:00 2001 From: Carles Arnal Date: Tue, 21 Jan 2025 16:46:46 +0100 Subject: [PATCH 2/3] Add update clause to smoke test --- .../test/java/io/apicurio/registry/operator/it/SmokeITTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java b/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java index e6e99a25b6..caec48892b 100644 --- a/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java +++ b/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java @@ -90,12 +90,14 @@ void replicas() { // Scale up registry.getSpec().getApp().setReplicas(3); registry.getSpec().getUi().setReplicas(3); + client.resource(registry).update(); checkDeploymentExists(registry, COMPONENT_APP, 3); checkDeploymentExists(registry, COMPONENT_UI, 3); // Scale down registry.getSpec().getApp().setReplicas(2); registry.getSpec().getUi().setReplicas(2); + client.resource(registry).update(); checkDeploymentExists(registry, COMPONENT_APP, 2); checkDeploymentExists(registry, COMPONENT_UI, 2); } From edae82af8305278aa573d4b1d74b3e43e3ff94a8 Mon Sep 17 00:00:00 2001 From: Carles Arnal Date: Tue, 21 Jan 2025 17:59:56 +0100 Subject: [PATCH 3/3] Use uptional for default values --- .../operator/resource/ResourceFactory.java | 29 ++++++++++++------- .../registry/operator/it/SmokeITTest.java | 27 +++++++++++++---- .../operator/it/StudioSmokeITTest.java | 2 +- operator/install/install.yaml | 9 ++++++ .../operator/api/v1/spec/ComponentSpec.java | 8 +++++ 5 files changed, 57 insertions(+), 18 deletions(-) diff --git a/operator/controller/src/main/java/io/apicurio/registry/operator/resource/ResourceFactory.java b/operator/controller/src/main/java/io/apicurio/registry/operator/resource/ResourceFactory.java index 9454892d21..9f232cf525 100644 --- a/operator/controller/src/main/java/io/apicurio/registry/operator/resource/ResourceFactory.java +++ b/operator/controller/src/main/java/io/apicurio/registry/operator/resource/ResourceFactory.java @@ -12,14 +12,14 @@ import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentSpec; import io.fabric8.kubernetes.api.model.networking.v1.Ingress; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; +import static io.apicurio.registry.operator.Constants.DEFAULT_REPLICAS; import static io.apicurio.registry.operator.api.v1.ContainerNames.*; import static io.apicurio.registry.operator.resource.app.AppDeploymentResource.getContainerFromPodTemplateSpec; import static io.apicurio.registry.operator.utils.Mapper.YAML_MAPPER; @@ -28,8 +28,6 @@ public class ResourceFactory { - private static final Logger log = LoggerFactory.getLogger(ResourceFactory.class); - public static final ResourceFactory INSTANCE = new ResourceFactory(); public static final String COMPONENT_APP = "app"; @@ -41,8 +39,11 @@ public class ResourceFactory { public static final String RESOURCE_TYPE_INGRESS = "ingress"; public Deployment getDefaultAppDeployment(ApicurioRegistry3 primary) { - var r = initDefaultDeployment(primary, COMPONENT_APP, 1, ofNullable(primary.getSpec()) - .map(ApicurioRegistry3Spec::getApp).map(AppSpec::getPodTemplateSpec).orElse(null)); // TODO: + var r = initDefaultDeployment(primary, COMPONENT_APP, + Optional.ofNullable(primary.getSpec()).map(ApicurioRegistry3Spec::getApp) + .map(AppSpec::getReplicas).orElse(DEFAULT_REPLICAS), + ofNullable(primary.getSpec()).map(ApicurioRegistry3Spec::getApp) + .map(AppSpec::getPodTemplateSpec).orElse(null)); // TODO: // Replicas mergeDeploymentPodTemplateSpec( // spotless:off @@ -63,8 +64,11 @@ public Deployment getDefaultAppDeployment(ApicurioRegistry3 primary) { } public Deployment getDefaultUIDeployment(ApicurioRegistry3 primary) { - var r = initDefaultDeployment(primary, COMPONENT_UI, 1, ofNullable(primary.getSpec()) - .map(ApicurioRegistry3Spec::getUi).map(UiSpec::getPodTemplateSpec).orElse(null)); // TODO: + var r = initDefaultDeployment(primary, COMPONENT_UI, + Optional.ofNullable(primary.getSpec()).map(ApicurioRegistry3Spec::getUi) + .map(UiSpec::getReplicas).orElse(DEFAULT_REPLICAS), + ofNullable(primary.getSpec()).map(ApicurioRegistry3Spec::getUi) + .map(UiSpec::getPodTemplateSpec).orElse(null)); // TODO: // Replicas mergeDeploymentPodTemplateSpec( // spotless:off @@ -85,9 +89,12 @@ public Deployment getDefaultUIDeployment(ApicurioRegistry3 primary) { } public Deployment getDefaultStudioUIDeployment(ApicurioRegistry3 primary) { - var r = initDefaultDeployment(primary, COMPONENT_STUDIO_UI, 1, ofNullable(primary.getSpec()) - .map(ApicurioRegistry3Spec::getStudioUi).map(StudioUiSpec::getPodTemplateSpec).orElse(null)); // TODO: - // Replicas + var r = initDefaultDeployment(primary, COMPONENT_STUDIO_UI, + Optional.ofNullable(primary.getSpec()).map(ApicurioRegistry3Spec::getStudioUi) + .map(StudioUiSpec::getReplicas).orElse(DEFAULT_REPLICAS), + ofNullable(primary.getSpec()).map(ApicurioRegistry3Spec::getStudioUi) + .map(StudioUiSpec::getPodTemplateSpec).orElse(null)); // TODO: + // Replicas mergeDeploymentPodTemplateSpec( // spotless:off r.getSpec().getTemplate(), diff --git a/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java b/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java index caec48892b..eb8a51a074 100644 --- a/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java +++ b/operator/controller/src/test/java/io/apicurio/registry/operator/it/SmokeITTest.java @@ -114,8 +114,15 @@ void testService() { client.resource(registry).create(); // Wait for Services - checkServiceExists(registry, COMPONENT_APP); - checkServiceExists(registry, COMPONENT_UI); + await().ignoreExceptions().until(() -> { + assertThat(client.services().inNamespace(namespace) + .withName(registry.getMetadata().getName() + "-app-service").get().getSpec() + .getClusterIP()).isNotBlank(); + assertThat(client.services().inNamespace(namespace) + .withName(registry.getMetadata().getName() + "-ui-service").get().getSpec() + .getClusterIP()).isNotBlank(); + return true; + }); int appServicePort = portForwardManager .startPortForward(registry.getMetadata().getName() + "-app-service", 8080); @@ -148,8 +155,12 @@ void testIngress() { client.resource(registry).create(); // Wait for Ingresses - checkIngressExists(registry, COMPONENT_APP); - checkIngressExists(registry, COMPONENT_UI); + await().untilAsserted(() -> { + assertThat(client.network().v1().ingresses().inNamespace(namespace) + .withName(registry.getMetadata().getName() + "-app-ingress").get()).isNotNull(); + assertThat(client.network().v1().ingresses().inNamespace(namespace) + .withName(registry.getMetadata().getName() + "-ui-ingress").get()).isNotNull(); + }); await().ignoreExceptions().until(() -> { ingressManager.startHttpRequest(registry.getMetadata().getName() + "-app-ingress") @@ -176,8 +187,12 @@ void testEmptyHostDisablesIngress() { client.resource(registry).create(); // Wait for Ingresses - checkIngressExists(registry, COMPONENT_APP); - checkIngressExists(registry, COMPONENT_UI); + await().untilAsserted(() -> { + assertThat(client.network().v1().ingresses().inNamespace(namespace) + .withName(registry.getMetadata().getName() + "-app-ingress").get()).isNotNull(); + assertThat(client.network().v1().ingresses().inNamespace(namespace) + .withName(registry.getMetadata().getName() + "-ui-ingress").get()).isNotNull(); + }); // Check that REGISTRY_API_URL is set await().ignoreExceptions().untilAsserted(() -> { diff --git a/operator/controller/src/test/java/io/apicurio/registry/operator/it/StudioSmokeITTest.java b/operator/controller/src/test/java/io/apicurio/registry/operator/it/StudioSmokeITTest.java index 791879e857..36c780f4a9 100644 --- a/operator/controller/src/test/java/io/apicurio/registry/operator/it/StudioSmokeITTest.java +++ b/operator/controller/src/test/java/io/apicurio/registry/operator/it/StudioSmokeITTest.java @@ -147,7 +147,7 @@ void replicas() { checkDeploymentDoesNotExist(simpleRegistry, COMPONENT_STUDIO_UI); // Now let's enable the Studio component and scale Registry to 3 replicas - simpleRegistry.getSpec().getStudioUi().setEnabled(true); + simpleRegistry.getSpec().withStudioUi().setEnabled(true); simpleRegistry.getSpec().getApp().setReplicas(3); simpleRegistry.getSpec().getUi().setReplicas(3); simpleRegistry.getSpec().getStudioUi().setReplicas(3); diff --git a/operator/install/install.yaml b/operator/install/install.yaml index e9e7376df7..a3dc420d9c 100644 --- a/operator/install/install.yaml +++ b/operator/install/install.yaml @@ -3019,6 +3019,9 @@ spec: type: array type: object type: object + replicas: + description: Number of replicas for the component + type: integer sql: description: |- DEPRECATED: Use the `app.storage.type` and `app.storage.sql` fields instead. @@ -6088,6 +6091,9 @@ spec: type: array type: object type: object + replicas: + description: Number of replicas for the component + type: integer type: object ui: description: | @@ -9074,6 +9080,9 @@ spec: type: array type: object type: object + replicas: + description: Number of replicas for the component + type: integer type: object type: object status: diff --git a/operator/model/src/main/java/io/apicurio/registry/operator/api/v1/spec/ComponentSpec.java b/operator/model/src/main/java/io/apicurio/registry/operator/api/v1/spec/ComponentSpec.java index bce7b7f893..c29c2107d9 100644 --- a/operator/model/src/main/java/io/apicurio/registry/operator/api/v1/spec/ComponentSpec.java +++ b/operator/model/src/main/java/io/apicurio/registry/operator/api/v1/spec/ComponentSpec.java @@ -84,6 +84,14 @@ public abstract class ComponentSpec { @JsonSetter(nulls = Nulls.SKIP) private String host; + /** + * Number of replicas for the component + */ + @JsonProperty("replicas") + @JsonPropertyDescription("Number of replicas for the component") + @JsonSetter(nulls = Nulls.SKIP) + private Integer replicas; + public IngressSpec withIngress() { if (ingress == null) { ingress = new IngressSpec();