From 339520a293a94cd7e5104364c913c401e05b4a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 22 Nov 2023 13:18:40 +0100 Subject: [PATCH 1/8] chore: change version to 4.7.0-SNAPSHOT (#2132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index f797a7d56f..b82bcc11f4 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index fb5e2c98a1..a63c5889fe 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 3e640e3e7f..6f6669999a 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index e54776b161..75ead60afa 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index b4afcf0d33..dc054d587a 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index a80d03d69e..9366485f25 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index ff38d5fc66..430cc508b2 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 6ca4f9684f..c389c01c2f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index af8589be61..ea18538d30 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index c69c388299..7dba03f3d9 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index f7b1b4dfcb..56c7834d03 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index ffb17e2cda..89e243ba0a 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 8cbac1f178..e0becee1a5 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT sample-webpage-operator From 9da18060c0feba4ff343eedb74173cb1cad18420 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 5 May 2023 15:31:12 +0200 Subject: [PATCH 2/8] feat: namespace deletion issue --- .../operator/NamespaceDeletionIT.java | 112 ++++++++++++++++++ .../NamespaceDeletionTestCustomResource.java | 15 +++ .../NamespaceDeletionTestReconciler.java | 38 ++++++ .../namespacedeletion/role-binding.yaml | 13 ++ .../sample/namespacedeletion/role.yaml | 11 ++ 5 files changed, 189 insertions(+) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/NamespaceDeletionIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/namespacedeletion/NamespaceDeletionTestCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/namespacedeletion/NamespaceDeletionTestReconciler.java create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/namespacedeletion/role-binding.yaml create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/namespacedeletion/role.yaml diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/NamespaceDeletionIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/NamespaceDeletionIT.java new file mode 100644 index 0000000000..44d8b372d0 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/NamespaceDeletionIT.java @@ -0,0 +1,112 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; + +import io.fabric8.kubernetes.api.model.Namespace; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.rbac.Role; +import io.fabric8.kubernetes.api.model.rbac.RoleBinding; +import io.fabric8.kubernetes.client.ConfigBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; +import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.namespacedeletion.NamespaceDeletionTestCustomResource; +import io.javaoperatorsdk.operator.sample.namespacedeletion.NamespaceDeletionTestReconciler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class NamespaceDeletionIT { + + KubernetesClient adminClient = new KubernetesClientBuilder().build(); + + KubernetesClient client = new KubernetesClientBuilder() + .withConfig(new ConfigBuilder() + .withImpersonateUsername("namespace-deletion-test-user") + .build()) + .build(); + + String actualNamespace; + Operator operator; + + @BeforeEach + void beforeEach(TestInfo testInfo) { + LocallyRunOperatorExtension.applyCrd(NamespaceDeletionTestCustomResource.class, + adminClient); + + testInfo.getTestMethod().ifPresent(method -> { + actualNamespace = KubernetesResourceUtil.sanitizeName(method.getName()); + adminClient.resource(namespace()).create(); + }); + + applyRBACResources(); + operator = new Operator(client); + operator.register(new NamespaceDeletionTestReconciler(), + o -> o.settingNamespaces(actualNamespace)); + operator.start(); + } + + @AfterEach + void cleanup() { + if (operator != null) { + operator.stop(Duration.ofSeconds(1)); + } + } + + @Test + void testDeletingNamespaceWithRolesForOperator() { + var res = adminClient.resource(testResource()).create(); + + await().untilAsserted(() -> { + var actual = adminClient.resource(res).get(); + assertThat(actual.getMetadata().getFinalizers()).isNotEmpty(); + }); + + adminClient.resource(namespace()).delete(); + + await().untilAsserted(() -> { + var actual = adminClient.resource(res).get(); + assertThat(actual).isNull(); + }); + } + + NamespaceDeletionTestCustomResource testResource() { + NamespaceDeletionTestCustomResource resource = new NamespaceDeletionTestCustomResource(); + resource.setMetadata(new ObjectMetaBuilder() + .withName("test1") + .withNamespace(actualNamespace) + .build()); + return resource; + } + + private Namespace namespace() { + return namespace(actualNamespace); + } + + private Namespace namespace(String name) { + Namespace n = new Namespace(); + n.setMetadata(new ObjectMetaBuilder() + .withName(name) + .withName(actualNamespace) + .build()); + return n; + } + + private void applyRBACResources() { + var role = ReconcilerUtils + .loadYaml(Role.class, NamespaceDeletionTestReconciler.class, "role.yaml"); + role.getMetadata().setNamespace(actualNamespace); + adminClient.resource(role).create(); + + var roleBinding = ReconcilerUtils + .loadYaml(RoleBinding.class, NamespaceDeletionTestReconciler.class, "role-binding.yaml"); + roleBinding.getMetadata().setNamespace(actualNamespace); + adminClient.resource(roleBinding).create(); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/namespacedeletion/NamespaceDeletionTestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/namespacedeletion/NamespaceDeletionTestCustomResource.java new file mode 100644 index 0000000000..06a0758b0b --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/namespacedeletion/NamespaceDeletionTestCustomResource.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.namespacedeletion; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("ndt") +public class NamespaceDeletionTestCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/namespacedeletion/NamespaceDeletionTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/namespacedeletion/NamespaceDeletionTestReconciler.java new file mode 100644 index 0000000000..1682321b4d --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/namespacedeletion/NamespaceDeletionTestReconciler.java @@ -0,0 +1,38 @@ +package io.javaoperatorsdk.operator.sample.namespacedeletion; + +import java.util.concurrent.atomic.AtomicInteger; + +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; + +@ControllerConfiguration +public class NamespaceDeletionTestReconciler + implements Reconciler, TestExecutionInfoProvider, + Cleaner { + + public static final int CLEANER_WAIT_PERIOD = 300; + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + + @Override + public UpdateControl reconcile( + NamespaceDeletionTestCustomResource resource, + Context context) { + numberOfExecutions.addAndGet(1); + return UpdateControl.noUpdate(); + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + + @Override + public DeleteControl cleanup(NamespaceDeletionTestCustomResource resource, + Context context) { + try { + Thread.sleep(CLEANER_WAIT_PERIOD); + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } + return DeleteControl.defaultDelete(); + } +} diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/namespacedeletion/role-binding.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/namespacedeletion/role-binding.yaml new file mode 100644 index 0000000000..78ae143932 --- /dev/null +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/namespacedeletion/role-binding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace. +kind: RoleBinding +metadata: + name: namespace-deletion +subjects: + - kind: User + name: namespace-deletion-test-user + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: Role + name: namespace-deletion-test + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/namespacedeletion/role.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/namespacedeletion/role.yaml new file mode 100644 index 0000000000..de6a9dd036 --- /dev/null +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/namespacedeletion/role.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: namespace-deletion-test +rules: + - apiGroups: [ "sample.javaoperatorsdk" ] + resources: [ "namespacedeletiontestcustomresources" ] + verbs: [ "get", "watch", "list", "post", "update", "patch", "delete" ] + + From 39f6793b3973b113eeb636d6c102255f113781a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 12 Dec 2023 14:11:56 +0100 Subject: [PATCH 3/8] skeleton of resource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- ...ceDeletionRoleBindingHandlerReconciler.java | 16 ++++++++++++++++ ...NamespaceDeletionRoleHandlerReconciler.java | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingHandlerReconciler.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleHandlerReconciler.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingHandlerReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingHandlerReconciler.java new file mode 100644 index 0000000000..08d6e16350 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingHandlerReconciler.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.operator.support; + +import io.fabric8.kubernetes.api.model.rbac.RoleBinding; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; + +public class NamespaceDeletionRoleBindingHandlerReconciler implements Reconciler { + + @Override + public UpdateControl reconcile(RoleBinding resource, Context context) + throws Exception { + + return UpdateControl.noUpdate(); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleHandlerReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleHandlerReconciler.java new file mode 100644 index 0000000000..f5d7f68fdc --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleHandlerReconciler.java @@ -0,0 +1,18 @@ +package io.javaoperatorsdk.operator.support; + +import io.fabric8.kubernetes.api.model.rbac.Role; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; + +@ControllerConfiguration +public class NamespaceDeletionRoleHandlerReconciler implements Reconciler { + + @Override + public UpdateControl reconcile(Role resource, Context context) throws Exception { + + + return UpdateControl.noUpdate(); + } +} From a4a7ece43fc67521810ac8d1f4f9eb748c7c6f79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 12 Dec 2023 15:00:41 +0100 Subject: [PATCH 4/8] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- ...eDeletionRoleBindingHandlerReconciler.java | 16 ------ ...amespaceDeletionRoleBindingReconciler.java | 20 ++++++++ ...amespaceDeletionRoleHandlerReconciler.java | 18 ------- .../NamespaceDeletionRoleReconciler.java | 50 +++++++++++++++++++ 4 files changed, 70 insertions(+), 34 deletions(-) delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingHandlerReconciler.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleHandlerReconciler.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingHandlerReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingHandlerReconciler.java deleted file mode 100644 index 08d6e16350..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingHandlerReconciler.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.javaoperatorsdk.operator.support; - -import io.fabric8.kubernetes.api.model.rbac.RoleBinding; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; - -public class NamespaceDeletionRoleBindingHandlerReconciler implements Reconciler { - - @Override - public UpdateControl reconcile(RoleBinding resource, Context context) - throws Exception { - - return UpdateControl.noUpdate(); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java new file mode 100644 index 0000000000..03cb196631 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.support; + +import io.fabric8.kubernetes.api.model.rbac.RoleBinding; +import io.javaoperatorsdk.operator.api.reconciler.*; + +@ControllerConfiguration(labelSelector = "") +public class NamespaceDeletionRoleBindingReconciler implements Reconciler, Cleaner { + + @Override + public UpdateControl reconcile(RoleBinding resource, Context context) + throws Exception { + + return UpdateControl.noUpdate(); + } + + @Override + public DeleteControl cleanup(RoleBinding resource, Context context) { + return null; + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleHandlerReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleHandlerReconciler.java deleted file mode 100644 index f5d7f68fdc..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleHandlerReconciler.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.javaoperatorsdk.operator.support; - -import io.fabric8.kubernetes.api.model.rbac.Role; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; - -@ControllerConfiguration -public class NamespaceDeletionRoleHandlerReconciler implements Reconciler { - - @Override - public UpdateControl reconcile(Role resource, Context context) throws Exception { - - - return UpdateControl.noUpdate(); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java new file mode 100644 index 0000000000..21ceda77ed --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java @@ -0,0 +1,50 @@ +package io.javaoperatorsdk.operator.support; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.rbac.Role; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; +import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@ControllerConfiguration +public class NamespaceDeletionRoleReconciler implements Reconciler, Cleaner, EventSourceInitializer { + + List> resourceClasses; + + public NamespaceDeletionRoleReconciler(List> resourceClasses) { + this.resourceClasses = resourceClasses; + } + + @Override + public UpdateControl reconcile(Role resource, Context context) throws Exception { + return UpdateControl.noUpdate(); + } + + @Override + public DeleteControl cleanup(Role resource, Context context) { + return null; + } + + @SuppressWarnings({"rawtypes","unchecked"}) + @Override + public Map prepareEventSources(EventSourceContext context) { + + return resourceClasses.stream().map(c-> new InformerEventSource(InformerConfiguration.from(c,context) + .withPrimaryToSecondaryMapper(primary -> { + + return null; + }) + .withSecondaryToPrimaryMapper((SecondaryToPrimaryMapper) resource -> null) + .build(),context)).collect(Collectors.toMap(i->i.resourceType().getName(),i->i)); + + } +} From 4a41c88aac57475b6b13a9ff917713b5d6352994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 12 Dec 2023 17:09:08 +0100 Subject: [PATCH 5/8] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- ...amespaceDeletionRoleBindingReconciler.java | 3 +- .../NamespaceDeletionRoleReconciler.java | 40 +++++++++++-------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java index 03cb196631..eff62cc22e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java @@ -4,7 +4,8 @@ import io.javaoperatorsdk.operator.api.reconciler.*; @ControllerConfiguration(labelSelector = "") -public class NamespaceDeletionRoleBindingReconciler implements Reconciler, Cleaner { +public class NamespaceDeletionRoleBindingReconciler + implements Reconciler, Cleaner { @Override public UpdateControl reconcile(RoleBinding resource, Context context) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java index 21ceda77ed..5d936998fd 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java @@ -1,27 +1,30 @@ package io.javaoperatorsdk.operator.support; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.rbac.Role; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; +import static io.fabric8.kubernetes.api.model.HasMetadata.getPlural; @ControllerConfiguration -public class NamespaceDeletionRoleReconciler implements Reconciler, Cleaner, EventSourceInitializer { +public class NamespaceDeletionRoleReconciler + implements Reconciler, Cleaner, EventSourceInitializer { - List> resourceClasses; + final List> resourceClasses; + final Map, String> plurals; public NamespaceDeletionRoleReconciler(List> resourceClasses) { this.resourceClasses = resourceClasses; + this.plurals = + resourceClasses.stream().collect(Collectors.toMap(c -> c, HasMetadata::getPlural)); } @Override @@ -34,17 +37,22 @@ public DeleteControl cleanup(Role resource, Context context) { return null; } - @SuppressWarnings({"rawtypes","unchecked"}) + @SuppressWarnings({"rawtypes", "unchecked"}) @Override public Map prepareEventSources(EventSourceContext context) { - - return resourceClasses.stream().map(c-> new InformerEventSource(InformerConfiguration.from(c,context) - .withPrimaryToSecondaryMapper(primary -> { - - return null; + // var allPlurals = plurals.values(); + // context.getPrimaryCache().addIndexer("namespace-target-resource-index", r-> { + // r.getRules().stream().map() // todo + // + // }); + + return resourceClasses.stream() + .map(c -> new InformerEventSource(InformerConfiguration.from(c, context) + .withSecondaryToPrimaryMapper((SecondaryToPrimaryMapper) resource -> { + return null; }) - .withSecondaryToPrimaryMapper((SecondaryToPrimaryMapper) resource -> null) - .build(),context)).collect(Collectors.toMap(i->i.resourceType().getName(),i->i)); + .build(), context)) + .collect(Collectors.toMap(i -> plurals.get(i.resourceType()), i -> i)); } } From bbce6bc107afd3e03f94b60174c063bd0d3ab815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 13 Dec 2023 13:38:56 +0100 Subject: [PATCH 6/8] indexes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../NamespaceDeletionRoleReconciler.java | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java index 5d936998fd..9a81f4c08f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java @@ -1,23 +1,31 @@ package io.javaoperatorsdk.operator.support; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.rbac.Role; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import static io.fabric8.kubernetes.api.model.HasMetadata.getPlural; +// todo filters @ControllerConfiguration public class NamespaceDeletionRoleReconciler implements Reconciler, Cleaner, EventSourceInitializer { + public static final String TARGET_RESOURCES_IN_NAMESPACE_TO_ROLE_INDEX = "target-resources-in-namespace"; + public static final String RESOURCE_NAMESPACE_INDEX = "resource-namespace-index"; + final List> resourceClasses; final Map, String> plurals; @@ -34,25 +42,46 @@ public UpdateControl reconcile(Role resource, Context context) throw @Override public DeleteControl cleanup(Role resource, Context context) { - return null; + + + return DeleteControl.defaultDelete(); } @SuppressWarnings({"rawtypes", "unchecked"}) @Override public Map prepareEventSources(EventSourceContext context) { - // var allPlurals = plurals.values(); - // context.getPrimaryCache().addIndexer("namespace-target-resource-index", r-> { - // r.getRules().stream().map() // todo - // - // }); + var allPlurals = plurals.values(); + context.getPrimaryCache().addIndexer(TARGET_RESOURCES_IN_NAMESPACE_TO_ROLE_INDEX, r-> { + // resource-plural+namespace -> role (in that namespace) + List result = new ArrayList<>(); + r.getRules().forEach(rule->{ + rule.getResources().forEach(resource-> { + if (allPlurals.contains(resource)) { + result.add(keyFor(r.getMetadata().getNamespace(),resource)); + } + }); + }); + return result; + }); return resourceClasses.stream() - .map(c -> new InformerEventSource(InformerConfiguration.from(c, context) + .map(c -> { var ies = new InformerEventSource(InformerConfiguration.from(c, context) .withSecondaryToPrimaryMapper((SecondaryToPrimaryMapper) resource -> { - return null; + HasMetadata rm = (HasMetadata) resource; + var roles = context.getPrimaryCache().byIndex(TARGET_RESOURCES_IN_NAMESPACE_TO_ROLE_INDEX, + keyFor(rm.getMetadata().getNamespace(),rm.getPlural())); + return roles.stream().map(r->new ResourceID(r.getMetadata().getName(), + r.getMetadata().getNamespace())).collect(Collectors.toSet()); }) - .build(), context)) + .build(), context); + ies.addIndexer(RESOURCE_NAMESPACE_INDEX, r-> List.of(r.getMetadata().getNamespace())); + return ies; + }) .collect(Collectors.toMap(i -> plurals.get(i.resourceType()), i -> i)); + } + public static String keyFor(String namespace, String resourcePlural) { + return resourcePlural+"-"+namespace; } + } From 40f66397c520fa76d0e231a03792c449a6345220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 13 Dec 2023 13:57:11 +0100 Subject: [PATCH 7/8] format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../NamespaceDeletionRoleReconciler.java | 92 ++++++++++++------- 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java index 9a81f4c08f..8bb1df994a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java @@ -4,7 +4,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Function; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import io.fabric8.kubernetes.api.model.HasMetadata; @@ -16,23 +16,28 @@ import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; -import static io.fabric8.kubernetes.api.model.HasMetadata.getPlural; - // todo filters @ControllerConfiguration public class NamespaceDeletionRoleReconciler implements Reconciler, Cleaner, EventSourceInitializer { - public static final String TARGET_RESOURCES_IN_NAMESPACE_TO_ROLE_INDEX = "target-resources-in-namespace"; + public static final String TARGET_RESOURCES_IN_NAMESPACE_TO_ROLE_INDEX = + "target-resources-in-namespace"; public static final String RESOURCE_NAMESPACE_INDEX = "resource-namespace-index"; final List> resourceClasses; - final Map, String> plurals; + final Set resourcePlurals; + final Map, String> classToPlural; + final Map> pluralToClass; public NamespaceDeletionRoleReconciler(List> resourceClasses) { this.resourceClasses = resourceClasses; - this.plurals = + this.classToPlural = resourceClasses.stream().collect(Collectors.toMap(c -> c, HasMetadata::getPlural)); + this.pluralToClass = + resourceClasses.stream().collect(Collectors.toMap(HasMetadata::getPlural, c -> c)); + this.resourcePlurals = + resourceClasses.stream().map(HasMetadata::getPlural).collect(Collectors.toSet()); } @Override @@ -40,48 +45,67 @@ public UpdateControl reconcile(Role resource, Context context) throw return UpdateControl.noUpdate(); } + @SuppressWarnings("unchecked") @Override public DeleteControl cleanup(Role resource, Context context) { - - - return DeleteControl.defaultDelete(); + AtomicBoolean watchedResourceExistsInNamespace = new AtomicBoolean(false); + resource.getRules().forEach(rule -> { + rule.getResources().forEach(r -> { + if (resourcePlurals.contains(r)) { + InformerEventSource es = + (InformerEventSource) context.eventSourceRetriever() + .getResourceEventSourceFor(pluralToClass.get(r)); + var resources = + es.byIndex(RESOURCE_NAMESPACE_INDEX, resource.getMetadata().getNamespace()); + if (!resources.isEmpty()) { + watchedResourceExistsInNamespace.set(true); + } + } + }); + }); + if (watchedResourceExistsInNamespace.get()) { + return DeleteControl.noFinalizerRemoval(); + } else { + return DeleteControl.defaultDelete(); + } } @SuppressWarnings({"rawtypes", "unchecked"}) @Override public Map prepareEventSources(EventSourceContext context) { - var allPlurals = plurals.values(); - context.getPrimaryCache().addIndexer(TARGET_RESOURCES_IN_NAMESPACE_TO_ROLE_INDEX, r-> { - // resource-plural+namespace -> role (in that namespace) - List result = new ArrayList<>(); - r.getRules().forEach(rule->{ - rule.getResources().forEach(resource-> { - if (allPlurals.contains(resource)) { - result.add(keyFor(r.getMetadata().getNamespace(),resource)); - } - }); - }); - return result; - }); + var allPlurals = classToPlural.values(); + context.getPrimaryCache().addIndexer(TARGET_RESOURCES_IN_NAMESPACE_TO_ROLE_INDEX, r -> { + // resource-plural+namespace -> role (in that namespace) + List result = new ArrayList<>(); + r.getRules().forEach(rule -> rule.getResources().forEach(resource -> { + if (allPlurals.contains(resource)) { + result.add(keyFor(r.getMetadata().getNamespace(), resource)); + } + })); + return result; + }); return resourceClasses.stream() - .map(c -> { var ies = new InformerEventSource(InformerConfiguration.from(c, context) - .withSecondaryToPrimaryMapper((SecondaryToPrimaryMapper) resource -> { - HasMetadata rm = (HasMetadata) resource; - var roles = context.getPrimaryCache().byIndex(TARGET_RESOURCES_IN_NAMESPACE_TO_ROLE_INDEX, - keyFor(rm.getMetadata().getNamespace(),rm.getPlural())); - return roles.stream().map(r->new ResourceID(r.getMetadata().getName(), - r.getMetadata().getNamespace())).collect(Collectors.toSet()); - }) - .build(), context); - ies.addIndexer(RESOURCE_NAMESPACE_INDEX, r-> List.of(r.getMetadata().getNamespace())); + .map(c -> { + var ies = + new InformerEventSource(InformerConfiguration.from(c, context) + .withSecondaryToPrimaryMapper((SecondaryToPrimaryMapper) resource -> { + HasMetadata rm = (HasMetadata) resource; + var roles = context.getPrimaryCache().byIndex( + TARGET_RESOURCES_IN_NAMESPACE_TO_ROLE_INDEX, + keyFor(rm.getMetadata().getNamespace(), rm.getPlural())); + return roles.stream().map(r -> new ResourceID(r.getMetadata().getName(), + r.getMetadata().getNamespace())).collect(Collectors.toSet()); + }) + .build(), context); + ies.addIndexer(RESOURCE_NAMESPACE_INDEX, r -> List.of(r.getMetadata().getNamespace())); return ies; }) - .collect(Collectors.toMap(i -> plurals.get(i.resourceType()), i -> i)); + .collect(Collectors.toMap(i -> classToPlural.get(i.resourceType()), i -> i)); } public static String keyFor(String namespace, String resourcePlural) { - return resourcePlural+"-"+namespace; + return resourcePlural + "-" + namespace; } } From 7bd6ff8c16b31906072c4749b7cad629800ed214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 13 Dec 2023 14:20:10 +0100 Subject: [PATCH 8/8] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../NamespaceDeletionRoleBindingReconciler.java | 3 ++- .../support/NamespaceDeletionRoleReconciler.java | 5 +++-- .../support/NonMarkedForDeletionAddFilter.java | 12 ++++++++++++ .../support/NonMarkedForDeletionUpdateFilter.java | 12 ++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NonMarkedForDeletionAddFilter.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NonMarkedForDeletionUpdateFilter.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java index eff62cc22e..eda579d80a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleBindingReconciler.java @@ -3,7 +3,8 @@ import io.fabric8.kubernetes.api.model.rbac.RoleBinding; import io.javaoperatorsdk.operator.api.reconciler.*; -@ControllerConfiguration(labelSelector = "") +// todo handle also ClusterRole bindings only if has permission +@ControllerConfiguration public class NamespaceDeletionRoleBindingReconciler implements Reconciler, Cleaner { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java index 8bb1df994a..1ef4344d1f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NamespaceDeletionRoleReconciler.java @@ -16,8 +16,9 @@ import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; -// todo filters -@ControllerConfiguration +// todo label selector needs to added explicitly +@ControllerConfiguration(onAddFilter = NonMarkedForDeletionAddFilter.class, + onUpdateFilter = NonMarkedForDeletionUpdateFilter.class) public class NamespaceDeletionRoleReconciler implements Reconciler, Cleaner, EventSourceInitializer { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NonMarkedForDeletionAddFilter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NonMarkedForDeletionAddFilter.java new file mode 100644 index 0000000000..c409e0d803 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NonMarkedForDeletionAddFilter.java @@ -0,0 +1,12 @@ +package io.javaoperatorsdk.operator.support; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter; + +public class NonMarkedForDeletionAddFilter implements OnAddFilter { + @Override + public boolean accept(T resource) { + return resource.getMetadata().getDeletionTimestamp() != null; + } + +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NonMarkedForDeletionUpdateFilter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NonMarkedForDeletionUpdateFilter.java new file mode 100644 index 0000000000..0bb9cf83ea --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/support/NonMarkedForDeletionUpdateFilter.java @@ -0,0 +1,12 @@ +package io.javaoperatorsdk.operator.support; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter; + +public class NonMarkedForDeletionUpdateFilter implements OnUpdateFilter { + + @Override + public boolean accept(T newResource, T oldResource) { + return newResource.getMetadata().getDeletionTimestamp() != null; + } +}