From e60c3ac92e6b486a3cb918bd97e9f710bbce16fd Mon Sep 17 00:00:00 2001 From: Jose Date: Tue, 18 Apr 2023 08:39:55 +0200 Subject: [PATCH] Ensure the ServiceAccount/Role/ClusterRole resourcs are created in order Fix https://github.com/quarkusio/quarkus/issues/32640 Partially reverts https://github.com/quarkusio/quarkus/pull/32208 --- .../AddClusterRoleResourceDecorator.java | 6 - .../deployment/AddRoleResourceDecorator.java | 6 - .../AddServiceAccountResourceDecorator.java | 6 - .../deployment/KubernetesProcessor.java | 3 +- .../deployment/QuarkusFileWriter.java | 105 ++++++++++++++++++ .../KubernetesWithRbacFullTest.java | 6 + 6 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/QuarkusFileWriter.java diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddClusterRoleResourceDecorator.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddClusterRoleResourceDecorator.java index d13091514834b..2074e4fd122f1 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddClusterRoleResourceDecorator.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddClusterRoleResourceDecorator.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Map; -import io.dekorate.kubernetes.decorator.Decorator; import io.dekorate.kubernetes.decorator.ResourceProvidingDecorator; import io.fabric8.kubernetes.api.model.KubernetesListBuilder; import io.fabric8.kubernetes.api.model.ObjectMeta; @@ -46,9 +45,4 @@ public void visit(KubernetesListBuilder list) { .endMetadata() .withRules(rules)); } - - @Override - public Class[] before() { - return new Class[] { AddRoleBindingResourceDecorator.class }; - } } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddRoleResourceDecorator.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddRoleResourceDecorator.java index 632b3bca7bcef..752efe7fd2b03 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddRoleResourceDecorator.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddRoleResourceDecorator.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Map; -import io.dekorate.kubernetes.decorator.Decorator; import io.dekorate.kubernetes.decorator.ResourceProvidingDecorator; import io.fabric8.kubernetes.api.model.KubernetesListBuilder; import io.fabric8.kubernetes.api.model.ObjectMeta; @@ -49,9 +48,4 @@ public void visit(KubernetesListBuilder list) { .endMetadata() .withRules(rules)); } - - @Override - public Class[] before() { - return new Class[] { AddRoleBindingResourceDecorator.class }; - } } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddServiceAccountResourceDecorator.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddServiceAccountResourceDecorator.java index f6f90801b3608..b8fb1f0eb8dc4 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddServiceAccountResourceDecorator.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddServiceAccountResourceDecorator.java @@ -5,7 +5,6 @@ import java.util.HashMap; import java.util.Map; -import io.dekorate.kubernetes.decorator.Decorator; import io.dekorate.kubernetes.decorator.ResourceProvidingDecorator; import io.fabric8.kubernetes.api.model.KubernetesListBuilder; import io.fabric8.kubernetes.api.model.ObjectMeta; @@ -44,9 +43,4 @@ public void visit(KubernetesListBuilder list) { .endMetadata() .endServiceAccountItem(); } - - @Override - public Class[] before() { - return new Class[] { AddRoleBindingResourceDecorator.class }; - } } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java index cce484f5534c9..fa4d58dad9825 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java @@ -30,7 +30,6 @@ import io.dekorate.kubernetes.decorator.Decorator; import io.dekorate.logger.NoopLogger; import io.dekorate.processor.SimpleFileReader; -import io.dekorate.processor.SimpleFileWriter; import io.dekorate.project.Project; import io.dekorate.utils.Maps; import io.dekorate.utils.Strings; @@ -146,7 +145,7 @@ public void build(ApplicationInfoBuildItem applicationInfo, .map(DeploymentTargetEntry::getName) .collect(Collectors.toSet())); final Map generatedResourcesMap; - final SessionWriter sessionWriter = new SimpleFileWriter(project, false); + final SessionWriter sessionWriter = new QuarkusFileWriter(project); final SessionReader sessionReader = new SimpleFileReader( project.getRoot().resolve("src").resolve("main").resolve("kubernetes"), targets); sessionWriter.setProject(project); diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/QuarkusFileWriter.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/QuarkusFileWriter.java new file mode 100644 index 0000000000000..a837f359522dc --- /dev/null +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/QuarkusFileWriter.java @@ -0,0 +1,105 @@ +package io.quarkus.kubernetes.deployment; + +import static io.quarkus.kubernetes.deployment.Constants.CLUSTER_ROLE; +import static io.quarkus.kubernetes.deployment.Constants.CLUSTER_ROLE_BINDING; +import static io.quarkus.kubernetes.deployment.Constants.CRONJOB; +import static io.quarkus.kubernetes.deployment.Constants.DEPLOYMENT; +import static io.quarkus.kubernetes.deployment.Constants.DEPLOYMENT_CONFIG; +import static io.quarkus.kubernetes.deployment.Constants.INGRESS; +import static io.quarkus.kubernetes.deployment.Constants.JOB; +import static io.quarkus.kubernetes.deployment.Constants.ROLE; +import static io.quarkus.kubernetes.deployment.Constants.ROLE_BINDING; +import static io.quarkus.kubernetes.deployment.Constants.ROUTE; +import static io.quarkus.kubernetes.deployment.Constants.SERVICE_ACCOUNT; +import static io.quarkus.kubernetes.deployment.Constants.STATEFULSET; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import io.dekorate.processor.SimpleFileWriter; +import io.dekorate.project.Project; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.KubernetesList; +import io.fabric8.kubernetes.api.model.KubernetesListBuilder; + +public class QuarkusFileWriter extends SimpleFileWriter { + + private static final List RESOURCE_KIND_ORDER = List.of("Namespace", + "NetworkPolicy", + "ResourceQuota", + "LimitRange", + "PodSecurityPolicy", + "PodDisruptionBudget", + SERVICE_ACCOUNT, + "Secret", + "SecretList", + "ConfigMap", + "StorageClass", + "PersistentVolume", + "PersistentVolumeClaim", + "CustomResourceDefinition", + CLUSTER_ROLE, + "ClusterRoleList", + CLUSTER_ROLE_BINDING, + "ClusterRoleBindingList", + ROLE, + "RoleList", + ROLE_BINDING, + "RoleBindingList", + "Service", + "ImageStream", + "BuildConfig", + "DaemonSet", + "Pod", + "ReplicationController", + "ReplicaSet", + DEPLOYMENT, + "HorizontalPodAutoscaler", + STATEFULSET, + DEPLOYMENT_CONFIG, + JOB, + CRONJOB, + INGRESS, + ROUTE, + "APIService"); + + public QuarkusFileWriter(Project project) { + super(project, false); + } + + @Override + public Map write(String group, KubernetesList list) { + // sort resources in list by: ServiceAccount, Role, ClusterRole, the rest... + return super.write(group, new KubernetesListBuilder().addAllToItems(sort(list.getItems())).build()); + } + + private List sort(List items) { + // Resources that we need the order. + Map> groups = new HashMap<>(); + // List of resources with unknown order: we preserve the order of creation in this case + List rest = new LinkedList<>(); + for (HasMetadata item : items) { + String kind = item.getKind(); + if (RESOURCE_KIND_ORDER.contains(kind)) { + groups.computeIfAbsent(kind, k -> new LinkedList<>()) + .add(item); + } else { + rest.add(item); + } + } + + List sorted = new LinkedList<>(); + // we first add the resources with order + for (String kind : RESOURCE_KIND_ORDER) { + List group = groups.get(kind); + if (group != null) { + sorted.addAll(group); + } + } + + sorted.addAll(rest); + return sorted; + } +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithRbacFullTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithRbacFullTest.java index 41bdd6c3e594f..83be5e5411d86 100644 --- a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithRbacFullTest.java +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithRbacFullTest.java @@ -53,6 +53,12 @@ public void assertGeneratedResources() throws IOException { assertTrue(lastIndexOfRoleRefKind < firstIndexOfRoleBinding, "RoleBinding resource is created before " + "the Role/ClusterRole/ServiceAccount resource!"); + // ensure service account resource is generated before the Deployment resource: + int lastIndexOfServiceAccount = lastIndexOfKind(kubernetesFileContent, "ServiceAccount"); + int firstIndexOfDeployment = kubernetesFileContent.indexOf("kind: Deployment"); + assertTrue(lastIndexOfServiceAccount < firstIndexOfDeployment, "ServiceAccount resource is created after " + + "the Deployment resource!"); + List kubernetesList = DeserializationUtil.deserializeAsList(kubernetesFile); Deployment deployment = getDeploymentByName(kubernetesList, APP_NAME);