name: Arrow

run-name: Arrow - ${{ inputs.rebuild && 'Rebuild and ' || '' }}${{ inputs.action == 'create' && 'Create' || ( inputs.action == 'destroy' && 'Destroy' || 'No Action' ) }}

env:
  TERRAFORM_DIRECTORY: hosts/arrow/vultr
  DEPLOY_IDENTITY_BASE64: ${{ secrets.DEPLOY_IDENTITY_BASE64 }}
  ARROW_IDENTITY_BASE64: ${{ secrets.ARROW_IDENTITY_BASE64 }}
  CLOUDFLARE_R2_ENDPOINT: "${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com"
  AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_KEY }}
  AWS_DEFAULT_REGION: auto
  AWS_ENDPOINT_URL_S3: "https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com"
  TF_VAR_vultr_api_key: ${{ secrets.VULTR_API_KEY }}
  ZONE_NAME: masu.rs
  CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
  CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}

on:
  workflow_dispatch:
    inputs:
      rebuild:
        type: boolean
        default: false
      action:
        type: choice
        required: true
        default: create
        options:
          - create
          - destroy
          - nothing
      plan:
        type: choice
        required: false
        options:
          - vc2-1c-1gb # 25 GB / $5
          - vc2-1c-2gb # 55 GB / $10 (default)
          - vc2-2c-2gb # 65 GB / $15
          - vc2-2c-4gb # 80 GB / $20
          - vc2-4c-8gb # 160 GB / $40
          - vc2-6c-16gb # 320 GB / $80

jobs:
  build-deploy:
    name: Build and Deploy
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo Code
        uses: actions/checkout@v4

      # Enable access to KVM, required to build an image
      - name: Enable KVM group perms
        if: inputs.rebuild && inputs.action != 'destroy'
        run: |
            echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
            sudo udevadm control --reload-rules
            sudo udevadm trigger --name-match=kvm

      # Install Nix
      - name: Install Nix
        if: inputs.rebuild && inputs.action != 'destroy'
        uses: cachix/install-nix-action@v17

      # Build the image
      - name: Build Image
        if: inputs.rebuild && inputs.action != 'destroy'
        run: nix build .#arrow

      - name: Upload Image to S3
        if: inputs.rebuild && inputs.action != 'destroy'
        run: |
          aws s3 cp \
            result/iso/nixos.iso \
            s3://noahmasur-arrow-images/arrow.iso \
            --endpoint-url "https://${{ env.CLOUDFLARE_R2_ENDPOINT }}"

      # Installs the Terraform binary and some other accessory functions.
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2

      # Checks whether Terraform is formatted properly. If this fails, you
      # should install the pre-commit hook.
      - name: Check Formatting
        working-directory: ${{ env.TERRAFORM_DIRECTORY }}
        run: |
          terraform fmt -no-color -check -diff -recursive

      # Connects to remote state backend and download providers.
      - name: Terraform Init
        working-directory: ${{ env.TERRAFORM_DIRECTORY }}
        run: terraform init

      # Deploys infrastructure or changes to infrastructure.
      - name: Terraform Apply
        if: inputs.action == 'create'
        working-directory: ${{ env.TERRAFORM_DIRECTORY }}
        env:
          TF_VAR_vultr_plan: ${{ inputs.plan }}
        run: |
          terraform apply \
            -auto-approve \
            -input=false

      # Removes infrastructure.
      - name: Terraform Destroy
        if: inputs.action == 'destroy'
        working-directory: ${{ env.TERRAFORM_DIRECTORY }}
        run: |
          terraform destroy \
            -auto-approve \
            -input=false

      - name: Get Host IP
        if: inputs.action == 'create'
        id: host
        working-directory: ${{ env.TERRAFORM_DIRECTORY }}
        run: terraform output -raw host_ip

      - name: Wait on SSH
        if: inputs.action == 'create'
        run: |
          for i in $(seq 1 15); do
            if $(nc -z -w 3 ${{ steps.host.outputs.stdout }} 22); then
              exit 0
            fi
            sleep 10
          done

      - name: Write Identity Keys to Files
        if: inputs.action == 'create'
        run: |
          echo "${{ env.DEPLOY_IDENTITY_BASE64 }}" | base64 -d > deploy_ed25519
          chmod 0600 deploy_ed25519
          echo "${{ env.ARROW_IDENTITY_BASE64 }}" | base64 -d > arrow_ed25519
          chmod 0600 arrow_ed25519

      - name: Copy Identity File to Host
        if: inputs.action == 'create'
        run: |
          ssh -i deploy_ed25519 -o StrictHostKeyChecking=accept-new noah@${{ steps.host.outputs.stdout }} 'mkdir -pv .ssh'
          scp -i deploy_ed25519 arrow_ed25519 noah@${{ steps.host.outputs.stdout }}:~/.ssh/id_ed25519

      - name: Wipe Records
        if: ${{ inputs.action == 'destroy' }}
        run: |
          RECORD_ID=$(curl --request GET \
             --url https://api.cloudflare.com/client/v4/zones/${{ env.CLOUDFLARE_ZONE_ID }}/dns_records \
             --header 'Content-Type: application/json' \
             --header "Authorization: Bearer ${{ env.CLOUDFLARE_API_TOKEN }}" | jq -r '.result[] | select(.name == "n8n2.${{ env.ZONE_NAME }}") | .id')
          curl --request DELETE \
             --url https://api.cloudflare.com/client/v4/zones/${{ env.CLOUDFLARE_ZONE_ID }}/dns_records/${RECORD_ID} \
             --header 'Content-Type: application/json' \
             --header "Authorization: Bearer ${{ env.CLOUDFLARE_API_TOKEN }}"