From 85c981762eb4c75dbd7e631a24485d57ab882f79 Mon Sep 17 00:00:00 2001 From: Aurel Canciu Date: Wed, 4 Dec 2019 19:04:36 +0200 Subject: [PATCH] feat(kubernetes): Add ServiceAccount provisioning support --- .../deploy/deployment/v1/KubectlDeployer.java | 6 ++++++ .../v1/service/KubernetesSettings.java | 2 +- .../kubernetes/v2/KubernetesV2Service.java | 14 ++++++++++++- .../kubernetes/manifests/serviceAccount.yml | 12 +++++++++++ .../v2/KubernetesV2ServiceTest.groovy | 20 +++++++++++++++---- 5 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 halyard-deploy/src/main/resources/kubernetes/manifests/serviceAccount.yml diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/deployment/v1/KubectlDeployer.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/deployment/v1/KubectlDeployer.java index cd702c0e8c..78afa11dcf 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/deployment/v1/KubectlDeployer.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/deployment/v1/KubectlDeployer.java @@ -87,6 +87,8 @@ public RemoteAction deploy( String namespaceDefinition = service.getNamespaceYaml(resolvedConfiguration); String serviceDefinition = service.getServiceYaml(resolvedConfiguration); + String serviceAccountDefinition = + service.getServiceAccountYaml(resolvedConfiguration); if (!executor.exists(namespaceDefinition)) { executor.apply(namespaceDefinition); @@ -96,6 +98,10 @@ public RemoteAction deploy( executor.apply(serviceDefinition); } + if (!executor.exists(serviceAccountDefinition)) { + executor.apply(serviceAccountDefinition); + } + String resourceDefinition = service.getResourceYaml( executor, deploymentDetails, resolvedConfiguration); diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/KubernetesSettings.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/KubernetesSettings.java index 253dec8bdc..b7970b315a 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/KubernetesSettings.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/KubernetesSettings.java @@ -31,8 +31,8 @@ public class KubernetesSettings { Map podAnnotations = new HashMap<>(); Map podLabels = new HashMap<>(); Map serviceLabels = new HashMap<>(); + Map serviceAccountAnnotations = new HashMap<>(); List volumes = new ArrayList<>(); - String serviceAccountName = null; String serviceType = "ClusterIP"; String nodePort = null; Boolean useExecHealthCheck = true; diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2Service.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2Service.java index 78ac1018dd..e5e785e79c 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2Service.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2Service.java @@ -193,6 +193,18 @@ default String getResourceYaml( .toString(); } + default String getServiceAccountYaml( + GenerateService.ResolvedConfiguration resolvedConfiguration) { + ServiceSettings settings = resolvedConfiguration.getServiceSettings(getService()); + String namespace = getNamespace(settings); + return new JinjaJarResource("/kubernetes/manifests/serviceAccount.yml") + .addBinding("name", getService().getCanonicalName()) + .addBinding("namespace", getNamespace(settings)) + .addBinding( + "serviceAccountAnnotations", settings.getKubernetes().getServiceAccountAnnotations()) + .toString(); + } + default String getPodSpecYaml( KubernetesV2Executor executor, AccountDeploymentDetails details, @@ -250,7 +262,7 @@ default String getPodSpecYaml( .addBinding("initContainers", getInitContainers(details)) .addBinding("hostAliases", getHostAliases(details)) .addBinding("imagePullSecrets", settings.getKubernetes().getImagePullSecrets()) - .addBinding("serviceAccountName", settings.getKubernetes().getServiceAccountName()) + .addBinding("serviceAccountName", getService().getCanonicalName()) .addBinding("terminationGracePeriodSeconds", terminationGracePeriodSeconds()) .addBinding("nodeSelector", settings.getKubernetes().getNodeSelector()) .addBinding("affinity", getAffinity(details)) diff --git a/halyard-deploy/src/main/resources/kubernetes/manifests/serviceAccount.yml b/halyard-deploy/src/main/resources/kubernetes/manifests/serviceAccount.yml new file mode 100644 index 0000000000..689bdaa22e --- /dev/null +++ b/halyard-deploy/src/main/resources/kubernetes/manifests/serviceAccount.yml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spin-{{ name }} + namespace: {{ namespace }} + labels: + app: spin + cluster: spin-{{ name }} + annotations: { + {% for key, value in serviceAccountAnnotations.items() %} + "{{ key }}": "{{ value }}"{% if not loop.last %}, {% endif %} + {% endfor %}} diff --git a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy index 46a59e93d2..3bb72aed07 100644 --- a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy +++ b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy @@ -395,15 +395,27 @@ class KubernetesV2ServiceTest extends Specification { yaml.contains('"tolerations": [{"key":"test","operator":"Equal","value":"a","effect":"NoSchedule"}]') } - def "Can we set ServiceAccountNames"() { + def "Does the serviceAccountName get set correctly?"() { setup: def executor = Mock(KubernetesV2Executor) - serviceSettings.getKubernetes().serviceAccountName = "customServiceAccount" when: String podSpecYaml = testService.getPodSpecYaml(executor, details, config) then: - podSpecYaml.contains('"serviceAccountName": customServiceAccount') + podSpecYaml.contains('"serviceAccountName": orca') } -} + + def "Can we set ServiceAccount.serviceAccountAnnotations?"() { + setup: + serviceSettings.getKubernetes().serviceAccountAnnotations = [ + "example-service-account-annotation": "test" + ] + + when: + String yaml = testService.getServiceAccountYaml(config) + + then: + yaml.matches(/(?ms).+annotations: \{.+"example-service-account-annotation": "test".+\}.*/) + } +} \ No newline at end of file