From 0ba810240f63986a9e8b7580d18aae8a784f8dbc Mon Sep 17 00:00:00 2001 From: Moritz Sanft <58110325+msanft@users.noreply.github.com> Date: Tue, 21 Feb 2023 12:47:14 +0100 Subject: [PATCH] ci: integrate automatic iam creation in e2e test (#1158) * integrate automatic iam creation in e2e test * fix typo * break long line comments * fix semvers * correct bracing --- .../actions/constellation_create/action.yml | 9 +- .../constellation_iam_create/action.yml | 83 +++++++++++++++++++ .../constellation_iam_destroy/action.yml | 17 ++++ .github/actions/e2e_test/action.yml | 20 ++++- .github/workflows/e2e-test-manual.yml | 6 ++ .github/workflows/e2e-test-weekly.yml | 12 ++- cli/internal/cmd/iam.go | 1 + 7 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 .github/actions/constellation_iam_create/action.yml create mode 100644 .github/actions/constellation_iam_destroy/action.yml diff --git a/.github/actions/constellation_create/action.yml b/.github/actions/constellation_create/action.yml index ee22ab2bd..6929b26c2 100644 --- a/.github/actions/constellation_create/action.yml +++ b/.github/actions/constellation_create/action.yml @@ -26,6 +26,9 @@ inputs: keepMeasurements: default: "false" description: "Keep measurements embedded in the CLI." + existingConfig: + default: "false" + description: "Use existing config file." # # GCP specific inputs # @@ -70,6 +73,7 @@ runs: steps: - name: Constellation config generate shell: bash + if: inputs.existingConfig != 'true' run: | constellation config generate ${{ inputs.cloudProvider }} @@ -99,6 +103,9 @@ runs: (.provider | select(. | has(\"aws\")).aws.iamProfileWorkerNodes) = \"e2e_test_worker_node_instance_profile\"" \ constellation-conf.yaml + - name: Update config + shell: bash + run: | if [[ ${{ inputs.kubernetesVersion != '' }} = true ]]; then yq eval -i "(.kubernetesVersion) = \"${{ inputs.kubernetesVersion }}\"" constellation-conf.yaml fi @@ -138,7 +145,7 @@ runs: yq eval -i "(.provider | select(. | has(\"aws\")).aws.instanceType) = \"${{ inputs.machineType }}\"" constellation-conf.yaml - name: Create serviceAccountKey.json - if: inputs.cloudProvider == 'gcp' + if: inputs.cloudProvider == 'gcp' && !inputs.existingConfig # Skip if using existing config. serviceAccountKey.json is already present in that case. shell: bash env: GCP_CLUSTER_SERVICE_ACCOUNT_KEY: ${{ inputs.gcpClusterServiceAccountKey }} diff --git a/.github/actions/constellation_iam_create/action.yml b/.github/actions/constellation_iam_create/action.yml new file mode 100644 index 000000000..2e653a64b --- /dev/null +++ b/.github/actions/constellation_iam_create/action.yml @@ -0,0 +1,83 @@ +name: Constellation IAM create +description: Create IAM configuration for a Constellation cluster. + +inputs: + cloudProvider: + description: "Either 'aws', 'azure' or 'gcp'." + required: true + # + # AWS specific inputs + # + awsZone: + description: "AWS zone to deploy Constellation in." + required: false + awsPrefix: + description: "name prefix to use for the AWS resources." + required: false + # + # Azure specific inputs + # + azureRegion: + description: "Azure region to deploy Constellation in." + required: false + azureResourceGroup: + description: "Name of the Azure resource group being created." + required: false + azureServicePrincipal: + description: "Name of the Azure service principal being created." + required: false + # + # GCP specific inputs + # + gcpProjectID: + description: "The GCP project ID to deploy Constellation in." + required: false + gcpZone: + description: "The GCP zone to deploy Constellation in." + required: false + gcpServiceAccountID: + description: "ID of the GCP service account being created." + required: false + +outputs: + existingConfig: + description: "Whether a configuration file has been created to be used in the next step." + value: ${{ steps.setExistingConfig.outputs.existingConfig }} + +runs: + using: "composite" + steps: + - name: Constellation iam create aws + shell: bash + if: inputs.cloudProvider == 'aws' + run: | + constellation iam create aws \ + --zone=${{ inputs.awsZone }} \ + --prefix=${{ inputs.awsPrefix }} \ + --generate-config --yes + + - name: Constellation iam create azure + shell: bash + if: inputs.cloudProvider == 'azure' + run: | + constellation iam create azure \ + --region=${{ inputs.azureRegion }} \ + --resourceGroup=${{ inputs.azureResourceGroup }} \ + --servicePrincipal=${{ inputs.azureServicePrincipal }} \ + --generate-config --yes + + - name: Constellation iam create gcp + shell: bash + if: inputs.cloudProvider == 'gcp' + run: | + constellation iam create gcp \ + --projectID=${{ inputs.gcpProjectID }} \ + --zone=${{ inputs.gcpZone }} \ + --serviceAccountID=${{ inputs.gcpServiceAccountID }} \ + --generate-config --yes + + - name: Set existing config + id: setExistingConfig + shell: bash + run: | + echo "existingConfig=true" >> $GITHUB_OUTPUT diff --git a/.github/actions/constellation_iam_destroy/action.yml b/.github/actions/constellation_iam_destroy/action.yml new file mode 100644 index 000000000..05daf4c91 --- /dev/null +++ b/.github/actions/constellation_iam_destroy/action.yml @@ -0,0 +1,17 @@ +name: Delete IAM configuration +description: Delete previously created IAM configuration. + +runs: + using: "composite" + steps: + - name: Delete IAM configuration + shell: bash + run: | + if [[ -f constellation-iam-terraform/terraform.tfstate ]]; then + echo "IAM Terraform state file exists, deleting..." + cd constellation-iam-terraform + terraform destroy -auto-approve + else + echo "IAM Terraform state file does not exist, exiting..." + exit 0 + fi diff --git a/.github/actions/e2e_test/action.yml b/.github/actions/e2e_test/action.yml index 775127739..b3608846e 100644 --- a/.github/actions/e2e_test/action.yml +++ b/.github/actions/e2e_test/action.yml @@ -57,7 +57,7 @@ inputs: description: "The resource group to use" required: false test: - description: "The test to run. Can currently be one of [sonobuoy full, sonobuoy quick, autoscaling, lb, k-bench, verify, recover, nop]." + description: "The test to run. Can currently be one of [sonobuoy full, sonobuoy quick, autoscaling, lb, k-bench, verify, recover, nop, iamcreate]." required: true sonobuoyTestSuiteCmd: description: "The sonobuoy test suite to run." @@ -72,7 +72,7 @@ runs: using: "composite" steps: - name: Check input - if: (!contains(fromJson('["sonobuoy full", "sonobuoy quick", "autoscaling", "k-bench", "verify", "lb", "recover", "nop"]'), inputs.test)) + if: (!contains(fromJson('["sonobuoy full", "sonobuoy quick", "autoscaling", "k-bench", "verify", "lb", "recover", "nop", "iamcreate"]'), inputs.test)) shell: bash run: | echo "Invalid input for test field: ${{ inputs.test }}" @@ -155,6 +155,21 @@ runs: # extend token expiry to 6 hours to ensure constellation can terminate role-duration-seconds: 21600 + - name: Create IAM configuration + id: constellation-iam-create + if: inputs.test == 'iamcreate' && inputs.cloudProvider != 'azure' # skip for Azure, as the SP / MI does not have the required permissions + uses: ./.github/actions/constellation_iam_create + with: + cloudProvider: ${{ inputs.cloudProvider }} + awsZone: eu-central-1a + awsPrefix: e2e_${{ github.run_id }}_${{ github.run_attempt }} + azureRegion: northeurope + azureResourceGroup: e2e_${{ github.run_id }}_${{ github.run_attempt }}_rg + azureServicePrincipal: e2e_${{ github.run_id }}_${{ github.run_attempt }}_sp + gcpProjectID: ${{ inputs.gcpProject }} + gcpZone: europe-west3-b + gcpServiceAccountID: e2e-${{ github.run_id }}-${{ github.run_attempt }}-sa + - name: Create cluster id: constellation-create uses: ./.github/actions/constellation_create @@ -175,6 +190,7 @@ runs: azureClientSecret: ${{ inputs.azureClientSecret }} azureUserAssignedIdentity: ${{ inputs.azureUserAssignedIdentity }} azureResourceGroup: ${{ inputs.azureResourceGroup }} + existingConfig: ${{ steps.constellation-iam-create.outputs.existingConfig }} # # Test payloads diff --git a/.github/workflows/e2e-test-manual.yml b/.github/workflows/e2e-test-manual.yml index 5f0d13e81..02c6b65c5 100644 --- a/.github/workflows/e2e-test-manual.yml +++ b/.github/workflows/e2e-test-manual.yml @@ -39,6 +39,7 @@ on: - "verify" - "recover" - "nop" + - "iamcreate" required: true kubernetesVersion: description: "Kubernetes version to create the cluster from." @@ -311,6 +312,11 @@ jobs: with: kubeconfig: ${{ steps.e2e_test.outputs.kubeconfig }} + - name: Always delete IAM configuration + if: always() && inputs.test == 'iamcreate' && inputs.cloudProvider != 'azure' # skip for Azure, as the SP / MI does not have the required permissions + continue-on-error: true + uses: ./.github/actions/constellation_iam_destroy + - name: Always destroy Azure resource group if: always() && inputs.cloudProvider == 'azure' shell: bash diff --git a/.github/workflows/e2e-test-weekly.yml b/.github/workflows/e2e-test-weekly.yml index b3c960a72..03f0226ce 100644 --- a/.github/workflows/e2e-test-weekly.yml +++ b/.github/workflows/e2e-test-weekly.yml @@ -46,10 +46,15 @@ jobs: max-parallel: 5 matrix: test: - ["sonobuoy full", "autoscaling", "k-bench", "lb", "verify", "recover"] + ["sonobuoy full", "autoscaling", "k-bench", "lb", "verify", "recover", "iamcreate"] provider: ["gcp", "azure", "aws"] version: ["v1.24.9", "v1.25.6", "v1.26.1"] exclude: + # IAM create test runs only on latest version. + - test: "iamcreate" + version: "v1.24.9" + - test: "iamcreate" + version: "v1.25.6" # Verify test runs only on latest version. - test: "verify" version: "v1.24.9" @@ -140,6 +145,11 @@ jobs: with: kubeconfig: ${{ steps.e2e_test.outputs.kubeconfig }} + - name: Always delete IAM configuration + if: always() && matrix.test == 'iamcreate' && matrix.provider != 'azure' # skip for Azure, as the SP / MI does not have the required permissions + continue-on-error: true + uses: ./.github/actions/constellation_iam_destroy + - name: Notify teams channel if: failure() && github.ref == 'refs/heads/main' continue-on-error: true diff --git a/cli/internal/cmd/iam.go b/cli/internal/cmd/iam.go index 1e3d65b03..73a84f941 100644 --- a/cli/internal/cmd/iam.go +++ b/cli/internal/cmd/iam.go @@ -383,6 +383,7 @@ func (c *awsIAMCreator) printOutputValues(cmd *cobra.Command, flags iamFlags, ia cmd.Printf("zone:\t\t\t%s\n", flags.aws.zone) cmd.Printf("iamProfileControlPlane:\t%s\n", iamFile.AWSOutput.ControlPlaneInstanceProfile) cmd.Printf("iamProfileWorkerNodes:\t%s\n\n", iamFile.AWSOutput.WorkerNodeInstanceProfile) + cmd.Println("Your IAM configuration was created successfully. Please fill the above values into your configuration file.") } func (c *awsIAMCreator) writeOutputValuesToConfig(conf *config.Config, flags iamFlags, iamFile iamid.File) {