Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(operator): New "features" section of the app spec to allow enabling deletes #5898

Merged
merged 3 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
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);
EricWittmann marked this conversation as resolved.
Show resolved Hide resolved
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);
EricWittmann marked this conversation as resolved.
Show resolved Hide resolved
// 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;
EricWittmann marked this conversation as resolved.
Show resolved Hide resolved

}
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
Loading