diff --git a/eks-anywhere-common/Addons/Partner/Pulumi/README.md b/eks-anywhere-common/Addons/Partner/Pulumi/README.md new file mode 100644 index 00000000..e6d1abd2 --- /dev/null +++ b/eks-anywhere-common/Addons/Partner/Pulumi/README.md @@ -0,0 +1,3 @@ +# Pulumi + +This folder contains Kubernetes manifest that install the [Pulumi Kubernetes Operator](https://www.pulumi.com/docs/using-pulumi/continuous-delivery/pulumi-kubernetes-operator/) along with resources necessary to run the automated tests under `../Testers/Pulumi` in this repository. diff --git a/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-access-token-externalsecret.yaml b/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-access-token-externalsecret.yaml new file mode 100644 index 00000000..193dd74f --- /dev/null +++ b/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-access-token-externalsecret.yaml @@ -0,0 +1,16 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: pulumi-access-token + namespace: pulumi +spec: + refreshInterval: 1m + secretStoreRef: + name: eksa-secret-store #The secret store name we have just created. + kind: ClusterSecretStore + target: + name: pulumi-access-token # Secret name in k8s + data: + - secretKey: accessToken # which key it's going to be stored in + remoteRef: + key: pulumi-access-token # External secret name goes here diff --git a/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-helmrepository.yaml b/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-helmrepository.yaml new file mode 100644 index 00000000..29592f85 --- /dev/null +++ b/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-helmrepository.yaml @@ -0,0 +1,9 @@ +apiVersion: source.toolkit.fluxcd.io/v1beta2 +kind: HelmRepository +metadata: + name: pulumi + namespace: pulumi +spec: + interval: 10m + type: oci + url: oci://ghcr.io/pulumi/helm-charts diff --git a/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-namespace.yaml b/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-namespace.yaml new file mode 100644 index 00000000..04cfd02c --- /dev/null +++ b/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: pulumi + labels: + aws.conformance.vendor: pulumi + aws.conformance.vendor-solution: pulumi-kubernetes-operator diff --git a/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-operator-helmrelease.yaml b/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-operator-helmrelease.yaml new file mode 100644 index 00000000..300ffad6 --- /dev/null +++ b/eks-anywhere-common/Addons/Partner/Pulumi/pulumi-operator-helmrelease.yaml @@ -0,0 +1,15 @@ +apiVersion: helm.toolkit.fluxcd.io/v2beta1 +kind: HelmRelease +metadata: + name: pulumi-kubernetes-operator + namespace: pulumi +spec: + interval: 10m + targetNamespace: pulumi + chart: + spec: + chart: pulumi-kubernetes-operator + version: "0.3.0" + sourceRef: + kind: HelmRepository + name: pulumi diff --git a/eks-anywhere-common/Testers/Pulumi/pulumi-tester-cronjob.yaml b/eks-anywhere-common/Testers/Pulumi/pulumi-tester-cronjob.yaml new file mode 100644 index 00000000..ee98c882 --- /dev/null +++ b/eks-anywhere-common/Testers/Pulumi/pulumi-tester-cronjob.yaml @@ -0,0 +1,187 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pulumi-tester + namespace: pulumi +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: pulumi-tester + namespace: pulumi +rules: + - apiGroups: ["pulumi.com"] + resources: ["stacks", "programs"] + verbs: ["*"] + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pulumi-tester + namespace: pulumi +subjects: + - kind: ServiceAccount + name: pulumi-tester +roleRef: + kind: Role + name: pulumi-tester + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: pulumi-tester + namespace: pulumi +data: + pulumi-org: aws-partnership + pulumi-k8s-operator-test.sh: |- + #!/bin/bash + set -e + + RANDOM_SUFFIX=$(date +%s)-$RANDOM + MANIFEST_FILENAME=/tmp/pulumi-test-stack-${RANDOM_SUFFIX}.yaml + + # Create a new, unique stack name. The name of the stack must be unique for each + # run for 2 reasons: + # 1. To ensure that each test run on the current platform starts from a known + # state, free from any previously test runs. + # 2. To ensure that we don't get colliding updates as AWS runs the test + # simultaneously on different EKS-A platforms. + TEST_PULUMI_STACK_NAME=test-${RANDOM_SUFFIX} + + STACKPATH=${PULUMI_ORG}/eks-pulumi-operator-test/${TEST_PULUMI_STACK_NAME} + + echo "" + echo "Writing out test manifest file '${MANIFEST_FILENAME}'" + # Note that while we use a random Pulumi stack name within the Stack resource, + # we keep the name of the Kubernetes Stack and Program resources static. This is + # intentional. If a test fails, we don't want it to leave superfluous Stack and + # Program K8s resources behind because the operator will keep trying to + # reconcile them. (The test failed - they should never be re-run again.) + # Instead, we want to reuse the same Kubernetes resource over and over but have + # it generate a new, uniquely-named Pulumi stack. + cat << EOF > $MANIFEST_FILENAME + apiVersion: pulumi.com/v1 + kind: Program + metadata: + name: eks-pulumi-operator-test + namespace: pulumi + program: + resources: + myRandomPet: + type: random:RandomPet + outputs: + petName: \${myRandomPet.id} + --- + apiVersion: pulumi.com/v1 + kind: Stack + metadata: + name: eks-pulumi-operator-test + namespace: pulumi + spec: + stack: ${STACKPATH} + programRef: + name: eks-pulumi-operator-test + destroyOnFinalize: true + envRefs: + PULUMI_ACCESS_TOKEN: + type: Secret + secret: + name: pulumi-access-token + key: accessToken + EOF + + echo "" + echo "Deploying sample stack and program." + kubectl apply -f $MANIFEST_FILENAME + + echo "" + echo "Waiting for the operator to deploy the stack." + kubectl wait -n pulumi stack/eks-pulumi-operator-test --for=condition=Ready --timeout=180s + + echo "" + echo "Verifying that the stack exists." + curl \ + -s \ + --fail \ + -H "Accept: application/vnd.pulumi+8" \ + -H "Content-Type: application/json" \ + -H "Authorization: token $PULUMI_ACCESS_TOKEN" \ + https://api.pulumi.com/api/stacks/${STACKPATH} + + echo "" + echo "Destroying K8s Stack resource" + kubectl delete -n pulumi stacks/eks-pulumi-operator-test + + echo "" + echo "Waiting for the operator to remove the stack" + kubectl wait -n pulumi stack/eks-pulumi-operator-test --for=delete --timeout=180s + + echo "" + echo "Verifying the stack no longer exists" + STATUSCODE=$(curl \ + -s \ + -o /dev/null \ + --w "%{http_code}" \ + -H "Accept: application/vnd.pulumi+8" \ + -H "Content-Type: application/json" \ + -H "Authorization: token $PULUMI_ACCESS_TOKEN" \ + https://api.pulumi.com/api/stacks/${STACKPATH} + ) + + if test $STATUSCODE -ne 404; then + echo "ERROR: Expected HTTP status code 404 from the Pulumi Cloud API when querying the stack. Got HTTP status code $STATUSCODE instead." + false + fi + + # This is for purely for running the script locally. Since the K8s tester Job is + # run in an ephemeral container, deleting the file is unnecessary in that + # context: + echo "" + echo "Deleting test manifest file '${MANIFEST_FILENAME}'" + rm ${MANIFEST_FILENAME} +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: pulumi-k8s-operator-test + namespace: pulumi +spec: + schedule: "10 10 * * *" + jobTemplate: + spec: + activeDeadlineSeconds: 900 + template: + spec: + serviceAccountName: pulumi-tester + containers: + - command: + - bash + - /scripts/pulumi-k8s-operator-test.sh + image: "alpine/k8s:1.26.2" + name: script + env: + - name: PULUMI_ACCESS_TOKEN + valueFrom: + secretKeyRef: + name: pulumi-access-token + key: accessToken + - name: PULUMI_ORG + valueFrom: + configMapKeyRef: + name: pulumi-tester + key: pulumi-org + volumeMounts: + - name: pulumi-tester-configmap + mountPath: /scripts/pulumi-k8s-operator-test.sh + subPath: pulumi-k8s-operator-test.sh + readOnly: false + restartPolicy: Never + volumes: + - name: pulumi-tester-configmap + configMap: + name: pulumi-tester + defaultMode: 0777