diff --git a/operator/overlays/default-namespace/kustomization.yaml b/operator/overlays/default-namespace/kustomization.yaml index cbec1674ec..20498a818c 100644 --- a/operator/overlays/default-namespace/kustomization.yaml +++ b/operator/overlays/default-namespace/kustomization.yaml @@ -5,3 +5,15 @@ resources: - ../../target namespace: default + +transformers: +- |- + apiVersion: builtin + kind: NamespaceTransformer + metadata: + name: notImportantHere + namespace: default + setRoleBindingSubjects: allServiceAccounts + fieldSpecs: + - path: metadata/namespace + create: true diff --git a/operator/src/main/kubernetes/kubernetes.yml b/operator/src/main/kubernetes/kubernetes.yml index c1d2259234..45c60438c5 100644 --- a/operator/src/main/kubernetes/kubernetes.yml +++ b/operator/src/main/kubernetes/kubernetes.yml @@ -58,6 +58,12 @@ rules: - delete - patch - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: keycloak-operator-clusterrole +rules: - apiGroups: - config.openshift.io resources: @@ -78,3 +84,18 @@ roleRef: subjects: - kind: ServiceAccount name: keycloak-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: keycloak-operator + name: keycloak-operator-clusterrole-binding +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: keycloak-operator-clusterrole +subjects: + - kind: ServiceAccount + name: keycloak-operator + namespace: keycloak diff --git a/operator/src/test/java/org/keycloak/operator/testsuite/integration/BaseOperatorTest.java b/operator/src/test/java/org/keycloak/operator/testsuite/integration/BaseOperatorTest.java index 795fb71bfb..4eb588763c 100644 --- a/operator/src/test/java/org/keycloak/operator/testsuite/integration/BaseOperatorTest.java +++ b/operator/src/test/java/org/keycloak/operator/testsuite/integration/BaseOperatorTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.api.model.PodTemplateSpecFluent.SpecNested; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.KubernetesClient; @@ -62,6 +63,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; +import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.time.Duration; @@ -69,6 +71,7 @@ import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.stream.Stream; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.inject.spi.CDI; @@ -151,7 +154,12 @@ public class BaseOperatorTest implements QuarkusTestAfterEachCallback { private static void createRBACresourcesAndOperatorDeployment() throws FileNotFoundException { Log.info("Creating RBAC and Deployment into Namespace " + namespace); - K8sUtils.set(k8sclient, new FileInputStream(TARGET_KUBERNETES_GENERATED_YML_FOLDER + deploymentTarget + ".yml")); + K8sUtils.set(k8sclient, new FileInputStream(TARGET_KUBERNETES_GENERATED_YML_FOLDER + deploymentTarget + ".yml"), obj -> { + if (obj instanceof ClusterRoleBinding) { + ((ClusterRoleBinding)obj).getSubjects().forEach(s -> s.setNamespace(namespace)); + } + return obj; + }); } private static void cleanRBACresourcesAndOperatorDeployment() throws FileNotFoundException { @@ -262,10 +270,15 @@ public class BaseOperatorTest implements QuarkusTestAfterEachCallback { @Override public void afterEach(QuarkusTestMethodContext context) { if (!(context.getTestInstance() instanceof BaseOperatorTest)) { - return; + return; // this hook gets called for all quarkus tests, not all are operator tests } try { - if (!context.getTestStatus().isTestFailed() || context.getTestStatus().getTestErrorCause() instanceof TestAbortedException) { + Method testMethod = context.getTestMethod(); + if (context.getTestStatus().getTestErrorCause() == null + || context.getTestStatus().getTestErrorCause() instanceof TestAbortedException + || !Stream.of(context.getTestStatus().getTestErrorCause().getStackTrace()) + .anyMatch(ste -> ste.getMethodName().equals(testMethod.getName()) + && ste.getClassName().equals(testMethod.getDeclaringClass().getName()))) { return; } Log.warnf("Test failed with %s: %s", context.getTestStatus().getTestErrorCause().getMessage(), context.getTestStatus().getTestErrorCause().getClass().getName()); diff --git a/operator/src/test/java/org/keycloak/operator/testsuite/utils/K8sUtils.java b/operator/src/test/java/org/keycloak/operator/testsuite/utils/K8sUtils.java index a6d89fc686..8bb1561f15 100644 --- a/operator/src/test/java/org/keycloak/operator/testsuite/utils/K8sUtils.java +++ b/operator/src/test/java/org/keycloak/operator/testsuite/utils/K8sUtils.java @@ -39,6 +39,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -63,7 +64,11 @@ public final class K8sUtils { } public static List set(KubernetesClient client, InputStream stream) { - return client.load(stream).items().stream().map(i -> set(client, i)).collect(Collectors.toList()); + return set(client, stream, Function.identity()); + } + + public static List set(KubernetesClient client, InputStream stream, Function modifier) { + return client.load(stream).items().stream().map(modifier).map(i -> set(client, i)).collect(Collectors.toList()); } public static T set(KubernetesClient client, T hasMetadata) {