From 35df666eaf32bae2c013f13f34932c15a53190ea Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Mon, 4 Mar 2024 16:33:02 +0100 Subject: [PATCH] fix: add proper default install mode derived from watched namespaces Fixes #839 Signed-off-by: Chris Laprun --- .../bundle/deployment/BundleGenerator.java | 6 ++- .../bundle/deployment/BundleProcessor.java | 7 ++- .../builders/CsvManifestsBuilder.java | 45 ++++++++++++++----- .../bundle/MultipleOperatorsBundleTest.java | 14 +++++- .../bundle/sources/FirstReconciler.java | 2 +- 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/BundleGenerator.java b/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/BundleGenerator.java index a47931ef5..65c657a61 100644 --- a/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/BundleGenerator.java +++ b/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/BundleGenerator.java @@ -15,6 +15,7 @@ import io.quarkiverse.operatorsdk.common.ReconcilerAugmentedClassInfo; import io.quarkiverse.operatorsdk.runtime.BuildTimeOperatorConfiguration; import io.quarkiverse.operatorsdk.runtime.CRDInfo; +import io.quarkiverse.operatorsdk.runtime.QuarkusControllerConfiguration; import io.quarkiverse.operatorsdk.runtime.Version; import io.quarkus.container.util.PathsUtil; @@ -46,10 +47,11 @@ public class BundleGenerator { private BundleGenerator() { } + @SuppressWarnings("rawtypes") public static List prepareGeneration(BundleGenerationConfiguration bundleConfiguration, BuildTimeOperatorConfiguration operatorConfiguration, Version version, Map> csvGroups, Map crds, - Path outputDirectory, String deploymentName) { + Path outputDirectory, String deploymentName, Map controllerConfigs) { List builders = new ArrayList<>(); for (Map.Entry> entry : csvGroups.entrySet()) { final var csvMetadata = entry.getKey(); @@ -57,7 +59,7 @@ public static List prepareGeneration(BundleGenerationConfigura final var mainSourcesRoot = PathsUtil.findMainSourcesRoot(outputDirectory); final var csvBuilder = new CsvManifestsBuilder(csvMetadata, operatorConfiguration, entry.getValue(), - mainSourcesRoot != null ? mainSourcesRoot.getKey() : null, deploymentName); + mainSourcesRoot != null ? mainSourcesRoot.getKey() : null, deploymentName, controllerConfigs); builders.add(csvBuilder); builders.add(new AnnotationsManifestsBuilder(csvMetadata, labels)); builders.add(new BundleDockerfileManifestsBuilder(csvMetadata, labels)); diff --git a/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/BundleProcessor.java b/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/BundleProcessor.java index 8f34ee896..c5362e173 100644 --- a/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/BundleProcessor.java +++ b/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/BundleProcessor.java @@ -32,6 +32,7 @@ import io.quarkiverse.operatorsdk.bundle.runtime.BundleGenerationConfiguration; import io.quarkiverse.operatorsdk.bundle.runtime.CSVMetadataHolder; import io.quarkiverse.operatorsdk.common.*; +import io.quarkiverse.operatorsdk.deployment.ControllerConfigurationsBuildItem; import io.quarkiverse.operatorsdk.deployment.GeneratedCRDInfoBuildItem; import io.quarkiverse.operatorsdk.deployment.VersionBuildItem; import io.quarkiverse.operatorsdk.runtime.BuildTimeOperatorConfiguration; @@ -185,7 +186,8 @@ void generateBundle(ApplicationInfoBuildItem configuration, BuildProducer doneGeneratingCSV, GeneratedCRDInfoBuildItem generatedCustomResourcesDefinitions, DeserializedKubernetesResourcesBuildItem generatedKubernetesResources, - BuildProducer generatedCSVs) { + BuildProducer generatedCSVs, + ControllerConfigurationsBuildItem controllerConfigurationsBuildItem) { final var crds = generatedCustomResourcesDefinitions.getCRDGenerationInfo().getCrds() .values().stream() .flatMap(entry -> entry.values().stream()) @@ -233,7 +235,8 @@ void generateBundle(ApplicationInfoBuildItem configuration, final var deploymentName = ResourceNameUtil.getResourceName(kubernetesConfig, configuration); final var generated = BundleGenerator.prepareGeneration(bundleConfiguration, operatorConfiguration, versionBuildItem.getVersion(), - csvMetadata.getCsvGroups(), crds, outputTarget.getOutputDirectory(), deploymentName); + csvMetadata.getCsvGroups(), crds, outputTarget.getOutputDirectory(), deploymentName, + controllerConfigurationsBuildItem.getControllerConfigs()); generated.forEach(manifestBuilder -> { final var fileName = manifestBuilder.getFileName(); try { diff --git a/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/builders/CsvManifestsBuilder.java b/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/builders/CsvManifestsBuilder.java index 1d2ab1fdd..b74b9e0f1 100644 --- a/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/builders/CsvManifestsBuilder.java +++ b/bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/builders/CsvManifestsBuilder.java @@ -23,12 +23,13 @@ import io.quarkiverse.operatorsdk.bundle.runtime.CSVMetadataHolder.RequiredCRD; import io.quarkiverse.operatorsdk.common.*; import io.quarkiverse.operatorsdk.runtime.BuildTimeOperatorConfiguration; +import io.quarkiverse.operatorsdk.runtime.QuarkusControllerConfiguration; public class CsvManifestsBuilder extends ManifestsBuilder { private static final Logger log = Logger.getLogger(CsvManifestsBuilder.class); - private static final String DEFAULT_INSTALL_MODE = "AllNamespaces"; + private static final String ALL_NAMESPACES = "AllNamespaces"; private static final String DEPLOYMENT = "deployment"; private static final String SERVICE_ACCOUNT_KIND = "ServiceAccount"; private static final String CLUSTER_ROLE_KIND = "ClusterRole"; @@ -37,6 +38,9 @@ public class CsvManifestsBuilder extends ManifestsBuilder { private static final Logger LOGGER = Logger.getLogger(CsvManifestsBuilder.class.getName()); private static final String IMAGE_PNG = "image/png"; public static final String OLM_TARGET_NAMESPACES = "metadata.annotations['olm.targetNamespaces']"; + public static final String OWN_NAMESPACE = "OwnNamespace"; + public static final String SINGLE_NAMESPACE = "SingleNamespace"; + public static final String MULTI_NAMESPACE = "MultiNamespace"; private ClusterServiceVersionBuilder csvBuilder; private final Set ownedCRs = new HashSet<>(); private final Set requiredCRs = new HashSet<>(); @@ -44,9 +48,10 @@ public class CsvManifestsBuilder extends ManifestsBuilder { private final String deploymentName; private final List controllers; + @SuppressWarnings("rawtypes") public CsvManifestsBuilder(CSVMetadataHolder metadata, BuildTimeOperatorConfiguration operatorConfiguration, List controllers, - Path mainSourcesRoot, String deploymentName) { + Path mainSourcesRoot, String deploymentName, Map controllerConfigs) { super(metadata); this.deploymentName = deploymentName; this.controllers = controllers; @@ -54,7 +59,8 @@ public CsvManifestsBuilder(CSVMetadataHolder metadata, BuildTimeOperatorConfigur csvBuilder = new ClusterServiceVersionBuilder(); - final var metadataBuilder = csvBuilder.withNewMetadata().withName(getName()); + final var name = getName(); + final var metadataBuilder = csvBuilder.withNewMetadata().withName(name); if (metadata.annotations != null) { metadataBuilder.addToAnnotations("olm.skipRange", metadata.annotations.skipRange); metadataBuilder.addToAnnotations("containerImage", metadata.annotations.containerImage); @@ -72,7 +78,7 @@ public CsvManifestsBuilder(CSVMetadataHolder metadata, BuildTimeOperatorConfigur final var csvSpecBuilder = csvBuilder .editOrNewSpec() .withDescription(metadata.description) - .withDisplayName(defaultIfEmpty(metadata.displayName, getName())) + .withDisplayName(defaultIfEmpty(metadata.displayName, name)) .withKeywords(metadata.keywords) .withReplaces(metadata.replaces) .withVersion(metadata.version) @@ -135,14 +141,6 @@ public CsvManifestsBuilder(CSVMetadataHolder metadata, BuildTimeOperatorConfigur } } - if (metadata.installModes == null || metadata.installModes.length == 0) { - csvSpecBuilder.addNewInstallMode(true, DEFAULT_INSTALL_MODE); - } else { - for (CSVMetadataHolder.InstallMode installMode : metadata.installModes) { - csvSpecBuilder.addNewInstallMode(installMode.supported, installMode.type); - } - } - // add owned and required CRD, also collect them final var nativeApis = new ArrayList(); controllers.forEach(raci -> { @@ -181,6 +179,29 @@ public CsvManifestsBuilder(CSVMetadataHolder metadata, BuildTimeOperatorConfigur } }); } + + // deal with install modes + // use watched namespaces information for default install mode + // fixme: multiple, incompatible controller configurations in the same bundle will result in inconsistent runs + final var config = controllerConfigs.get(raci.nameOrFailIfUnset()); + if (config.watchAllNamespaces()) { + csvSpecBuilder.withInstallModes(new InstallMode(true, ALL_NAMESPACES)); + } else if (config.watchCurrentNamespace()) { + csvSpecBuilder.withInstallModes(new InstallMode(true, OWN_NAMESPACE)); + } else { + final var namespaces = config.getNamespaces(); + if (namespaces.size() == 1) { + csvSpecBuilder.withInstallModes(new InstallMode(true, SINGLE_NAMESPACE)); + } else { + csvSpecBuilder.withInstallModes(new InstallMode(true, MULTI_NAMESPACE)); + } + } + // then process metadata + if (metadata.installModes != null) { + for (CSVMetadataHolder.InstallMode installMode : metadata.installModes) { + csvSpecBuilder.addNewInstallMode(installMode.supported, installMode.type); + } + } }); // add required CRDs from CSV metadata diff --git a/bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/MultipleOperatorsBundleTest.java b/bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/MultipleOperatorsBundleTest.java index a6ed788e2..a4fe3b77f 100644 --- a/bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/MultipleOperatorsBundleTest.java +++ b/bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/MultipleOperatorsBundleTest.java @@ -1,8 +1,7 @@ package io.quarkiverse.operatorsdk.bundle; import static io.quarkiverse.operatorsdk.bundle.Utils.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import java.io.IOException; @@ -49,6 +48,13 @@ public void shouldWriteBundleForTheOperators() throws IOException { assertEquals(FirstReconciler.REPLACES, csv.getSpec().getReplaces()); var bundleMeta = getAnnotationsFor(bundle, "first-operator"); assertEquals(BUNDLE_PACKAGE, bundleMeta.getAnnotations().get("operators.operatorframework.io.bundle.package.v1")); + assertEquals(2, csv.getSpec().getInstallModes().size()); + var installMode = csv.getSpec().getInstallModes().get(0); + assertEquals("AllNamespaces", installMode.getType()); + assertTrue(installMode.getSupported()); + installMode = csv.getSpec().getInstallModes().get(1); + assertEquals("MultiNamespace", installMode.getType()); + assertFalse(installMode.getSupported()); checkBundleFor(bundle, "second-operator", Second.class); csv = getCSVFor(bundle, "second-operator"); @@ -59,6 +65,10 @@ public void shouldWriteBundleForTheOperators() throws IOException { .addToResources(SecondReconciler.RBAC_RULE_RES) .addToVerbs(SecondReconciler.RBAC_RULE_VERBS) .build())); + assertEquals(1, csv.getSpec().getInstallModes().size()); + installMode = csv.getSpec().getInstallModes().get(0); + assertEquals("SingleNamespace", installMode.getType()); + assertTrue(installMode.getSupported()); checkBundleFor(bundle, "third-operator", Third.class); // also check that external CRD is present diff --git a/bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/sources/FirstReconciler.java b/bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/sources/FirstReconciler.java index cd176cda4..354ec4e00 100644 --- a/bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/sources/FirstReconciler.java +++ b/bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/sources/FirstReconciler.java @@ -5,7 +5,7 @@ import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.quarkiverse.operatorsdk.annotations.CSVMetadata; -@CSVMetadata(name = "first-operator", version = FirstReconciler.VERSION) +@CSVMetadata(name = "first-operator", version = FirstReconciler.VERSION, installModes = @CSVMetadata.InstallMode(type = "MultiNamespace", supported = false)) public class FirstReconciler implements Reconciler { public static final String VERSION = "first-version";