name: e2e test upgrade

on:
  workflow_dispatch:
    inputs:
      cloudProvider:
        description: "Which cloud provider to use."
        type: choice
        options:
          - "gcp"
          - "azure"
          - "aws"
        default: "azure"
      workerNodesCount:
        description: "Number of worker nodes to spawn."
        default: "2"
      controlNodesCount:
        description: "Number of control-plane nodes to spawn."
        default: "3"
      fromVersion:
        description: CLI version to create a new cluster with. This has to be a released version, e.g., 'v2.1.3'.
        type: string
        required: true
      gitRef:
        description: Ref to build upgrading CLI on, empty for HEAD.
        type: string
        default: "head"
        required: false
      toImage:
        description: Image (shortpath) the cluster is upgraded to, or empty for main/nightly.
        type: string
        required: false
      toKubernetes:
        description: Kubernetes version to target for the upgrade, empty for target's default version.
        type: string
        required: false
      toMicroservices:
        description: Microservice version to target for the upgrade, empty for target's default version.
        type: string
        required: false
      simulatedTargetVersion:
        description: Enter a version to build the CLI with. This can be used to simulate a patch-upgrade.
        type: string
        required: false
      scheduled:
        description: Don't set this when triggering manually.
        type: boolean
        default: false
        required: false
  workflow_call:
    inputs:
      cloudProvider:
        description: "Which cloud provider to use."
        type: string
        required: true
      workerNodesCount:
        description: "Number of worker nodes to spawn."
        type: number
        required: true
      controlNodesCount:
        description: "Number of control-plane nodes to spawn."
        type: number
        required: true
      fromVersion:
        description: CLI version to create a new cluster with. This has to be a released version, e.g., 'v2.1.3'.
        type: string
        required: true
      gitRef:
        description: Ref to build upgrading CLI on.
        type: string
        default: "head"
        required: false
      toImage:
        description: Image (shortpath) the cluster is upgraded to, or empty for main/nightly.
        type: string
        required: false
      toKubernetes:
        description: Kubernetes version to target for the upgrade, empty for target's default version.
        type: string
        required: false
      toMicroservices:
        description: Kubernetes version to target for the upgrade, empty for target's default version.
        type: string
        required: false
      simulatedTargetVersion:
        description: Enter a version to build the CLI with. This can be used to simulate a patch-upgrade.
        type: string
        required: false
      scheduled:
        description: Whether this is a scheduled run.
        type: boolean
        default: false
        required: false

jobs:
  e2e-upgrade:
    runs-on: ubuntu-22.04
    permissions:
      id-token: write
      checks: write
      contents: read
      packages: write
    steps:
      - name: Checkout
        if: inputs.gitRef == 'head'
        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
        with:
          fetch-depth: 0
          ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }}

      - name: Checkout ref
        if: inputs.gitRef != 'head'
        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
        with:
          fetch-depth: 0
          ref: ${{ inputs.gitRef }}

      - name: Login to AWS
        uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0
        with:
          role-to-assume: arn:aws:iam::795746500882:role/GithubConstellationVersionsAPIRead
          aws-region: eu-central-1

      - name: Find latest nightly image
        id: find-image
        if: inputs.toImage == ''
        uses: ./.github/actions/versionsapi
        with:
          command: latest
          ref: main
          stream: nightly

      - name: Simulate patch upgrade
        if: inputs.simulatedTargetVersion != ''
        run: |
          echo ${{ inputs.simulatedTargetVersion }} > version.txt

      - name: Create cluster with 'fromVersion' CLI.
        id: e2e_test
        uses: ./.github/actions/e2e_test
        with:
          workerNodesCount: ${{ inputs.workerNodesCount }}
          controlNodesCount: ${{ inputs.controlNodesCount }}
          cloudProvider: ${{ inputs.cloudProvider }}
          osImage: ${{ inputs.fromVersion }}
          isDebugImage: "false"
          cliVersion: ${{ inputs.fromVersion }}
          gcpProject: ${{ secrets.GCP_E2E_PROJECT }}
          gcpClusterCreateServiceAccount: "constellation-e2e-cluster@constellation-331613.iam.gserviceaccount.com"
          gcpIAMCreateServiceAccount: "constellation-iam-e2e@constellation-331613.iam.gserviceaccount.com"
          gcpInClusterServiceAccountKey: ${{ secrets.GCP_CLUSTER_SERVICE_ACCOUNT }}
          test: "nop"
          buildBuddyApiKey: ${{ secrets.BUILDBUDDY_ORG_API_KEY }}
          azureClusterCreateCredentials: ${{ secrets.AZURE_E2E_CLUSTER_CREDENTIALS }}
          azureIAMCreateCredentials: ${{ secrets.AZURE_E2E_IAM_CREDENTIALS }}
          registry: ghcr.io
          githubToken: ${{ secrets.GITHUB_TOKEN }}

      - name: Build CLI
        uses: ./.github/actions/build_cli
        with:
          enterpriseCLI: true
          outputPath: "build/constellation"
          push: true

      - name: Run upgrade test
        env:
          KUBECONFIG: ${{ steps.e2e_test.outputs.kubeconfig }}
          IMAGE: ${{ inputs.toImage && inputs.toImage || steps.find-image.outputs.output }}
          KUBERNETES: ${{ inputs.toKubernetes }}
          MICROSERVICES: ${{ inputs.toMicroservices }}
          WORKERNODES: ${{ inputs.workerNodesCount }}
          CONTROLNODES: ${{ inputs.controlNodesCount }}
        run: |
          echo "Image target: $IMAGE"
          echo "K8s target: $KUBERNETES"
          echo "Microservice target: $MICROSERVICES"

          if [[ -n ${MICROSERVICES} ]]; then
            MICROSERVICES_FLAG="--target-microservices=$MICROSERVICES"
          fi
          if [[ -n ${KUBERNETES} ]]; then
            KUBERNETES_FLAG="--target-kubernetes=$KUBERNETES"
          fi

          bazel run //e2e/internal/upgrade:upgrade_test -- --want-worker "$WORKERNODES" --want-control "$CONTROLNODES" --target-image "$IMAGE" "$KUBERNETES_FLAG" "$MICROSERVICES_FLAG"

      - name: Always fetch logs
        if: always()
        env:
          KUBECONFIG: ${{ steps.e2e_test.outputs.kubeconfig }}
        run: |
          kubectl logs -n kube-system -l "app.kubernetes.io/name=constellation-operator" --tail=-1 > node-operator.logs
          kubectl logs -n kube-system -l "app.kubernetes.io/name=node-maintenance-operator" --tail=-1 > node-maintenance-operator.logs
          kubectl get nodeversions.update.edgeless.systems constellation-version -o yaml > constellation-version.yaml

      - name: Always upload logs
        if: always()
        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
        with:
          name: upgrade-logs
          path: |
            node-operator.logs
            node-maintenance-operator.logs
            constellation-version.yaml

      - name: Always terminate cluster
        if: always()
        uses: ./.github/actions/constellation_destroy
        with:
          kubeconfig: ${{ steps.e2e_test.outputs.kubeconfig }}

      - name: Always delete IAM configuration
        if: always()
        uses: ./.github/actions/constellation_iam_destroy
        with:
          cloudProvider: ${{ inputs.cloudProvider }}
          azureCredentials: ${{ secrets.AZURE_E2E_IAM_CREDENTIALS }}
          gcpServiceAccount: "constellation-iam-e2e@constellation-331613.iam.gserviceaccount.com"

      - name: Always upload Terraform logs
        if: always()
        uses: ./.github/actions/upload_terraform_logs
        with:
          artifactNameSuffix: ${{ steps.e2e_test.outputs.namePrefix }}

      - name: Notify about failure
        if: |
          failure() &&
          github.ref == 'refs/heads/main' &&
          github.event_name == 'workflow_call' &&
          inputs.scheduled == 'true'
        continue-on-error: true
        uses: ./.github/actions/notify_failure
        with:
          projectWriteToken: ${{ secrets.PROJECT_WRITE_TOKEN }}
          teamsWebhookUri: ${{ secrets.MS_TEAMS_WEBHOOK_URI }}
          test: "upgrade"
          provider: ${{ inputs.cloudProvider }}