diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index f238fb791..9d8ae12db 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -2,8 +2,12 @@ self-hosted-runner: labels: - aarch64-darwin - aarch64-linux - - blacksmith-32vcpu-ubuntu-2404 + - arm-native-runner - blacksmith-2vcpu-ubuntu-2404 - blacksmith-2vcpu-ubuntu-2404-arm - blacksmith-4vcpu-ubuntu-2404 + - blacksmith-4vcpu-ubuntu-2404-arm + - blacksmith-8vcpu-ubuntu-2404 + - blacksmith-32vcpu-ubuntu-2404 - large-linux-arm + - large-linux-x86 diff --git a/.github/actionlint.yml b/.github/actionlint.yml deleted file mode 100644 index eaf4d7d50..000000000 --- a/.github/actionlint.yml +++ /dev/null @@ -1,4 +0,0 @@ -self-hosted-runner: - labels: - - blacksmith-2vcpu-ubuntu-2404-arm - - blacksmith-4vcpu-ubuntu-2404 diff --git a/.github/actions/build-ami/action.yml b/.github/actions/build-ami/action.yml index a9c903c96..83602334d 100644 --- a/.github/actions/build-ami/action.yml +++ b/.github/actions/build-ami/action.yml @@ -11,6 +11,9 @@ inputs: arch: description: Architecture to build AMI for (amd64|arm64) required: true + force: + description: Force building stage1 AMI + required: false git_sha: description: 'Git SHA for this build' required: true @@ -49,9 +52,9 @@ runs: id: set-execution-id shell: bash run: | - EXECUTION_ID="${{ github.run_id }}-${{ inputs.postgres_version }}-${{ inputs.arch }}" - echo "EXECUTION_ID=$EXECUTION_ID" >> $GITHUB_ENV - echo "execution_id=$EXECUTION_ID" >> $GITHUB_OUTPUT + PACKER_EXECUTION_ID="${{ github.run_id }}-${{ inputs.postgres_version }}-${{ inputs.arch }}" + echo "PACKER_EXECUTION_ID=$PACKER_EXECUTION_ID" >> $GITHUB_ENV + echo "execution_id=$PACKER_EXECUTION_ID" >> $GITHUB_OUTPUT - name: Generate common-nix.vars.pkr.hcl id: generate-vars @@ -71,30 +74,44 @@ runs: AWS_MAX_ATTEMPTS: 10 AWS_RETRY_MODE: adaptive AWS_REGION: ${{ inputs.region }} + GIT_SHA: ${{ inputs.git_sha }} run: | + echo "::group::AMI Build: Stage 1" + + if [[ -n "${{ inputs.force }}" ]]; then + export BUILD_AMI_NIX_FORCE_BUILD_STAGE1="${{ inputs.force }}" + fi + nix run .#build-ami -- stage1 ${{ inputs.arch }} \ - -var "git-head-version=${{ inputs.git_sha }}" \ - -var "packer-execution-id=${{ env.EXECUTION_ID }}" \ - -var "ansible_arguments=-e postgresql_major=${{ inputs.postgres_version }}" \ + -var "ami_name=${{ inputs.ami_name_prefix }}" \ -var 'ami_regions=${{ inputs.ami_regions }}' \ + -var "ansible_arguments=-e postgresql_major=${{ inputs.postgres_version }}" \ + -var "git-head-version=${{ inputs.git_sha }}" \ + -var "packer-execution-id=$PACKER_EXECUTION_ID" \ amazon-${{ inputs.arch }}-nix.pkr.hcl + echo "::endgroup::" + - name: Build AMI stage 2 id: build-stage2 shell: bash env: POSTGRES_MAJOR_VERSION: ${{ inputs.postgres_version }} POSTGRES_VERSION: ${{ steps.generate-vars.outputs.version }} - PACKER_EXECUTION_ID: ${{ env.EXECUTION_ID }} AWS_MAX_ATTEMPTS: 10 AWS_RETRY_MODE: adaptive AWS_REGION: ${{ inputs.region }} + GIT_SHA: ${{ inputs.git_sha }} run: | + echo "::group::AMI Build: Stage 2" + nix run .#build-ami -- stage2 ${{ inputs.arch }} \ - -var "git-head-version=${{ inputs.git_sha }}" \ - -var "packer-execution-id=${{ env.EXECUTION_ID }}" \ - -var "postgres_major_version=${{ inputs.postgres_version }}" \ -var "ami_name=${{ inputs.ami_name_prefix }}" \ + -var "git-head-version=${{ inputs.git_sha }}" \ -var "git_sha=${{ inputs.git_sha }}" \ -var "instance_type=${{ inputs.instance_type }}" \ + -var "packer-execution-id=$PACKER_EXECUTION_ID" \ + -var "postgres_major_version=${{ inputs.postgres_version }}" \ stage2-nix-psql.pkr.hcl + + echo "::endgroup::" diff --git a/.github/workflows/ami-release-nix.yml b/.github/workflows/ami-release-nix.yml index 932d279d9..0cab5865d 100644 --- a/.github/workflows/ami-release-nix.yml +++ b/.github/workflows/ami-release-nix.yml @@ -6,9 +6,11 @@ on: - develop - release/* paths: - - '.github/workflows/ami-release-nix.yml' - - 'common-nix.vars.pkr.hcl' - - 'ansible/vars.yml' + - .github/workflows/ami-release-nix.yml + - ansible/vars.yml + - flake.lock + - flake.nix + - nix/packages/build-ami.nix workflow_dispatch: permissions: @@ -16,6 +18,9 @@ permissions: id-token: write actions: write +env: + AWS_REGION: us-east-1 + jobs: prepare: runs-on: blacksmith-4vcpu-ubuntu-2404 @@ -40,33 +45,34 @@ jobs: fail-fast: false matrix: postgres_version: ${{ fromJson(needs.prepare.outputs.postgres_versions) }} - arch: - - name: arm64 - runner: blacksmith-2vcpu-ubuntu-2404-arm - packer_template: amazon-arm64-nix.pkr.hcl - vars_file: development-arm64.vars.pkr.hcl - instance_type: c6g.4xlarge - nix_system: aarch64-linux - ami_arch_filter: arm64 - - name: amd64 - runner: blacksmith-2vcpu-ubuntu-2404 - packer_template: amazon-amd64-nix.pkr.hcl - vars_file: development-amd64.vars.pkr.hcl + target: + - arch: amd64 instance_type: c6i.4xlarge - nix_system: x86_64-linux - ami_arch_filter: x86_64 - runs-on: ${{ matrix.arch.runner }} + runner: blacksmith-2vcpu-ubuntu-2404 + - arch: arm64 + instance_type: c6g.4xlarge + runner: blacksmith-2vcpu-ubuntu-2404-arm + runs-on: ${{ matrix.target.runner }} timeout-minutes: 150 steps: - name: Checkout Repo uses: supabase/postgres/.github/actions/shared-checkout@HEAD - - name: aws-creds + - name: Debug AWS role secret + run: | + echo "Checking DEV_AWS_ROLE secret availability..." + if [ -z "${{ secrets.DEV_AWS_ROLE }}" ]; then + echo "❌ DEV_AWS_ROLE is empty or not available" + else + echo "✅ DEV_AWS_ROLE is available" + fi + + - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 with: role-to-assume: ${{ secrets.DEV_AWS_ROLE }} - aws-region: "us-east-1" + aws-region: ${{ env.AWS_REGION }} output-credentials: true role-duration-seconds: 7200 @@ -74,142 +80,97 @@ jobs: uses: ./.github/actions/nix-install-ephemeral with: push-to-cache: 'true' + aws-region: ${{ env.AWS_REGION }} env: DEV_AWS_ROLE: ${{ secrets.DEV_AWS_ROLE }} NIX_SIGN_SECRET_KEY: ${{ secrets.NIX_SIGN_SECRET_KEY }} - - name: Set PostgreSQL version environment variable - run: | - echo "POSTGRES_MAJOR_VERSION=${{ matrix.postgres_version }}" >> "$GITHUB_ENV" - echo "EXECUTION_ID=${{ github.run_id }}-${{ matrix.postgres_version }}-${{ matrix.arch.name }}" >> "$GITHUB_ENV" - - - name: Generate common-nix.vars.pkr.hcl - run: | - PG_VERSION="$(nix run nixpkgs#yq-go -- -r '.postgres_release["postgres'${{ matrix.postgres_version }}'"]' ansible/vars.yml)" - echo "postgres-version = \"$PG_VERSION\"" > common-nix.vars.pkr.hcl - - - name: Build AMI stage 1 - env: - POSTGRES_MAJOR_VERSION: ${{ env.POSTGRES_MAJOR_VERSION }} - run: | - GIT_SHA=${{github.sha}} - - nix run github:supabase/postgres/${GIT_SHA}#packer -- init ${{ matrix.arch.packer_template }} - nix run github:supabase/postgres/${GIT_SHA}#packer -- build -var "git-head-version=${GIT_SHA}" -var "packer-execution-id=${EXECUTION_ID}" -var-file="${{ matrix.arch.vars_file }}" -var-file="common-nix.vars.pkr.hcl" -var "ansible_arguments=-e postgresql_major=${POSTGRES_MAJOR_VERSION}" -var "region=us-east-1" -var 'ami_regions=["us-east-1"]' -var "ami_name=supabase-postgres-${{ matrix.arch.ami_arch_filter }}" ${{ matrix.arch.packer_template }} - - - name: Find stage 1 AMI - run: | - GIT_SHA=${{github.sha}} - - PG_VERSION=$(sed -n 's/postgres-version = "\(.*\)"/\1/p' common-nix.vars.pkr.hcl) - REGION="us-east-1" - - echo "Looking for stage 1 AMI with postgresVersion=${PG_VERSION}-stage1 and sourceSha=${GIT_SHA} in region ${REGION}" - - STAGE1_AMI_ID=$(aws ec2 describe-images \ - --region "$REGION" \ - --owners self \ - --filters \ - "Name=tag:postgresVersion,Values=${PG_VERSION}-stage1" \ - "Name=tag:sourceSha,Values=${GIT_SHA}" \ - "Name=state,Values=available" \ - "Name=architecture,Values=${{ matrix.arch.ami_arch_filter }}" \ - --query 'Images[0].ImageId' \ - --output text) - - if [ -z "$STAGE1_AMI_ID" ] || [ "$STAGE1_AMI_ID" = "None" ]; then - echo "ERROR: Failed to find stage 1 AMI" - exit 1 - fi - - echo "Found stage 1 AMI: $STAGE1_AMI_ID" - echo "STAGE1_AMI_ID=$STAGE1_AMI_ID" >> "$GITHUB_ENV" - - - name: Build AMI stage 2 - env: - POSTGRES_MAJOR_VERSION: ${{ env.POSTGRES_MAJOR_VERSION }} - run: | - GIT_SHA=${{github.sha}} - nix run github:supabase/postgres/${GIT_SHA}#packer -- init stage2-nix-psql.pkr.hcl - nix run github:supabase/postgres/${GIT_SHA}#packer -- build -var "git_sha=${GIT_SHA}" -var "git-head-version=${GIT_SHA}" -var "packer-execution-id=${EXECUTION_ID}" -var "postgres_major_version=${POSTGRES_MAJOR_VERSION}" -var "source_ami=${STAGE1_AMI_ID}" -var-file="${{ matrix.arch.vars_file }}" -var-file="common-nix.vars.pkr.hcl" -var "region=us-east-1" -var "instance_type=${{ matrix.arch.instance_type }}" -var "ami_name=supabase-postgres-${{ matrix.arch.ami_arch_filter }}" stage2-nix-psql.pkr.hcl - - - name: Grab release version - id: process_release_version - run: | - VERSION=$(sed -e 's/postgres-version = "\(.*\)"/\1/g' common-nix.vars.pkr.hcl) - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - echo "::notice title=AMI Published::Postgres AMI version: $VERSION" - - - name: Set arch-qualified version - id: arch_version + - name: Build AMI + id: build-ami + uses: ./.github/actions/build-ami + with: + ami_name_prefix: "supabase-postgres-${{ github.run_id }}-${{ matrix.target.arch }}" + ami_regions: '["${{ env.AWS_REGION }}"]' + arch: ${{ matrix.target.arch }} + force: "true" + git_sha: ${{ github.sha }} + instance_type: ${{ matrix.target.instance_type }} + postgres_version: ${{ matrix.postgres_version }} + region: ${{ env.AWS_REGION }} + + - name: Setup post build env vars run: | - VERSION="${{ steps.process_release_version.outputs.version }}" - if [ "${{ matrix.arch.name }}" = "amd64" ]; then + POSTGRES_SUPABASE_VERSION=${{ steps.build-ami.outputs.postgres_release_version }} + echo "::notice title=AMI Published::Postgres AMI version: $POSTGRES_SUPABASE_VERSION" + { + echo "PACKER_EXECUTION_ID=${{ steps.build-ami.outputs.execution_id }}" + echo "POSTGRES_MAJOR_VERSION=${{ matrix.postgres_version }}" + echo "POSTGRES_SUPABASE_VERSION=$POSTGRES_SUPABASE_VERSION" + } >>"$GITHUB_ENV" + + if [ "${{ matrix.target.arch }}" = "amd64" ]; then { - echo "version=${VERSION}" - echo "arch_suffix=-x86" - echo "release_tag=${VERSION}-x86" - } >> "$GITHUB_OUTPUT" + echo "ARCH_SUFFIX=-x86" + echo "RELEASE_TAG=${POSTGRES_SUPABASE_VERSION}-x86" + } >>"$GITHUB_ENV" else { - echo "version=${VERSION}" - echo "arch_suffix=" - echo "release_tag=${VERSION}" - } >> "$GITHUB_OUTPUT" + echo "ARCH_SUFFIX=" + echo "RELEASE_TAG=${POSTGRES_SUPABASE_VERSION}" + } >>"$GITHUB_ENV" fi - name: Create nix flake revision tarball run: | GIT_SHA=${{github.sha}} - MAJOR_VERSION=${{ matrix.postgres_version }} - mkdir -p "/tmp/pg_upgrade_bin/${MAJOR_VERSION}" - echo "$GIT_SHA" >> "/tmp/pg_upgrade_bin/${MAJOR_VERSION}/nix_flake_version" + mkdir -p "/tmp/pg_upgrade_bin/${POSTGRES_MAJOR_VERSION}" + echo "$GIT_SHA" >> "/tmp/pg_upgrade_bin/${POSTGRES_MAJOR_VERSION}/nix_flake_version" tar -czf "/tmp/pg_binaries.tar.gz" -C "/tmp/pg_upgrade_bin" . - name: configure aws credentials - staging uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 with: role-to-assume: ${{ secrets.DEV_AWS_ROLE }} - aws-region: "us-east-1" + aws-region: ${{ env.AWS_REGION }} - name: Upload software manifest to s3 staging run: | cd ansible ansible-playbook -i localhost \ - -e "ami_release_version=${{ steps.arch_version.outputs.version }}" \ + -e "ami_release_version=$POSTGRES_SUPABASE_VERSION" \ -e "internal_artifacts_bucket=${{ secrets.ARTIFACTS_BUCKET }}" \ - -e "postgres_major_version=${{ matrix.postgres_version }}" \ - -e "arch=${{ matrix.arch.name }}" \ + -e "postgres_major_version=$POSTGRES_MAJOR_VERSION" \ + -e "arch=${{ matrix.target.arch }}" \ manifest-playbook.yml - name: Upload nix flake revision to s3 staging run: | - aws s3 cp /tmp/pg_binaries.tar.gz s3://${{ secrets.ARTIFACTS_BUCKET }}/upgrades${{ steps.arch_version.outputs.arch_suffix }}/postgres/supabase-postgres-${{ steps.arch_version.outputs.version }}/20.04.tar.gz - aws s3 cp /tmp/pg_binaries.tar.gz s3://${{ secrets.ARTIFACTS_BUCKET }}/upgrades${{ steps.arch_version.outputs.arch_suffix }}/postgres/supabase-postgres-${{ steps.arch_version.outputs.version }}/24.04.tar.gz - aws s3 cp /tmp/pg_binaries.tar.gz s3://${{ secrets.ARTIFACTS_BUCKET }}/upgrades${{ steps.arch_version.outputs.arch_suffix }}/postgres/supabase-postgres-${{ steps.arch_version.outputs.version }}/upgrade_bundle.tar.gz + aws s3 cp /tmp/pg_binaries.tar.gz "s3://${{ secrets.ARTIFACTS_BUCKET }}/upgrades$ARCH_SUFFIX/postgres/supabase-postgres-$POSTGRES_SUPABASE_VERSION/20.04.tar.gz" + aws s3 cp /tmp/pg_binaries.tar.gz "s3://${{ secrets.ARTIFACTS_BUCKET }}/upgrades$ARCH_SUFFIX/postgres/supabase-postgres-$POSTGRES_SUPABASE_VERSION/24.04.tar.gz" + aws s3 cp /tmp/pg_binaries.tar.gz "s3://${{ secrets.ARTIFACTS_BUCKET }}/upgrades$ARCH_SUFFIX/postgres/supabase-postgres-$POSTGRES_SUPABASE_VERSION/upgrade_bundle.tar.gz" - name: configure aws credentials - prod uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 with: role-to-assume: ${{ secrets.PROD_AWS_ROLE }} - aws-region: "us-east-1" + aws-region: ${{ env.AWS_REGION }} - name: Upload software manifest to s3 prod run: | cd ansible ansible-playbook -i localhost \ - -e "ami_release_version=${{ steps.arch_version.outputs.version }}" \ + -e "ami_release_version=$POSTGRES_SUPABASE_VERSION" \ -e "internal_artifacts_bucket=${{ secrets.PROD_ARTIFACTS_BUCKET }}" \ - -e "postgres_major_version=${{ matrix.postgres_version }}" \ - -e "arch=${{ matrix.arch.name }}" \ + -e "postgres_major_version=$POSTGRES_MAJOR_VERSION" \ + -e "arch=${{ matrix.target.arch }}" \ manifest-playbook.yml - name: Upload nix flake revision to s3 prod run: | - aws s3 cp /tmp/pg_binaries.tar.gz s3://${{ secrets.PROD_ARTIFACTS_BUCKET }}/upgrades${{ steps.arch_version.outputs.arch_suffix }}/postgres/supabase-postgres-${{ steps.arch_version.outputs.version }}/20.04.tar.gz - aws s3 cp /tmp/pg_binaries.tar.gz s3://${{ secrets.PROD_ARTIFACTS_BUCKET }}/upgrades${{ steps.arch_version.outputs.arch_suffix }}/postgres/supabase-postgres-${{ steps.arch_version.outputs.version }}/24.04.tar.gz - aws s3 cp /tmp/pg_binaries.tar.gz s3://${{ secrets.PROD_ARTIFACTS_BUCKET }}/upgrades${{ steps.arch_version.outputs.arch_suffix }}/postgres/supabase-postgres-${{ steps.arch_version.outputs.version }}/upgrade_bundle.tar.gz + aws s3 cp /tmp/pg_binaries.tar.gz "s3://${{ secrets.PROD_ARTIFACTS_BUCKET }}/upgrades$ARCH_SUFFIX/postgres/supabase-postgres-$POSTGRES_SUPABASE_VERSION/20.04.tar.gz" + aws s3 cp /tmp/pg_binaries.tar.gz "s3://${{ secrets.PROD_ARTIFACTS_BUCKET }}/upgrades$ARCH_SUFFIX/postgres/supabase-postgres-$POSTGRES_SUPABASE_VERSION/24.04.tar.gz" + aws s3 cp /tmp/pg_binaries.tar.gz "s3://${{ secrets.PROD_ARTIFACTS_BUCKET }}/upgrades$ARCH_SUFFIX/postgres/supabase-postgres-$POSTGRES_SUPABASE_VERSION/upgrade_bundle.tar.gz" - name: GitHub OIDC Auth uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 @@ -229,26 +190,24 @@ jobs: - name: Update nix store path catalog run: | - VERSION="${{ steps.process_release_version.outputs.version }}" GIT_SHA="${{ github.sha }}" - PG_VERSION="${{ matrix.postgres_version }}" - SYSTEM="${{ matrix.arch.nix_system }}" + SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem') # Get store path for this build - STORE_PATH=$(nix eval --raw ".#psql_${PG_VERSION}/bin.outPath") + STORE_PATH=$(nix eval --raw ".#psql_${POSTGRES_MAJOR_VERSION}/bin.outPath") # Each postgres version gets its own catalog file (no race conditions) - CATALOG_S3="s3://${{ secrets.SHARED_AWS_ARTIFACTS_BUCKET }}/nix-catalog/${GIT_SHA}-psql_${PG_VERSION}-${SYSTEM}.json" + CATALOG_S3="s3://${{ secrets.SHARED_AWS_ARTIFACTS_BUCKET }}/nix-catalog/${GIT_SHA}-psql_${POSTGRES_MAJOR_VERSION}-${SYSTEM}.json" # Create catalog JSON for this version jq -n \ - --arg ver "$VERSION" \ + --arg ver "$POSTGRES_SUPABASE_VERSION" \ --arg sha "$GIT_SHA" \ --arg sys "$SYSTEM" \ --arg path "$STORE_PATH" \ '{version: $ver, git_sha: $sha, ($sys): $path}' > /tmp/catalog.json - echo "Catalog for psql_${PG_VERSION}:" + echo "Catalog for psql_${POSTGRES_MAJOR_VERSION}:" cat /tmp/catalog.json # Upload catalog @@ -260,17 +219,16 @@ jobs: - name: Create release uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 with: - name: ${{ steps.arch_version.outputs.release_tag }} - tag_name: ${{ steps.arch_version.outputs.release_tag }} - target_commitish: ${{github.sha}} + name: ${{ env.RELEASE_TAG }} + tag_name: ${{ env.RELEASE_TAG }} + target_commitish: ${{ github.sha }} - name: Create CLI tag for PG 17 - if: matrix.postgres_version == '17' && matrix.arch.name == 'arm64' && github.event_name != 'workflow_dispatch' + if: matrix.postgres_version == '17' && matrix.target.arch == 'arm64' && github.event_name != 'workflow_dispatch' env: GH_TOKEN: ${{ github.token }} run: | - VERSION="${{ steps.process_release_version.outputs.version }}" - CLI_TAG="v${VERSION}-cli" + CLI_TAG="v${POSTGRES_SUPABASE_VERSION}-cli" echo "Creating CLI tag: ${CLI_TAG}" git tag "${CLI_TAG}" "${{ github.sha }}" git push origin "${CLI_TAG}" @@ -280,29 +238,28 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | - VERSION="${{ steps.process_release_version.outputs.version }}" - CLI_TAG="v${VERSION}-cli" + CLI_TAG="v${POSTGRES_SUPABASE_VERSION}-cli" gh workflow run cli-release.yml \ --ref "${CLI_TAG}" \ -f version="${CLI_TAG}" - name: Trigger pg_upgrade_scripts workflow - if: matrix.arch.name == 'arm64' + if: matrix.target.arch == 'arm64' env: GH_TOKEN: ${{ github.token }} run: | gh workflow run publish-nix-pgupgrade-scripts.yml \ --ref "${{ github.ref_name }}" \ - -f postgresVersion="${{ steps.process_release_version.outputs.version }}" + -f postgresVersion="$POSTGRES_SUPABASE_VERSION" - name: Trigger pg_upgrade_bin flake version workflow - if: matrix.arch.name == 'arm64' + if: matrix.target.arch == 'arm64' env: GH_TOKEN: ${{ github.token }} run: | gh workflow run publish-nix-pgupgrade-bin-flake-version.yml \ --ref "${{ github.ref_name }}" \ - -f postgresVersion="${{ steps.process_release_version.outputs.version }}" + -f postgresVersion="$POSTGRES_SUPABASE_VERSION" - name: Slack Notification on Failure if: ${{ failure() }} @@ -319,18 +276,16 @@ jobs: uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 with: role-to-assume: ${{ secrets.DEV_AWS_ROLE }} - aws-region: "us-east-1" + aws-region: ${{ env.AWS_REGION }} - name: Cleanup resources after build if: ${{ always() }} run: | - EXECUTION_ID="${{ env.EXECUTION_ID }}" - aws ec2 --region us-east-1 describe-instances --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" --query "Reservations[].Instances[].InstanceId" --output text | xargs -r aws ec2 terminate-instances --region us-east-1 --instance-ids - aws ec2 --region us-east-1 describe-volumes --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" "Name=status,Values=available" --query "Volumes[*].VolumeId" --output text | xargs -r -n1 aws ec2 --region us-east-1 delete-volume --volume-id + aws ec2 --region "$AWS_REGION" describe-instances --filters "Name=tag:packerExecutionId,Values=${PACKER_EXECUTION_ID}" --query "Reservations[].Instances[].InstanceId" --output text | xargs -r aws ec2 terminate-instances --region "$AWS_REGION" --instance-ids + aws ec2 --region "$AWS_REGION" describe-volumes --filters "Name=tag:packerExecutionId,Values=${PACKER_EXECUTION_ID}" "Name=status,Values=available" --query "Volumes[*].VolumeId" --output text | xargs -r -n1 aws ec2 --region "$AWS_REGION" delete-volume --volume-id - name: Cleanup resources on build cancellation if: ${{ cancelled() }} run: | - EXECUTION_ID="${{ env.EXECUTION_ID }}" - aws ec2 --region us-east-1 describe-instances --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" --query "Reservations[].Instances[].InstanceId" --output text | xargs -r aws ec2 terminate-instances --region us-east-1 --instance-ids - aws ec2 --region us-east-1 describe-volumes --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" "Name=status,Values=available" --query "Volumes[*].VolumeId" --output text | xargs -r -n1 aws ec2 --region us-east-1 delete-volume --volume-id + aws ec2 --region "$AWS_REGION" describe-instances --filters "Name=tag:packerExecutionId,Values=${PACKER_EXECUTION_ID}" --query "Reservations[].Instances[].InstanceId" --output text | xargs -r aws ec2 terminate-instances --region "$AWS_REGION" --instance-ids + aws ec2 --region "$AWS_REGION" describe-volumes --filters "Name=tag:packerExecutionId,Values=${PACKER_EXECUTION_ID}" "Name=status,Values=available" --query "Volumes[*].VolumeId" --output text | xargs -r -n1 aws ec2 --region "$AWS_REGION" delete-volume --volume-id diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 1b5720e82..e3a102487 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -10,7 +10,7 @@ on: permissions: id-token: write - # required by testinfra-ami-build dependent workflows + # required by testinfra-ami-build dependent workflows contents: write packages: write diff --git a/.github/workflows/testinfra-ami-build.yml b/.github/workflows/testinfra-ami-build.yml index ee71c7951..142250d1e 100644 --- a/.github/workflows/testinfra-ami-build.yml +++ b/.github/workflows/testinfra-ami-build.yml @@ -15,6 +15,9 @@ permissions: contents: write id-token: write +env: + AWS_REGION: ap-southeast-1 + jobs: prepare: runs-on: blacksmith-2vcpu-ubuntu-2404 @@ -66,7 +69,7 @@ jobs: uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 with: role-to-assume: ${{ secrets.DEV_AWS_ROLE }} - aws-region: "ap-southeast-1" + aws-region: ${{ env.AWS_REGION }} output-credentials: true role-duration-seconds: 7200 @@ -74,33 +77,28 @@ jobs: uses: ./.github/actions/nix-install-ephemeral with: push-to-cache: 'true' - aws-region: "ap-southeast-1" + aws-region: ${{ env.AWS_REGION }} env: DEV_AWS_ROLE: ${{ secrets.DEV_AWS_ROLE }} NIX_SIGN_SECRET_KEY: ${{ secrets.NIX_SIGN_SECRET_KEY }} - - id: args - uses: mikefarah/yq@065b200af9851db0d5132f50bc10b1406ea5c0a8 # v4.50.1 - with: - cmd: yq 'to_entries | map(select(.value|type == "!!str")) | map(.key + "=" + .value) | join("\n")' 'ansible/vars.yml' - - - run: docker context create builders - - - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - with: - endpoint: builders - - name: Build AMI id: build-ami uses: ./.github/actions/build-ami with: ami_name_prefix: "supabase-postgres-${{ github.run_id }}-${{ matrix.target.arch }}" - ami_regions: '["ap-southeast-1"]' + ami_regions: '["${{ env.AWS_REGION }}"]' arch: ${{ matrix.target.arch }} git_sha: ${{ github.sha }} instance_type: ${{ matrix.target.instance_type }} postgres_version: ${{ matrix.postgres_version }} - region: ap-southeast-1 + region: ${{ env.AWS_REGION }} + + - run: docker context create builders + + - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + with: + endpoint: builders - name: Run tests timeout-minutes: 10 @@ -116,17 +114,17 @@ jobs: if: ${{ cancelled() }} run: | EXECUTION_ID="${{ steps.build-ami.outputs.execution_id }}" - INSTANCE_IDS=$(aws ec2 --region ap-southeast-1 describe-instances --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" --query "Reservations[].Instances[].InstanceId" --output text) + INSTANCE_IDS=$(aws ec2 --region "$AWS_REGION" describe-instances --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" --query "Reservations[].Instances[].InstanceId" --output text) if [ -n "$INSTANCE_IDS" ]; then echo "Terminating packer build instances: $INSTANCE_IDS" - echo "$INSTANCE_IDS" | xargs -r aws ec2 terminate-instances --region ap-southeast-1 --instance-ids + echo "$INSTANCE_IDS" | xargs -r aws ec2 terminate-instances --region "$AWS_REGION" --instance-ids else echo "No packer build instances to clean up" fi - VOLUME_IDS=$(aws ec2 --region ap-southeast-1 describe-volumes --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" "Name=status,Values=available" --query "Volumes[*].VolumeId" --output text) + VOLUME_IDS=$(aws ec2 --region "$AWS_REGION" describe-volumes --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" "Name=status,Values=available" --query "Volumes[*].VolumeId" --output text) if [ -n "$VOLUME_IDS" ]; then echo "Deleting orphaned packer volumes: $VOLUME_IDS" - echo "$VOLUME_IDS" | xargs -r -n1 aws ec2 --region ap-southeast-1 delete-volume --volume-id + echo "$VOLUME_IDS" | xargs -r -n1 aws ec2 --region "$AWS_REGION" delete-volume --volume-id else echo "No orphaned packer volumes to clean up" fi @@ -135,17 +133,17 @@ jobs: if: ${{ always() }} run: | EXECUTION_ID="${{ steps.build-ami.outputs.execution_id }}" - INSTANCE_IDS=$(aws ec2 --region ap-southeast-1 describe-instances --filters "Name=tag:testinfra-run-id,Values=${EXECUTION_ID}" --query "Reservations[].Instances[].InstanceId" --output text) + INSTANCE_IDS=$(aws ec2 --region "$AWS_REGION" describe-instances --filters "Name=tag:testinfra-run-id,Values=${EXECUTION_ID}" --query "Reservations[].Instances[].InstanceId" --output text) if [ -n "$INSTANCE_IDS" ]; then echo "Terminating testinfra instances: $INSTANCE_IDS" - echo "$INSTANCE_IDS" | xargs -r aws ec2 terminate-instances --region ap-southeast-1 --instance-ids || true + echo "$INSTANCE_IDS" | xargs -r aws ec2 terminate-instances --region "$AWS_REGION" --instance-ids || true else echo "No testinfra instances to clean up" fi - VOLUME_IDS=$(aws ec2 --region ap-southeast-1 describe-volumes --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" "Name=status,Values=available" --query "Volumes[*].VolumeId" --output text) + VOLUME_IDS=$(aws ec2 --region "$AWS_REGION" describe-volumes --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" "Name=status,Values=available" --query "Volumes[*].VolumeId" --output text) if [ -n "$VOLUME_IDS" ]; then echo "Deleting orphaned packer volumes: $VOLUME_IDS" - echo "$VOLUME_IDS" | xargs -r -n1 aws ec2 --region ap-southeast-1 delete-volume --volume-id || true + echo "$VOLUME_IDS" | xargs -r -n1 aws ec2 --region "$AWS_REGION" delete-volume --volume-id || true else echo "No orphaned packer volumes to clean up" fi @@ -155,7 +153,7 @@ jobs: run: | EXECUTION_ID="${{ steps.build-ami.outputs.execution_id }}" STAGE2_AMI_IDS=$(aws ec2 describe-images \ - --region ap-southeast-1 \ + --region "$AWS_REGION" \ --owners self \ --filters "Name=tag:packerExecutionId,Values=${EXECUTION_ID}" \ --query 'Images[*].ImageId' \ @@ -164,7 +162,7 @@ jobs: if [ -n "$STAGE2_AMI_IDS" ]; then for ami_id in $STAGE2_AMI_IDS; do echo "Deregistering stage 2 AMI: $ami_id" - aws ec2 deregister-image --region ap-southeast-1 --image-id "$ami_id" || true + aws ec2 deregister-image --region "$AWS_REGION" --image-id "$ami_id" || true done else echo "No stage 2 AMI to clean up" diff --git a/amazon-amd64-nix.pkr.hcl b/amazon-amd64-nix.pkr.hcl index f3d2f4623..454395566 100644 --- a/amazon-amd64-nix.pkr.hcl +++ b/amazon-amd64-nix.pkr.hcl @@ -87,7 +87,10 @@ packer { required_plugins { amazon = { source = "github.com/hashicorp/amazon" - version = "~> 1" + # don't use semver for the version since there's no lock files + # can go back when we can have renovate watching this + # see https://github.com/hashicorp/packer-plugin-amazon/issues/676 + version = "1.8.0" } } } @@ -169,7 +172,7 @@ source "amazon-ebssurrogate" "source" { } communicator = "ssh" - ssh_pty = false + ssh_pty = true ssh_username = "ubuntu" ssh_timeout = "5m" diff --git a/amazon-arm64-nix.pkr.hcl b/amazon-arm64-nix.pkr.hcl index ac64fe350..a5faec3a9 100644 --- a/amazon-arm64-nix.pkr.hcl +++ b/amazon-arm64-nix.pkr.hcl @@ -87,7 +87,10 @@ packer { required_plugins { amazon = { source = "github.com/hashicorp/amazon" - version = "~> 1" + # don't use semver for the version since there's no lock files + # can go back when we can have renovate watching this + # see https://github.com/hashicorp/packer-plugin-amazon/issues/676 + version = "1.8.0" } } } diff --git a/nix/packages/build-ami.nix b/nix/packages/build-ami.nix index f6edd54df..a64136a86 100644 --- a/nix/packages/build-ami.nix +++ b/nix/packages/build-ami.nix @@ -1,10 +1,11 @@ { lib, stdenv, - writeShellApplication, - packer, awscli2, + coreutils, jq, + packer, + writeShellApplication, ... }: @@ -41,14 +42,13 @@ writeShellApplication { name = "build-ami"; runtimeInputs = [ - packer awscli2 + coreutils jq + packer ]; text = '' - set -euo pipefail - set -x # Parse required parameters @@ -63,22 +63,48 @@ writeShellApplication { amd64 | arm64) ;; *) echo "Error: Invalid arch '$ARCH'. Must be 'amd64' or 'arm64'" >&2 && exit 1 ;; esac + + if [[ $0 != "''${BASH_SOURCE[0]}" ]]; then + echo "This file is not to be sourced" >&2 + exit 1 + fi + INPUT_HASH=$(realpath "$0") + INPUT_HASH=''${INPUT_HASH#/nix/store/} + INPUT_HASH=''${INPUT_HASH%%-*} shift 2 + export PACKER_LOG=''${PACKER_LOG:-''${RUNNER_DEBUG:-0}} + on_error=ask + if ''${CI:-false}; then + echo "::notice::Setting packer build -on-error=abort since this is CI, this is different than non-CI runs!" + on_error=abort + elif ! [[ -t 0 ]]; then + echo "stdin is not a tty, so running packer build -on-error=cleanup (default) since there's no one to ask!" >&2 + on_error=cleanup + fi + REGION="''${AWS_REGION:-ap-southeast-1}" - PACKER_SOURCES="${packerSources}" - INPUT_HASH=$(basename "$PACKER_SOURCES" | cut -d- -f1) find_stage1_ami() { set +e + local arch + case $ARCH in + amd64) arch=x86_64 ;; + arm64) arch=arm64 ;; + esac + local filters=( + "Name=architecture,Values=$arch" + "Name=state,Values=available" + "Name=tag:inputHash,Values=$INPUT_HASH" + "Name=tag:postgresVersion,Values=$POSTGRES_VERSION-stage1" + "Name=tag:sourceSha,Values=$GIT_SHA" # This is set by packer via the git-head-version var which is always passed in by the build-ami action + ) + local ami_output ami_output=$(aws ec2 describe-images \ --region "$REGION" \ --owners self \ - --filters \ - "Name=tag:inputHash,Values=$INPUT_HASH" \ - "Name=tag:postgresVersion,Values=$POSTGRES_VERSION-stage1" \ - "Name=state,Values=available" \ + --filters "''${filters[@]}" \ --query 'Images[0].ImageId' \ --output text 2>&1) local exit_code=$? @@ -100,6 +126,17 @@ writeShellApplication { echo "Building stage 1..." echo "Checking for existing AMI..." + if [ -n "''${BUILD_AMI_NIX_FORCE_BUILD_STAGE1:-}" ]; then + if [ "''${BUILD_AMI_NIX_FORCE_BUILD_STAGE1:-}" == true ]; then + echo 'BUILD_AMI_NIX_FORCE_BUILD_STAGE1 == true ... skip search for stage1 AMI' >&2 + find_stage1_ami() { + return + } + else + echo 'BUILD_AMI_NIX_FORCE_BUILD_STAGE1 != true ... will search for stage1 AMI' >&2 + fi + fi + AMI_ID=$(find_stage1_ami) if [ -n "$AMI_ID" ]; then echo "Found existing AMI: $AMI_ID" @@ -122,9 +159,9 @@ writeShellApplication { echo "No cached AMI found" - cd "$PACKER_SOURCES" + cd ${packerSources} packer init "$@" - packer build \ + packer build -on-error=$on_error \ -var-file="development-$ARCH.vars.pkr.hcl" \ -var "input-hash=$INPUT_HASH" \ -var "postgres-version=$POSTGRES_VERSION" \ @@ -157,11 +194,11 @@ writeShellApplication { echo "Found stage 1 AMI: $STAGE1_AMI_ID" packer init stage2-nix-psql.pkr.hcl - packer build \ + packer build -on-error=$on_error \ -var-file="development-$ARCH.vars.pkr.hcl" \ -var-file="common-nix.vars.pkr.hcl" \ - -var "source_ami=$STAGE1_AMI_ID" \ -var "region=$REGION" \ + -var "source_ami=$STAGE1_AMI_ID" \ "$@" if [ -n "''${PACKER_EXECUTION_ID:-}" ]; then