From bc0aabf17fb0d71bb39485aacd0333719ae950f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 14 Nov 2024 23:06:08 +0100 Subject: [PATCH 1/4] improve: simpler api for adding additional CRD file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../junit/LocallyRunOperatorExtension.java | 77 +++++++++++-------- .../operator/CRDMappingInTestExtensionIT.java | 2 +- .../src/test/{ => resources}/crd/test.crd | 0 3 files changed, 47 insertions(+), 32 deletions(-) rename operator-framework/src/test/{ => resources}/crd/test.crd (100%) diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java index 442e398d83..9eb1225b9a 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java @@ -2,6 +2,7 @@ import java.io.ByteArrayInputStream; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -21,6 +22,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition; import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.LocalPortForward; @@ -45,7 +47,7 @@ public class LocallyRunOperatorExtension extends AbstractOperatorExtension { private final List localPortForwards; private final List> additionalCustomResourceDefinitions; private final Map registeredControllers; - private final Map crdMappings; + private final List additionalCrds; private LocallyRunOperatorExtension( List reconcilers, @@ -60,7 +62,7 @@ private LocallyRunOperatorExtension( Consumer configurationServiceOverrider, Function namespaceNameSupplier, Function perClassNamespaceNameSupplier, - Map crdMappings) { + List additionalCrds) { super( infrastructure, infrastructureTimeout, @@ -80,7 +82,7 @@ private LocallyRunOperatorExtension( : overrider -> overrider.withKubernetesClient(kubernetesClient); this.operator = new Operator(configurationServiceOverrider); this.registeredControllers = new HashMap<>(); - this.crdMappings = crdMappings; + this.additionalCrds = additionalCrds; } /** @@ -119,6 +121,10 @@ public static void applyCrd(String resourceTypeName, KubernetesClient client) { } } + public static void applyCrd(CustomResourceDefinition crd, KubernetesClient client) { + client.resource(crd).serverSideApply(); + } + private static void applyCrd(InputStream is, String path, KubernetesClient client) { try { if (is == null) { @@ -138,6 +144,16 @@ private static void applyCrd(InputStream is, String path, KubernetesClient clien } } + public static CustomResourceDefinition parseCrd(String path, KubernetesClient client) { + try (InputStream is = new FileInputStream(path)) { + return (CustomResourceDefinition) client.load(new ByteArrayInputStream(is.readAllBytes())); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + private Stream reconcilers() { return reconcilers.stream().map(reconcilerSpec -> reconcilerSpec.reconciler); } @@ -190,7 +206,7 @@ protected void before(ExtensionContext context) { } additionalCustomResourceDefinitions.forEach(this::applyCrd); - + Map unappliedCRDs = getAdditionalCRDsFromFiles(); for (var ref : reconcilers) { final var config = operator.getConfigurationService().getConfigurationFor(ref.reconciler); final var oconfig = override(config); @@ -207,29 +223,40 @@ protected void before(ExtensionContext context) { ref.controllerConfigurationOverrider.accept(oconfig); } - final var unapplied = new HashMap<>(crdMappings); final var resourceTypeName = ReconcilerUtils.getResourceTypeName(resourceClass); // only try to apply a CRD for the reconciler if it is associated to a CR if (CustomResource.class.isAssignableFrom(resourceClass)) { - applyCrd(resourceTypeName); - unapplied.remove(resourceTypeName); + if (unappliedCRDs.get(resourceTypeName) != null) { + applyCrd(resourceTypeName); + unappliedCRDs.remove(resourceTypeName); + } else { + applyCrd(resourceClass); + } } // apply yet unapplied CRDs - unapplied.keySet().forEach(this::applyCrd); - var registeredController = this.operator.register(ref.reconciler, oconfig.build()); registeredControllers.put(ref.reconciler, registeredController); } + unappliedCRDs.keySet().forEach(this::applyCrd); LOGGER.debug("Starting the operator locally"); this.operator.start(); } + private Map getAdditionalCRDsFromFiles() { + Map crdMappings = new HashMap<>(); + additionalCrds.forEach(p -> { + var crd = parseCrd(p, getKubernetesClient()); + crdMappings.put(crd.getMetadata().getName(), crd); + }); + return crdMappings; + } + /** * Applies the CRD associated with the specified custom resource, first checking if a CRD has been - * manually specified using {@link Builder#withCRDMapping(Class, String)}, otherwise assuming that - * its CRD should be found in the standard location as explained in + * manually specified using {@link Builder#withAdditionalCRD(String)}, otherwise assuming that its + * CRD should be found in the standard location as explained in * {@link LocallyRunOperatorExtension#applyCrd(String, KubernetesClient)} * * @param crClass the custom resource class for which we want to apply the CRD @@ -239,16 +266,7 @@ public void applyCrd(Class crClass) { } public void applyCrd(String resourceTypeName) { - final var path = crdMappings.get(resourceTypeName); - if (path != null) { - try (InputStream inputStream = new FileInputStream(path)) { - applyCrd(inputStream, path, getKubernetesClient()); - } catch (IOException e) { - throw new IllegalStateException("Cannot apply CRD yaml: " + path, e); - } - } else { - applyCrd(resourceTypeName, getKubernetesClient()); - } + applyCrd(resourceTypeName, getKubernetesClient()); } @Override @@ -277,6 +295,7 @@ public static class Builder extends AbstractBuilder { private final List portForwards; private final List> additionalCustomResourceDefinitions; private final Map crdMappings; + private final List additionalCRDs = new ArrayList<>(); private KubernetesClient kubernetesClient; protected Builder() { @@ -338,14 +357,9 @@ public Builder withAdditionalCustomResourceDefinition( additionalCustomResourceDefinitions.add(customResource); return this; } - - public Builder withCRDMapping(Class customResourceClass, - String path) { - return withCRDMapping(ReconcilerUtils.getResourceTypeName(customResourceClass), path); - } - - public Builder withCRDMapping(String resourceTypeName, String path) { - crdMappings.put(resourceTypeName, path); + + public Builder withAdditionalCRD(String path) { + additionalCRDs.add(path); return this; } @@ -360,8 +374,9 @@ public LocallyRunOperatorExtension build() { waitForNamespaceDeletion, oneNamespacePerClass, kubernetesClient, - configurationServiceOverrider, namespaceNameSupplier, perClassNamespaceNameSupplier, - crdMappings); + configurationServiceOverrider, namespaceNameSupplier, + perClassNamespaceNameSupplier, + additionalCRDs); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/CRDMappingInTestExtensionIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/CRDMappingInTestExtensionIT.java index a722f34b92..0a94b90b8a 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/CRDMappingInTestExtensionIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/CRDMappingInTestExtensionIT.java @@ -28,7 +28,7 @@ public class CRDMappingInTestExtensionIT { LocallyRunOperatorExtension operator = LocallyRunOperatorExtension.builder() .withReconciler(new TestReconciler()) - .withCRDMapping("tests.crd.example", "src/test/crd/test.crd") + .withAdditionalCRD("src/test/resource/crd/test.crd") .build(); @Test diff --git a/operator-framework/src/test/crd/test.crd b/operator-framework/src/test/resources/crd/test.crd similarity index 100% rename from operator-framework/src/test/crd/test.crd rename to operator-framework/src/test/resources/crd/test.crd From 72309ce26542151da78f909ffd86d1a3df20527d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 14 Nov 2024 23:08:58 +0100 Subject: [PATCH 2/4] format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/junit/LocallyRunOperatorExtension.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java index 9eb1225b9a..5220381320 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java @@ -357,7 +357,7 @@ public Builder withAdditionalCustomResourceDefinition( additionalCustomResourceDefinitions.add(customResource); return this; } - + public Builder withAdditionalCRD(String path) { additionalCRDs.add(path); return this; From 208d1d2486f72ccfd3fb18a42c74ed031b55e0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 14 Nov 2024 23:36:44 +0100 Subject: [PATCH 3/4] fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/junit/LocallyRunOperatorExtension.java | 3 ++- .../javaoperatorsdk/operator/CRDMappingInTestExtensionIT.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java index 5220381320..b703c0e388 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java @@ -146,7 +146,8 @@ private static void applyCrd(InputStream is, String path, KubernetesClient clien public static CustomResourceDefinition parseCrd(String path, KubernetesClient client) { try (InputStream is = new FileInputStream(path)) { - return (CustomResourceDefinition) client.load(new ByteArrayInputStream(is.readAllBytes())); + return (CustomResourceDefinition) client.load(new ByteArrayInputStream(is.readAllBytes())) + .items().get(0); } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/CRDMappingInTestExtensionIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/CRDMappingInTestExtensionIT.java index 0a94b90b8a..09b52f1078 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/CRDMappingInTestExtensionIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/CRDMappingInTestExtensionIT.java @@ -28,7 +28,7 @@ public class CRDMappingInTestExtensionIT { LocallyRunOperatorExtension operator = LocallyRunOperatorExtension.builder() .withReconciler(new TestReconciler()) - .withAdditionalCRD("src/test/resource/crd/test.crd") + .withAdditionalCRD("src/test/resources/crd/test.crd") .build(); @Test From e0ae283358719ae47141639260da97834bbb6837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Fri, 15 Nov 2024 18:08:04 +0100 Subject: [PATCH 4/4] improve: more crd in one file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/junit/LocallyRunOperatorExtension.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java index b703c0e388..c36a16cd38 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java @@ -144,10 +144,10 @@ private static void applyCrd(InputStream is, String path, KubernetesClient clien } } - public static CustomResourceDefinition parseCrd(String path, KubernetesClient client) { + public static List parseCrds(String path, KubernetesClient client) { try (InputStream is = new FileInputStream(path)) { - return (CustomResourceDefinition) client.load(new ByteArrayInputStream(is.readAllBytes())) - .items().get(0); + return client.load(new ByteArrayInputStream(is.readAllBytes())) + .items().stream().map(i -> (CustomResourceDefinition) i).collect(Collectors.toList()); } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { @@ -248,8 +248,8 @@ protected void before(ExtensionContext context) { private Map getAdditionalCRDsFromFiles() { Map crdMappings = new HashMap<>(); additionalCrds.forEach(p -> { - var crd = parseCrd(p, getKubernetesClient()); - crdMappings.put(crd.getMetadata().getName(), crd); + var crds = parseCrds(p, getKubernetesClient()); + crds.forEach(c -> crdMappings.put(c.getMetadata().getName(), c)); }); return crdMappings; }