Skip to content

Commit

Permalink
feat(operator): New "features" section of the app spec to allow enabl…
Browse files Browse the repository at this point in the history
…ing deletes (#5898)

* New "features" section of the app spec to allow enabling delete functionality

* Class rename and regenerated the install.yaml

* Removed examle file (accidentally added).
  • Loading branch information
EricWittmann authored Jan 23, 2025
1 parent f2bab39 commit 58606dd
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 4 deletions.
3 changes: 3 additions & 0 deletions operator/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
controller/src/main/deploy/crd/apicurioregistries3.registry.apicur.io-v1.yml
install/apicurio-registry-operator-*-SNAPSHOT.yaml
.*.sh
.*.yaml
.*.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.apicurio.registry.operator;

public class EnvironmentVariables {

public static final String QUARKUS_PROFILE = "QUARKUS_PROFILE";
public static final String QUARKUS_HTTP_ACCESS_LOG_ENABLED = "QUARKUS_HTTP_ACCESS_LOG_ENABLED";
public static final String QUARKUS_HTTP_CORS_ORIGINS = "QUARKUS_HTTP_CORS_ORIGINS";

public static final String APICURIO_REST_DELETION_ARTIFACT_VERSION_ENABLED = "APICURIO_REST_DELETION_ARTIFACT-VERSION_ENABLED";
public static final String APICURIO_REST_DELETION_ARTIFACT_ENABLED = "APICURIO_REST_DELETION_ARTIFACT_ENABLED";
public static final String APICURIO_REST_DELETION_GROUP_ENABLED = "APICURIO_REST_DELETION_GROUP_ENABLED";

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package io.apicurio.registry.operator.resource.app;

import io.apicurio.registry.operator.EnvironmentVariables;
import io.apicurio.registry.operator.OperatorException;
import io.apicurio.registry.operator.api.v1.ApicurioRegistry3;
import io.apicurio.registry.operator.api.v1.ApicurioRegistry3Spec;
import io.apicurio.registry.operator.api.v1.spec.AppFeaturesSpec;
import io.apicurio.registry.operator.api.v1.spec.AppSpec;
import io.apicurio.registry.operator.api.v1.spec.StorageSpec;
import io.apicurio.registry.operator.feat.KafkaSql;
Expand All @@ -21,6 +23,7 @@

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

import static io.apicurio.registry.operator.api.v1.ContainerNames.REGISTRY_APP_CONTAINER_NAME;
import static io.apicurio.registry.operator.resource.LabelDiscriminators.AppDeploymentDiscriminator;
Expand Down Expand Up @@ -55,9 +58,20 @@ protected Deployment desired(ApicurioRegistry3 primary, Context<ApicurioRegistry
.ifPresent(env -> env.forEach(e -> envVars.put(e.getName(), e)));

// spotless:off
addEnvVar(envVars, new EnvVarBuilder().withName("QUARKUS_PROFILE").withValue("prod").build());
addEnvVar(envVars, new EnvVarBuilder().withName("QUARKUS_HTTP_ACCESS_LOG_ENABLED").withValue("true").build());
addEnvVar(envVars, new EnvVarBuilder().withName("QUARKUS_HTTP_CORS_ORIGINS").withValue("*").build());
addEnvVar(envVars, new EnvVarBuilder().withName(EnvironmentVariables.QUARKUS_PROFILE).withValue("prod").build());
addEnvVar(envVars, new EnvVarBuilder().withName(EnvironmentVariables.QUARKUS_HTTP_ACCESS_LOG_ENABLED).withValue("true").build());
addEnvVar(envVars, new EnvVarBuilder().withName(EnvironmentVariables.QUARKUS_HTTP_CORS_ORIGINS).withValue("*").build());

// Enable deletes if configured in the CR
boolean allowDeletes = Optional.ofNullable(primary.getSpec().getApp())
.map(AppSpec::getFeatures)
.map(AppFeaturesSpec::getAllowDeletes)
.orElse(Boolean.FALSE);
if (allowDeletes) {
addEnvVar(envVars, new EnvVarBuilder().withName(EnvironmentVariables.APICURIO_REST_DELETION_ARTIFACT_VERSION_ENABLED).withValue("true").build());
addEnvVar(envVars, new EnvVarBuilder().withName(EnvironmentVariables.APICURIO_REST_DELETION_ARTIFACT_ENABLED).withValue("true").build());
addEnvVar(envVars, new EnvVarBuilder().withName(EnvironmentVariables.APICURIO_REST_DELETION_GROUP_ENABLED).withValue("true").build());
}
// spotless:on

// This is enabled only if Studio is deployed. It is based on Service in case a custom Ingress is
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.apicurio.registry.operator.it;

import io.apicurio.registry.operator.EnvironmentVariables;
import io.apicurio.registry.operator.api.v1.ApicurioRegistry3;
import io.apicurio.registry.operator.api.v1.spec.AppFeaturesSpec;
import io.apicurio.registry.operator.resource.ResourceFactory;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static io.apicurio.registry.operator.api.v1.ContainerNames.REGISTRY_APP_CONTAINER_NAME;
import static io.apicurio.registry.operator.resource.app.AppDeploymentResource.getContainerFromDeployment;
import static org.assertj.core.api.Assertions.assertThat;

@QuarkusTest
public class AppFeaturesITTest extends ITBase {

private static final Logger log = LoggerFactory.getLogger(AppFeaturesITTest.class);

@Test
void testAllowDeletesTrue() {
ApicurioRegistry3 registry = ResourceFactory
.deserialize("/k8s/examples/simple.apicurioregistry3.yaml", ApicurioRegistry3.class);
// Set Allow deletes = true
registry.getSpec().getApp().setFeatures(AppFeaturesSpec.builder().allowDeletes(true).build());
client.resource(registry).create();

// Wait for the deployment to exist
checkDeploymentExists(registry, ResourceFactory.COMPONENT_APP, 1);

// Check that the three deletion ENV vars are set
var appEnv = getContainerFromDeployment(
client.apps().deployments().inNamespace(namespace)
.withName(registry.getMetadata().getName() + "-app-deployment").get(),
REGISTRY_APP_CONTAINER_NAME).getEnv();
assertThat(appEnv).map(EnvVar::getName).contains(
EnvironmentVariables.APICURIO_REST_DELETION_ARTIFACT_ENABLED,
EnvironmentVariables.APICURIO_REST_DELETION_ARTIFACT_VERSION_ENABLED,
EnvironmentVariables.APICURIO_REST_DELETION_GROUP_ENABLED);
}

@Test
void testAllowDeletesDefault() {
ApicurioRegistry3 registry = ResourceFactory
.deserialize("/k8s/examples/simple.apicurioregistry3.yaml", ApicurioRegistry3.class);
client.resource(registry).create();

// Wait for the deployment to exist
checkDeploymentExists(registry, ResourceFactory.COMPONENT_APP, 1);

// Check that the three deletion ENV vars are NOT set
var appEnv = getContainerFromDeployment(
client.apps().deployments().inNamespace(namespace)
.withName(registry.getMetadata().getName() + "-app-deployment").get(),
REGISTRY_APP_CONTAINER_NAME).getEnv();
assertThat(appEnv).map(EnvVar::getName).doesNotContain(
EnvironmentVariables.APICURIO_REST_DELETION_ARTIFACT_ENABLED,
EnvironmentVariables.APICURIO_REST_DELETION_ARTIFACT_VERSION_ENABLED,
EnvironmentVariables.APICURIO_REST_DELETION_GROUP_ENABLED);
}
}
14 changes: 14 additions & 0 deletions operator/install/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,20 @@ spec:
type: object
type: object
type: array
features:
description: |
Configure features of the Apicurio Registry backend (app).
properties:
allowDeletes:
description: |-
Apicurio Registry backend 'allow deletes' feature.
If the value is true, the application will be configured to allow Groups, Artifacts, and
Artifact Versions to be deleted. By default, resources in Registry are immutable and so
cannot be deleted. Registry can be configured to allow deleting of these resources at a
granular level (e.g. only allow deleting artifact versions) using ENV variables. This
option enables deletes for all three resource types.
type: boolean
type: object
host:
description: 'DEPRECATED: Use the `(component).ingress.host` field
instead. The operator will attempt to update the field automatically.'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.apicurio.registry.operator.api.v1.spec;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
import static lombok.AccessLevel.PRIVATE;

@JsonDeserialize(using = JsonDeserializer.None.class)
@JsonInclude(NON_NULL)
@JsonPropertyOrder({ "allowDeletes" })
@NoArgsConstructor
@AllArgsConstructor(access = PRIVATE)
@SuperBuilder(toBuilder = true)
@Getter
@Setter
@EqualsAndHashCode
@ToString
public class AppFeaturesSpec {

@JsonProperty("allowDeletes")
@JsonPropertyDescription("""
Apicurio Registry backend 'allow deletes' feature.
If the value is true, the application will be configured to allow Groups, Artifacts, and
Artifact Versions to be deleted. By default, resources in Registry are immutable and so
cannot be deleted. Registry can be configured to allow deleting of these resources at a
granular level (e.g. only allow deleting artifact versions) using ENV variables. This
option enables deletes for all three resource types.""")
@JsonSetter(nulls = Nulls.SKIP)
private Boolean allowDeletes;

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

@JsonDeserialize(using = None.class)
@JsonInclude(NON_NULL)
@JsonPropertyOrder({ "env", "ingress", "podTemplateSpec", "storage", "sql", "kafkasql" })
@JsonPropertyOrder({ "env", "ingress", "podTemplateSpec", "storage", "sql", "kafkasql", "features" })
@NoArgsConstructor
@AllArgsConstructor(access = PRIVATE)
@SuperBuilder(toBuilder = true)
Expand All @@ -32,6 +32,16 @@ Configure storage for Apicurio Registry backend (app).
@JsonSetter(nulls = SKIP)
private StorageSpec storage;

/**
* Configure features of the Apicurio Registry application.
*/
@JsonProperty("features")
@JsonPropertyDescription("""
Configure features of the Apicurio Registry backend (app).
""")
@JsonSetter(nulls = SKIP)
private AppFeaturesSpec features;

/**
* DEPRECATED: Use the `app.storage.type` and `app.storage.sql` fields instead. The operator will attempt
* to update the fields automatically.
Expand Down

0 comments on commit 58606dd

Please sign in to comment.