Skip to content

Commit

Permalink
feat: namespace deletion issue
Browse files Browse the repository at this point in the history
  • Loading branch information
csviri committed May 5, 2023
1 parent 2e0d5af commit f3c558d
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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<Void, Void>
implements Namespaced {
}
Original file line number Diff line number Diff line change
@@ -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<NamespaceDeletionTestCustomResource>, TestExecutionInfoProvider,
Cleaner<NamespaceDeletionTestCustomResource> {

public static final int CLEANER_WAIT_PERIOD = 300;
private final AtomicInteger numberOfExecutions = new AtomicInteger(0);

@Override
public UpdateControl<NamespaceDeletionTestCustomResource> reconcile(
NamespaceDeletionTestCustomResource resource,
Context<NamespaceDeletionTestCustomResource> context) {
numberOfExecutions.addAndGet(1);
return UpdateControl.noUpdate();
}

public int getNumberOfExecutions() {
return numberOfExecutions.get();
}

@Override
public DeleteControl cleanup(NamespaceDeletionTestCustomResource resource,
Context<NamespaceDeletionTestCustomResource> context) {
try {
Thread.sleep(CLEANER_WAIT_PERIOD);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return DeleteControl.defaultDelete();
}
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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" ]


0 comments on commit f3c558d

Please sign in to comment.