name: 02 - Deploy Infrastructure and Stack on: workflow_dispatch: jobs: deploy: runs-on: ubuntu-latest permissions: contents: read packages: read env: TF_VAR_gcp_project: ${{ vars.GCP_PROJECT }} TF_VAR_gcp_region: ${{ vars.GCP_REGION }} TF_VAR_gcp_zone: ${{ vars.GCP_ZONE }} steps: - name: Checkout repository uses: actions/checkout@v4 - name: Validate deploy configuration shell: bash env: SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }} R2_ENDPOINT_URL: ${{ secrets.R2_ENDPOINT_URL }} R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} TURN_SHARED_SECRET: ${{ secrets.TURN_SHARED_SECRET }} GCP_PROJECT: ${{ vars.GCP_PROJECT }} GCP_REGION: ${{ vars.GCP_REGION }} GCP_ZONE: ${{ vars.GCP_ZONE }} TURN_REALM: ${{ vars.TURN_REALM }} CADDY_EMAIL: ${{ vars.CADDY_EMAIL }} run: | set -eu require_value() { local kind="$1" local name="$2" local value="$3" if [ -z "${value}" ]; then echo "::error::Missing required GitHub ${kind} ${name}." >&2 exit 1 fi } require_value "secret" "SSH_PRIVATE_KEY" "${SSH_PRIVATE_KEY}" require_value "secret" "GCP_SA_KEY" "${GCP_SA_KEY}" require_value "secret" "R2_ENDPOINT_URL" "${R2_ENDPOINT_URL}" require_value "secret" "R2_ACCESS_KEY_ID" "${R2_ACCESS_KEY_ID}" require_value "secret" "R2_SECRET_ACCESS_KEY" "${R2_SECRET_ACCESS_KEY}" require_value "secret" "TURN_SHARED_SECRET" "${TURN_SHARED_SECRET}" require_value "variable" "GCP_PROJECT" "${GCP_PROJECT}" require_value "variable" "GCP_REGION" "${GCP_REGION}" require_value "variable" "GCP_ZONE" "${GCP_ZONE}" require_value "variable" "TURN_REALM" "${TURN_REALM}" require_value "variable" "CADDY_EMAIL" "${CADDY_EMAIL}" - name: Prepare SSH key for provisioning shell: bash env: SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} run: | install -m 700 -d "${HOME}/.ssh" printf '%s\n' "${SSH_PRIVATE_KEY}" | tr -d '\r' > "${HOME}/.ssh/id_ed25519" chmod 600 "${HOME}/.ssh/id_ed25519" admin_ssh_public_key="$(ssh-keygen -y -f "${HOME}/.ssh/id_ed25519")" printf 'TF_VAR_admin_ssh_public_key=%s\n' "${admin_ssh_public_key}" >> "${GITHUB_ENV}" - name: Prepare Google credentials file shell: bash run: | credentials_file="${RUNNER_TEMP}/gcp-service-account.json" printf '%s' "${{ secrets.GCP_SA_KEY }}" > "${credentials_file}" chmod 600 "${credentials_file}" echo "GOOGLE_APPLICATION_CREDENTIALS=${credentials_file}" >> "${GITHUB_ENV}" - name: Setup OpenTofu uses: opentofu/setup-opentofu@v1 - name: Write OpenTofu backend config working-directory: ./tofu shell: bash run: | cat > backend.hcl <> "${GITHUB_ENV}" echo "relay_ip=${relay_ip}" >> "${GITHUB_OUTPUT}" - name: Wait for SSH shell: bash run: | for attempt in {1..30}; do if nc -z -w 5 "${STATIC_IP}" 22; then exit 0 fi sleep 10 done echo "SSH did not become reachable on ${STATIC_IP}" >&2 exit 1 - name: Run Ansible Playbook uses: dawidd6/action-ansible-playbook@v2 with: playbook: setup_host.yml directory: ./ansible key: ${{ secrets.SSH_PRIVATE_KEY }} inventory: | [turn_nodes] ${{ steps.tofu.outputs.relay_ip }} ansible_user=ubuntu options: --ssh-common-args='-o StrictHostKeyChecking=no' - name: SCP compose and config files uses: appleboy/scp-action@v0.1.7 with: host: ${{ steps.tofu.outputs.relay_ip }} username: ubuntu key: ${{ secrets.SSH_PRIVATE_KEY }} source: "compose/*" target: "/opt/stoat-turn" strip_components: 1 - name: Deploy Podman compose stack uses: appleboy/ssh-action@v1.0.3 with: host: ${{ steps.tofu.outputs.relay_ip }} username: ubuntu key: ${{ secrets.SSH_PRIVATE_KEY }} script: | set -eu cd /opt/stoat-turn owner_lc="$(printf '%s' "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')" cat > .env <