New Function: DEV VM
Some checks failed
Deploy / Update Proxmox Dev VMs / Detect changed Proxmox tfvars (push) Successful in 26s
Test / Static Analysis (push) Failing after 25s
Test / Unit Tests — Docker Stack (push) Has been skipped
Test / Unit Tests — K8s Stack (push) Has been skipped
Deploy / Update Proxmox Dev VMs / Provision ${{ matrix.tfvars }} (push) Failing after 32s
Deploy / Update Proxmox Dev VMs / Destroy ${{ matrix.tfvars }} (push) Has been skipped
Test / Integration Test — K8s (k3d) (push) Has been skipped

This commit is contained in:
2026-03-20 10:06:05 +01:00
parent f2bcb77863
commit b2a3e00452
15 changed files with 1733 additions and 42 deletions

View File

@@ -0,0 +1,300 @@
# ─────────────────────────────────────────────────────────────────────────────
# Proxmox dev VM deploy pipeline — mirrors .gitea/workflows/deploy-proxmox.yml
#
# Triggered on pushes to main when files under proxmox/apps/*.tfvars change.
# Two jobs run in sequence:
# provision-proxmox — loops over added/modified tfvars, provisions/updates VMs,
# stores credentials in gopass, runs chained app deploy
# when apps/<devname>-qa.tfvars or k8s/apps/<devname>-qa.tfvars exists
# destroy-proxmox — loops over deleted tfvars, destroys VMs, removes gopass entries
#
# Required GitLab CI/CD variables (in addition to the shared ones):
# PROXMOX_ENDPOINT — https://proxmox.example.com:8006/
# PROXMOX_API_TOKEN — user@pam!tokenid=xxxxxxxx-... (mark as Masked)
# PROXMOX_TLS_INSECURE — "true" when using a self-signed cert (optional)
#
# State key pattern: apps-proxmox/<devname>.tfstate
# gopass paths written by this pipeline:
# infra/ssh-keys/<devname> — SSH private key (if auto-generated)
# infra/kubeconfigs/<devname> — k3s kubeconfig (if vm_role = "k3s")
# ─────────────────────────────────────────────────────────────────────────────
.proxmox_base:
image: ubuntu:22.04
variables:
GIT_DEPTH: "0"
before_script:
- apt-get update -qq && apt-get install -y -qq curl git jq gnupg openssh-client
- |
curl -fsSL https://get.opentofu.org/install-opentofu.sh \
| sh -s -- --install-method=standalone --opentofu-version=$TOFU_VERSION
- |
curl -fsSL https://github.com/gopasspw/gopass/releases/latest/download/gopass-linux-amd64.tar.gz \
| tar xz
mv gopass /usr/local/bin/
- |
echo "$GOPASS_GPG_KEY" | gpg --batch --import
gopass clone "$GOPASS_STORE_REPO"
# ─── Provision / Update ───────────────────────────────────────────────────────
provision-proxmox:
extends: .proxmox_base
stage: deploy
rules:
- if: '$CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"'
changes:
- proxmox/apps/*.tfvars
script:
- |
ADDED_MODIFIED=$(git diff --name-only --diff-filter=ACM \
"$CI_COMMIT_BEFORE_SHA" "$CI_COMMIT_SHA" -- 'proxmox/apps/*.tfvars')
if [ -z "$ADDED_MODIFIED" ]; then
echo "No Proxmox tfvars files added or modified. Nothing to provision."
exit 0
fi
echo "Files to provision: $ADDED_MODIFIED"
FAILED=0
for TFVARS in $ADDED_MODIFIED; do
DEV=$(basename "$TFVARS" .tfvars)
echo ""
echo "══════════════════════════════════════════"
echo " Provisioning VM: $DEV"
echo "══════════════════════════════════════════"
if ! (
set -e
export AWS_ACCESS_KEY_ID="$SEAWEED_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="$SEAWEED_SECRET_KEY"
TLS_INSECURE="${PROXMOX_TLS_INSECURE:-false}"
# ── tofu init with SeaweedFS backend ──
cd proxmox
tofu init \
-backend-config="bucket=tofu-state" \
-backend-config="key=apps-proxmox/$DEV.tfstate" \
-backend-config="endpoint=$SEAWEED_S3_ENDPOINT" \
-backend-config="region=us-east-1" \
-backend-config="force_path_style=true" \
-reconfigure
tofu workspace select "$DEV" 2>/dev/null || tofu workspace new "$DEV"
tofu apply -auto-approve \
-var-file="../$TFVARS" \
-var="proxmox_endpoint=$PROXMOX_ENDPOINT" \
-var="proxmox_api_token=$PROXMOX_API_TOKEN" \
-var="proxmox_tls_insecure=$TLS_INSECURE"
# ── Read VM outputs ──
VM_IP=$(tofu output -raw vm_ip)
VM_ROLE=$(tofu output -raw vm_role)
KEY_GEN=$(tofu output -raw key_was_generated)
CI_USER=$(tofu output -raw cloud_init_user)
echo " VM IP: $VM_IP Role: $VM_ROLE Key generated: $KEY_GEN"
cd ..
# ── Store auto-generated SSH key in gopass ──
if [ "$KEY_GEN" = "true" ]; then
cd proxmox
SSH_KEY=$(tofu output -raw ssh_private_key)
echo "$SSH_KEY" | gopass insert -f "infra/ssh-keys/$DEV"
echo " SSH key stored in gopass at infra/ssh-keys/$DEV"
cd ..
fi
# ── For k3s: wait for k3s and fetch kubeconfig ──
if [ "$VM_ROLE" = "k3s" ]; then
gopass show -o "infra/ssh-keys/$DEV" > /tmp/deploy_key
chmod 600 /tmp/deploy_key
echo " Waiting for k3s to become active on $VM_IP..."
for i in $(seq 1 30); do
if ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 \
-i /tmp/deploy_key "$CI_USER@$VM_IP" \
"systemctl is-active --quiet k3s" 2>/dev/null; then
echo " k3s is active."
break
fi
if [ "$i" -eq 30 ]; then
echo "ERROR: k3s did not become active within 5 minutes."
exit 1
fi
echo " Attempt $i/30 — retrying in 10s..."
sleep 10
done
ssh -o StrictHostKeyChecking=no -i /tmp/deploy_key "$CI_USER@$VM_IP" \
"cat /etc/rancher/k3s/k3s.yaml" \
| sed "s|127.0.0.1|$VM_IP|g" \
| gopass insert -f "infra/kubeconfigs/$DEV"
rm -f /tmp/deploy_key
echo " kubeconfig stored in gopass at infra/kubeconfigs/$DEV"
fi
# ── Chained Docker deploy ──
if [ "$VM_ROLE" = "docker" ] && [ -f "apps/${DEV}-qa.tfvars" ]; then
APP="${DEV}-qa"
echo " Chained Docker deploy: $APP → $VM_IP"
gopass show -o "infra/ssh-keys/$DEV" > /tmp/deploy_key
chmod 600 /tmp/deploy_key
DB_PASSWORD=$(gopass show -o "apps/$APP/db_password" 2>/dev/null || echo "")
GIT_TOKEN=$(gopass show -o "apps/$APP/git_token" 2>/dev/null || echo "")
tofu init \
-backend-config="bucket=tofu-state" \
-backend-config="key=apps/$APP.tfstate" \
-backend-config="endpoint=$SEAWEED_S3_ENDPOINT" \
-backend-config="region=us-east-1" \
-backend-config="force_path_style=true" \
-reconfigure
tofu workspace select "$APP" 2>/dev/null || tofu workspace new "$APP"
tofu apply -auto-approve \
-var-file="apps/${DEV}-qa.tfvars" \
-var="ssh_host=$VM_IP" \
-var="ssh_key_path=/tmp/deploy_key" \
-var="db_password=$DB_PASSWORD" \
-var="openresty_git_token=$GIT_TOKEN"
rm -f /tmp/deploy_key
echo " Chained Docker deploy complete: $APP"
fi
# ── Chained K8s deploy ──
if [ "$VM_ROLE" = "k3s" ] && [ -f "k8s/apps/${DEV}-qa.tfvars" ]; then
APP="${DEV}-qa"
echo " Chained K8s deploy: $APP"
gopass show -o "infra/kubeconfigs/$DEV" > /tmp/kubeconfig
chmod 600 /tmp/kubeconfig
RABBITMQ_PASSWORD=$(gopass show -o "apps/$APP/rabbitmq_password" 2>/dev/null || echo "")
LOKI_AUTH_TOKEN=$(gopass show -o "apps/$APP/loki_token" 2>/dev/null || echo "")
cd k8s
tofu init \
-backend-config="bucket=tofu-state" \
-backend-config="key=apps-k8s/$APP.tfstate" \
-backend-config="endpoint=$SEAWEED_S3_ENDPOINT" \
-backend-config="region=us-east-1" \
-backend-config="force_path_style=true" \
-reconfigure
tofu workspace select "$APP" 2>/dev/null || tofu workspace new "$APP"
tofu apply -auto-approve \
-var-file="../k8s/apps/${DEV}-qa.tfvars" \
-var="kubeconfig_path=/tmp/kubeconfig" \
-var="rabbitmq_password=$RABBITMQ_PASSWORD" \
-var="loki_auth_token=$LOKI_AUTH_TOKEN"
cd ..
rm -f /tmp/kubeconfig
echo " Chained K8s deploy complete: $APP"
fi
echo " Provisioned: $DEV"
); then
echo "ERROR: Provisioning of $DEV failed — continuing with remaining VMs"
FAILED=1
rm -f /tmp/deploy_key /tmp/kubeconfig
fi
done
if [ $FAILED -ne 0 ]; then
echo ""
echo "One or more VM provisioning operations failed. See logs above for details."
exit 1
fi
after_script:
- rm -f /tmp/deploy_key /tmp/kubeconfig
# ─── Destroy (tfvars file deleted) ───────────────────────────────────────────
destroy-proxmox:
extends: .proxmox_base
stage: destroy
rules:
- if: '$CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"'
changes:
- proxmox/apps/*.tfvars
script:
- |
DELETED=$(git diff --name-only --diff-filter=D \
"$CI_COMMIT_BEFORE_SHA" "$CI_COMMIT_SHA" -- 'proxmox/apps/*.tfvars')
if [ -z "$DELETED" ]; then
echo "No Proxmox tfvars files deleted. Nothing to destroy."
exit 0
fi
echo "Files to destroy: $DELETED"
FAILED=0
for TFVARS in $DELETED; do
DEV=$(basename "$TFVARS" .tfvars)
echo ""
echo "══════════════════════════════════════════"
echo " Destroying VM: $DEV"
echo "══════════════════════════════════════════"
if ! (
set -e
# Recover deleted tfvars from git history
git show "$CI_COMMIT_BEFORE_SHA:$TFVARS" > /tmp/${DEV}.tfvars
export AWS_ACCESS_KEY_ID="$SEAWEED_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="$SEAWEED_SECRET_KEY"
TLS_INSECURE="${PROXMOX_TLS_INSECURE:-false}"
cd proxmox
tofu init \
-backend-config="bucket=tofu-state" \
-backend-config="key=apps-proxmox/$DEV.tfstate" \
-backend-config="endpoint=$SEAWEED_S3_ENDPOINT" \
-backend-config="region=us-east-1" \
-backend-config="force_path_style=true" \
-reconfigure
tofu workspace select "$DEV"
tofu destroy -auto-approve \
-var-file="/tmp/${DEV}.tfvars" \
-var="proxmox_endpoint=$PROXMOX_ENDPOINT" \
-var="proxmox_api_token=$PROXMOX_API_TOKEN" \
-var="proxmox_tls_insecure=$TLS_INSECURE"
tofu workspace select default
tofu workspace delete "$DEV"
cd ..
# Remove credentials from gopass
gopass rm -f "infra/ssh-keys/$DEV" 2>/dev/null || true
gopass rm -f "infra/kubeconfigs/$DEV" 2>/dev/null || true
rm -f "/tmp/${DEV}.tfvars"
echo " Destroyed: $DEV"
); then
echo "ERROR: Destroy of $DEV failed — continuing with remaining VMs"
FAILED=1
rm -f "/tmp/${DEV}.tfvars"
fi
done
if [ $FAILED -ne 0 ]; then
echo ""
echo "One or more VM destroy operations failed. See logs above for details."
exit 1
fi
after_script:
- rm -f /tmp/deploy_key /tmp/kubeconfig /tmp/*.tfvars