name: e2e test Terraform module

on:
  workflow_dispatch:
    inputs:
      ref:
        type: string
        description: "Git ref to checkout"
      cloudProvider:
        description: "Which cloud provider to use."
        type: choice
        options:
          - "aws"
          - "azure"
          - "gcp"
        required: true
      regionZone:
        description: "Region or zone to create the cluster in. Leave empty for default region/zone."
        type: string
      image:
        description: "OS Image version used in the cluster's VMs, as specified in the Constellation config. If not set, the latest nightly image from main is used."
        type: string
      cliVersion:
        description: "Constellation CLI version to use. Empty value means build from source."
        type: string
  workflow_call:
    inputs:
      ref:
        type: string
        description: "Git ref to checkout"
      cloudProvider:
        description: "Which cloud provider to use."
        type: string
        required: true
      regionZone:
        description: "Which zone to use."
        type: string
      image:
        description: "OS Image version used in the cluster's VMs, as specified in the Constellation config. If not set, the latest nightly image from main is used."
        type: string
      cliVersion:
        description: "Constellation CLI version to use. Empty value means build from source."
        type: string

jobs:
  tf-module-test:
    runs-on: ubuntu-22.04
    permissions:
      id-token: write
      contents: read
      packages: write
    steps:
      - name: Checkout
        id: checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          ref: ${{ inputs.ref || github.head_ref }}

      - name: Get Latest Image
        id: find-latest-image
        uses: ./.github/actions/find_latest_image
        with:
          git-ref: ${{ inputs.ref }}
          imageVersion: ${{ inputs.image }}
          ref: main
          stream: nightly

      - name: Upload Terraform module
        uses: ./.github/actions/upload_terraform_module
        with:
          version: ${{ inputs.cliVersion }}

      - name: Download Terraform module
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: terraform-module

      - name: Unzip Terraform module
        shell: bash
        run: |
          unzip terraform-module.zip -d ${{ github.workspace }}
          rm terraform-module.zip

      - name: Create resource prefix
        id: create-prefix
        shell: bash
        run: |
          run_id=${{ github.run_id }}
          last_three="${run_id: -3}"
          echo "prefix=e2e-${last_three}-${{ github.run_attempt }}" | tee -a "$GITHUB_OUTPUT"

      - name: Create AWS Terraform variable input file
        if: inputs.cloudProvider == 'aws'
        working-directory: ${{ github.workspace }}/terraform-module/aws-constellation
        shell: bash
        run: |
          cat > terraform.tfvars <<EOF
          name = "${{ steps.create-prefix.outputs.prefix }}"
          image = "${{ steps.find-latest-image.outputs.image  }}"
          zone = "${{ inputs.regionZone || 'us-east-2c' }}"
          name_prefix = "${{ steps.create-prefix.outputs.prefix }}"
          debug = ${{ steps.find-latest-image.outputs.isDebugImage }}
          node_groups = {
            control_plane_default = {
              role          = "control-plane"
              instance_type = "m6a.xlarge"
              disk_size     = 30
              disk_type     = "gp3"
              initial_count = 2
              zone = "${{ inputs.regionZone || 'us-east-2c' }}"
            },
            worker_default = {
              role          = "worker"
              instance_type = "m6a.xlarge"
              disk_size     = 30
              disk_type     = "gp3"
              initial_count = 2
              zone = "${{ inputs.regionZone || 'us-east-2c' }}"
            }
          }
          EOF
          cat terraform.tfvars

      - name: Create Azure Terraform variable input file
        if: inputs.cloudProvider == 'azure'
        working-directory: ${{ github.workspace }}/terraform-module/azure-constellation
        shell: bash
        run: |
          cat > terraform.tfvars <<EOF
          name = "${{ steps.create-prefix.outputs.prefix }}"
          image = "${{ steps.find-latest-image.outputs.image }}"
          location = "${{ inputs.regionZone || 'northeurope' }}"
          service_principal_name = "${{ steps.create-prefix.outputs.prefix }}-sp"
          resource_group_name = "${{ steps.create-prefix.outputs.prefix }}-rg"
          debug = ${{ steps.find-latest-image.outputs.isDebugImage }}
          node_groups = {
            control_plane_default = {
              role          = "control-plane"
              instance_type = "Standard_DC4as_v5"
              disk_size     = 30
              disk_type     = "Premium_LRS"
              initial_count = 2
            },
            worker_default = {
              role          = "worker"
              instance_type = "Standard_DC4as_v5"
              disk_size     = 30
              disk_type     = "Premium_LRS"
              initial_count = 2
            }
          }
          EOF
          cat terraform.tfvars

      - name: Create GCP Terraform variable input file
        if: inputs.cloudProvider == 'gcp'
        working-directory: ${{ github.workspace }}/terraform-module/gcp-constellation
        shell: bash
        run: |
          cat > terraform.tfvars <<EOF
          name = "${{ steps.create-prefix.outputs.prefix }}"
          project = "constellation-e2e"
          service_account_id = "${{ steps.create-prefix.outputs.prefix }}-sa"
          image = "${{ steps.find-latest-image.outputs.image }}"
          zone = "${{ inputs.regionZone || 'europe-west3-b' }}"
          debug = ${{ steps.find-latest-image.outputs.isDebugImage }}
          node_groups = {
            control_plane_default = {
              role          = "control-plane"
              instance_type = "n2d-standard-4"
              disk_size     = 30
              disk_type     = "pd-ssd"
              initial_count = 2
              zone = "${{ inputs.regionZone || 'europe-west3-b' }}"
            },
            worker_default = {
              role          = "worker"
              instance_type = "n2d-standard-4"
              disk_size     = 30
              disk_type     = "pd-ssd"
              initial_count = 2
              zone = "${{ inputs.regionZone || 'europe-west3-b' }}"
            }
          }
          EOF
          cat terraform.tfvars

      - name: Install dependencies (Terraform)
        shell: bash
        run: |
          sudo apt update && sudo apt install gpg
          wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
          gpg --no-default-keyring --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg --fingerprint
          echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
          sudo apt update
          sudo apt install terraform=1.4.4-*

      - name: Log in to the Container registry
        uses: ./.github/actions/container_registry_login
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup bazel
        if: inputs.cliVersion == ''
        uses: ./.github/actions/setup_bazel_nix
        with:
          useCache: "true"
          buildBuddyApiKey: ${{ secrets.BUILDBUDDY_ORG_API_KEY }}

      - name: Build CLI
        if: inputs.cliVersion == ''
        uses: ./.github/actions/build_cli
        with:
          outputPath: "constellation"
          enterpriseCLI: true
          push: true

      - name: Download CLI
        if: inputs.cliVersion != ''
        shell: bash
        run: |
          curl -fsSL -o constellation https://github.com/edgelesssys/constellation/releases/download/${{ inputs.cliVersion }}/constellation-linux-amd64
          chmod u+x constellation
          ./constellation version
          sudo sh -c 'echo "127.0.0.1 license.confidential.cloud" >> /etc/hosts'

      - name: Login to AWS (IAM + Cluster role)
        if: inputs.cloudProvider == 'aws'
        uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0
        with:
          role-to-assume: arn:aws:iam::795746500882:role/GithubActionsE2ETerraform
          aws-region: eu-central-1
          # extend token expiry to 6 hours to ensure constellation can terminate
          role-duration-seconds: 21600

      - name: Login to Azure (IAM + Cluster service principal)
        if: inputs.cloudProvider == 'azure'
        uses: ./.github/actions/login_azure
        with:
          azure_credentials: ${{ secrets.AZURE_E2E_TF_CREDENTIALS }}

      - name: Login to GCP (IAM + Cluster service account)
        if: inputs.cloudProvider == 'gcp'
        uses: ./.github/actions/login_gcp
        with:
          service_account: "terraform-e2e@constellation-e2e.iam.gserviceaccount.com"

      - name: Apply Terraform Cluster
        id: apply_terraform
        working-directory: ${{ github.workspace }}/terraform-module/${{ inputs.cloudProvider }}-constellation
        shell: bash
        run: |
          cp ../../constellation .
          terraform init
          terraform apply -var-file=terraform.tfvars  -auto-approve

      - name: Destroy Terraform Cluster
      # outcome is part of the steps context (https://docs.github.com/en/actions/learn-github-actions/contexts#steps-context)
        if: always() && steps.apply_terraform.outcome != 'skipped'
        working-directory: ${{ github.workspace }}/terraform-module/${{ inputs.cloudProvider }}-constellation
        shell: bash
        run: |
          terraform init
          terraform destroy -var-file=terraform.tfvars -auto-approve

      - name: Verify cleanup
        working-directory: ${{ github.workspace }}/terraform-module/${{ inputs.cloudProvider }}-constellation
        shell: bash
        run: |
          if [ -f constellation-mastersecret.json ] || [ -f constellation-conf.yaml ]; then
            echo "Files  constellation-mastersecret.json or constellation-conf.yaml still exist"
            exit 1
          fi

      - name: Notify about failure
        if: |
          failure() &&
          github.ref == 'refs/heads/main' &&
          github.event_name == 'schedule'
        continue-on-error: true
        uses: ./.github/actions/notify_e2e_failure
        with:
          projectWriteToken: ${{ secrets.PROJECT_WRITE_TOKEN }}
          test: "terraform-module"
          provider: ${{ inputs.cloudProvider }}