name: ci - next/build-golden-image 'on': workflow_dispatch: null concurrency: group: ci-golden-image cancel-in-progress: false permissions: contents: read jobs: validate-scripts: name: Validate - Provisioner Scripts runs-on: apex-debian13 steps: - name: Checkout repository run: "set -euo pipefail\ncase \"$CHECKOUT_REF\" in -*) exit 1;; esac\nGITHUB_SERVER_URL=${GITHUB_SERVER_URL%/}\n\ case \"$GITHUB_SERVER_URL\" in https://git.ermnvldmr.com) ;; *) exit 1;; esac\n\ AUTH=$(printf 'deytenit:%s' \"$CHECKOUT_TOKEN\" | base64 -w0)\nHEADER=\"http.${GITHUB_SERVER_URL}/.extraheader=AUTHORIZATION:\ \ basic $AUTH\"\ngit init \"$GITHUB_WORKSPACE\"\ncd \"$GITHUB_WORKSPACE\"\n\ git remote add origin \"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git\"\ngit -c\ \ \"$HEADER\" fetch --tags origin '+refs/heads/*:refs/remotes/origin/*'\n\ git -c \"$HEADER\" fetch origin \"$CHECKOUT_REF\"\ngit checkout --detach FETCH_HEAD\n\ test \"$(git rev-parse HEAD)\" = \"$GITHUB_SHA\"\nif [ \"$CHECKOUT_SUBMODULES\"\ \ = recursive ]; then\n key_file=$(mktemp \"${RUNNER_TEMP:-/tmp}/hextra-key.XXXXXX\"\ )\n trap 'rm -f \"$key_file\"' EXIT\n umask 077\n printf '%s\\n'\ \ \"$HEXTRA_READ_KEY\" > \"$key_file\"\n chmod 600 \"$key_file\"\n export\ \ GIT_SSH_COMMAND=\"ssh -T -i $key_file -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes\ \ -o HostKeyAlgorithms=ssh-ed25519 -o UserKnownHostsFile=$GITHUB_WORKSPACE/.gitea/known_hosts\"\ \n git submodule update --init --recursive\nfi\nif [ \"$PERSIST_CREDENTIALS\"\ \ = true ]; then\n git config \"http.${GITHUB_SERVER_URL}/.extraheader\"\ \ \"AUTHORIZATION: basic $AUTH\"\nfi\n" env: CHECKOUT_REF: ${{ github.sha }} CHECKOUT_SUBMODULES: 'false' CHECKOUT_TOKEN: ${{ github.token }} PERSIST_CREDENTIALS: 'false' HEXTRA_READ_KEY: '' - name: Validate Shell Script Syntax run: bash -n ci/packer/scripts/*.sh build-image: name: Build - Golden Image needs: validate-scripts runs-on: apex-debian13 outputs: image_name: ${{ steps.vars.outputs.image_name }} steps: - name: Checkout repository run: "set -euo pipefail\ncase \"$CHECKOUT_REF\" in -*) exit 1;; esac\nGITHUB_SERVER_URL=${GITHUB_SERVER_URL%/}\n\ case \"$GITHUB_SERVER_URL\" in https://git.ermnvldmr.com) ;; *) exit 1;; esac\n\ AUTH=$(printf 'deytenit:%s' \"$CHECKOUT_TOKEN\" | base64 -w0)\nHEADER=\"http.${GITHUB_SERVER_URL}/.extraheader=AUTHORIZATION:\ \ basic $AUTH\"\ngit init \"$GITHUB_WORKSPACE\"\ncd \"$GITHUB_WORKSPACE\"\n\ git remote add origin \"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git\"\ngit -c\ \ \"$HEADER\" fetch --tags origin '+refs/heads/*:refs/remotes/origin/*'\n\ git -c \"$HEADER\" fetch origin \"$CHECKOUT_REF\"\ngit checkout --detach FETCH_HEAD\n\ test \"$(git rev-parse HEAD)\" = \"$GITHUB_SHA\"\nif [ \"$CHECKOUT_SUBMODULES\"\ \ = recursive ]; then\n key_file=$(mktemp \"${RUNNER_TEMP:-/tmp}/hextra-key.XXXXXX\"\ )\n trap 'rm -f \"$key_file\"' EXIT\n umask 077\n printf '%s\\n'\ \ \"$HEXTRA_READ_KEY\" > \"$key_file\"\n chmod 600 \"$key_file\"\n export\ \ GIT_SSH_COMMAND=\"ssh -T -i $key_file -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes\ \ -o HostKeyAlgorithms=ssh-ed25519 -o UserKnownHostsFile=$GITHUB_WORKSPACE/.gitea/known_hosts\"\ \n git submodule update --init --recursive\nfi\nif [ \"$PERSIST_CREDENTIALS\"\ \ = true ]; then\n git config \"http.${GITHUB_SERVER_URL}/.extraheader\"\ \ \"AUTHORIZATION: basic $AUTH\"\nfi\n" env: CHECKOUT_REF: ${{ github.sha }} CHECKOUT_SUBMODULES: 'false' CHECKOUT_TOKEN: ${{ github.token }} PERSIST_CREDENTIALS: 'false' HEXTRA_READ_KEY: '' - name: Calculate Image Name id: vars run: 'SHORT_SHA="$(echo ${{ github.sha }} | cut -c1-7)" IMAGE_NAME="com-ermnvldmr-debian-12-k3s-amd64-${SHORT_SHA}.qcow2" echo "image_name=${IMAGE_NAME}" >> "$GITHUB_OUTPUT" ' - name: Install Build Tools run: 'sudo apt-get update sudo apt-get install -y qemu-utils ' - name: Build Debian K3s Golden Image run: 'mkdir -p output-qemu echo "Downloading official Debian 12 cloud image..." curl -fsSL -o base.qcow2 https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2 echo "Expanding disk image to 10G..." qemu-img resize base.qcow2 10G echo "Connecting disk image via NBD..." sudo modprobe nbd max_part=8 sudo qemu-nbd --connect=/dev/nbd0 base.qcow2 sleep 1 sudo partx -u /dev/nbd0 || true echo "Mounting disk filesystem..." sudo mkdir -p /mnt/target sudo mount /dev/nbd0p1 /mnt/target echo "Mounting host virtual filesystems and configuring DNS..." sudo rm -f /mnt/target/etc/resolv.conf echo "nameserver 1.1.1.1" | sudo tee /mnt/target/etc/resolv.conf echo "nameserver 8.8.8.8" | sudo tee -a /mnt/target/etc/resolv.conf sudo mount --bind /dev /mnt/target/dev sudo mount --bind /dev/pts /mnt/target/dev/pts sudo mount --bind /proc /mnt/target/proc sudo mount --bind /sys /mnt/target/sys echo "Copying provisioner scripts..." sudo mkdir -p /mnt/target/tmp/scripts sudo cp ci/packer/scripts/*.sh /mnt/target/tmp/scripts/ sudo cp /opt/ci/assets/k3s /opt/ci/assets/k3s-install.sh /mnt/target/tmp/scripts/ sudo cp /opt/ci/assets/flux-install-local.yaml /mnt/target/tmp/scripts/flux-install.yaml sudo chmod +x /mnt/target/tmp/scripts/*.sh echo "Running provisioner scripts in chroot..." sudo chroot /mnt/target /bin/bash /tmp/scripts/01-base-system.sh sudo chroot /mnt/target /bin/bash /tmp/scripts/02-install-k3s.sh sudo chroot /mnt/target /bin/bash /tmp/scripts/03-cleanup.sh sudo rm -rf /mnt/target/tmp/scripts echo "Unmounting filesystems..." sudo umount /mnt/target/sys sudo umount /mnt/target/proc sudo umount /mnt/target/dev/pts sudo umount /mnt/target/dev sudo umount /mnt/target sudo qemu-nbd --disconnect /dev/nbd0 echo "Compressing and optimizing qcow2 with 2M cluster size..." qemu-img convert -f qcow2 -O qcow2 -o cluster_size=2M -c base.qcow2 output-qemu/com-ermnvldmr-debian-12-k3s-amd64.qcow2 echo "Golden image built successfully." ' - name: Prepare and Upload Image Artifact uses: ./.gitea/actions/upload-artifact with: name: golden-image path: output-qemu/com-ermnvldmr-debian-12-k3s-amd64.qcow2 retention-days: 30 upload-s3: name: Upload - S3 Storage needs: build-image runs-on: apex-debian13 steps: - run: "set -euo pipefail\ncase \"$CHECKOUT_REF\" in -*) exit 1;; esac\nGITHUB_SERVER_URL=${GITHUB_SERVER_URL%/}\n\ case \"$GITHUB_SERVER_URL\" in https://git.ermnvldmr.com) ;; *) exit 1;; esac\n\ AUTH=$(printf 'deytenit:%s' \"$CHECKOUT_TOKEN\" | base64 -w0)\nHEADER=\"http.${GITHUB_SERVER_URL}/.extraheader=AUTHORIZATION:\ \ basic $AUTH\"\ngit init \"$GITHUB_WORKSPACE\"\ncd \"$GITHUB_WORKSPACE\"\n\ git remote add origin \"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git\"\ngit -c\ \ \"$HEADER\" fetch --tags origin '+refs/heads/*:refs/remotes/origin/*'\n\ git -c \"$HEADER\" fetch origin \"$CHECKOUT_REF\"\ngit checkout --detach FETCH_HEAD\n\ test \"$(git rev-parse HEAD)\" = \"$GITHUB_SHA\"\nif [ \"$CHECKOUT_SUBMODULES\"\ \ = recursive ]; then\n key_file=$(mktemp \"${RUNNER_TEMP:-/tmp}/hextra-key.XXXXXX\"\ )\n trap 'rm -f \"$key_file\"' EXIT\n umask 077\n printf '%s\\n'\ \ \"$HEXTRA_READ_KEY\" > \"$key_file\"\n chmod 600 \"$key_file\"\n export\ \ GIT_SSH_COMMAND=\"ssh -T -i $key_file -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes\ \ -o HostKeyAlgorithms=ssh-ed25519 -o UserKnownHostsFile=$GITHUB_WORKSPACE/.gitea/known_hosts\"\ \n git submodule update --init --recursive\nfi\nif [ \"$PERSIST_CREDENTIALS\"\ \ = true ]; then\n git config \"http.${GITHUB_SERVER_URL}/.extraheader\"\ \ \"AUTHORIZATION: basic $AUTH\"\nfi\n" env: CHECKOUT_REF: ${{ github.sha }} CHECKOUT_SUBMODULES: 'false' CHECKOUT_TOKEN: ${{ github.token }} PERSIST_CREDENTIALS: 'false' HEXTRA_READ_KEY: '' - name: Download Image Artifact uses: ./.gitea/actions/download-artifact with: name: golden-image path: output-qemu - name: Upload to Static S3 (/dev/images/) env: AWS_ACCESS_KEY_ID: ${{ secrets.STATIC_AWS_ACCESS_KEY_ID || secrets.COM_ERMNVLDMR_STATIC_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.STATIC_AWS_SECRET_ACCESS_KEY || secrets.COM_ERMNVLDMR_STATIC_AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: ${{ secrets.STATIC_AWS_REGION || secrets.COM_ERMNVLDMR_STATIC_S3_REGION || 'auto' }} S3_ENDPOINT: ${{ secrets.STATIC_S3_ENDPOINT_URL || secrets.COM_ERMNVLDMR_STATIC_S3_ENDPOINT_URL }} S3_BUCKET: ${{ secrets.STATIC_S3_BUCKET || secrets.COM_ERMNVLDMR_STATIC_S3_BUCKET }} IMAGE_NAME: ${{ needs.build-image.outputs.image_name }} run: "mv output-qemu/com-ermnvldmr-debian-12-k3s-amd64.qcow2 \"output-qemu/${IMAGE_NAME}\"\ \nif [ -n \"${S3_BUCKET}\" ] && [ -n \"${AWS_ACCESS_KEY_ID}\" ]; then\n ENDPOINT_FLAG=\"\ \"\n [ -n \"${S3_ENDPOINT}\" ] && ENDPOINT_FLAG=\"--endpoint-url=${S3_ENDPOINT}\"\ \n echo \"Cleaning up older images in dev/images/ to free bucket storage...\"\ \n aws ${ENDPOINT_FLAG} s3 rm \"s3://${S3_BUCKET}/dev/images/\" --recursive\ \ --exclude \"*\" --include \"com-ermnvldmr-debian-12-k3s-*.qcow2\" || true\n\ \ aws ${ENDPOINT_FLAG} s3 cp \"output-qemu/${IMAGE_NAME}\" \"s3://${S3_BUCKET}/dev/images/${IMAGE_NAME}\"\ \n echo \"Golden image uploaded to s3://${S3_BUCKET}/dev/images/${IMAGE_NAME}\"\ \nelse\n echo \"S3 storage secrets not provided; skipping remote S3 upload.\ \ Image artifact is preserved in GitHub Actions run artifacts.\"\nfi\n"