# ============================================================================= # Single pipeline – all event types handled via step-level when conditions: # # pull_request → syntax-check, validate # ONLY validates config correctness. # Does NOT compare to the live server – a PR branch is # expected to differ from the server (not yet deployed), # so a drift-check here would always be OUT_OF_SYNC by # design and is meaningless as a failure signal. # # push (master) → syntax-check, validate, deploy, update-gitops-status # Deploys to the server, then verifies sync and sends # JSON status snapshot to gitops-status-server for Grafana. # # cron → gitops_sync_check (read-only drift check, no deploy) # Continuously verifies that the live server still matches # Git even when no push has happened. Detects manual edits # made directly on the server. Sends JSON status with # detailed file-level drift information to gitops-status-server. # # NOTE: Woodpecker does not support multiple YAML documents (---) in one file. # All pipelines must live in a single document with step-level filtering. # ============================================================================= when: - event: pull_request - event: push branch: master - event: cron steps: # --------------------------------------------------------------------------- # syntax-check: Lint all playbooks – runs on pull_request and push # --------------------------------------------------------------------------- syntax-check: image: alpine/ansible:latest environment: ANSIBLE_CONFIG: ansible.cfg commands: - ansible-playbook -i ansible/inventory/hosts.yml --syntax-check ansible/playbooks/*.yml when: - event: pull_request - event: push branch: master # --------------------------------------------------------------------------- # validate: Validate server state – runs on pull_request and push # --------------------------------------------------------------------------- validate: image: alpine/ansible:latest depends_on: [syntax-check] environment: ANSIBLE_CONFIG: ansible.cfg SSH_PRIVATE_KEY: from_secret: SSH_PRIVATE_KEY commands: - mkdir -p ~/.ssh - printf '%s\n' "$${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - ansible-playbook -i ansible/inventory/hosts.yml ansible/playbooks/validate.yml when: - event: pull_request - event: push branch: master # --------------------------------------------------------------------------- # deploy: Apply Git configuration to server – runs on push to master only # --------------------------------------------------------------------------- deploy: image: alpine/ansible:latest depends_on: [syntax-check, validate] environment: ANSIBLE_CONFIG: ansible.cfg SSH_PRIVATE_KEY: from_secret: SSH_PRIVATE_KEY commands: - mkdir -p ~/.ssh - printf '%s\n' "$${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - ansible-playbook -i ansible/inventory/hosts.yml ansible/playbooks/apply.yml when: branch: master event: push # --------------------------------------------------------------------------- # update-gitops-status: Post-deploy sync check + JSON status update # Runs on push to master only, after deploy succeeds. # Generates structured JSON with sync status, drift count, and changed files. # Sends JSON to gitops-status-server for Grafana visualization. # --------------------------------------------------------------------------- update-gitops-status: image: alpine/ansible:latest depends_on: [deploy] environment: ANSIBLE_CONFIG: ansible.cfg SSH_PRIVATE_KEY: from_secret: SSH_PRIVATE_KEY GITOPS_STATUS_SERVER_URL: http://gitops-status-server.observability-stack.svc.cluster.local:5000 REPO_NAME: rsyslog SERVER_NAME: rsyslog-lab MODE: post-deploy # Optimize Ansible for container environment ANSIBLE_HOST_KEY_CHECKING: "False" ANSIBLE_FORCE_COLOR: "False" ANSIBLE_RETRY_FILES_ENABLED: "False" ANSIBLE_UNSAFE_WRITES: "True" ANSIBLE_FORKS: "1" commands: - | # Increase file descriptor limit for Ansible (max safe value) ulimit -n 65536 # Install dependencies: git for detecting deployed files, curl for HTTP requests, jq for JSON formatting apk add --no-cache git curl jq > /dev/null 2>&1 # Setup SSH key for Ansible mkdir -p ~/.ssh printf '%s\n' "$${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa echo "==> Running post-deploy GitOps status check..." # Make script executable and run it chmod +x update-gitops-status.sh ./update-gitops-status.sh echo "==> JSON status update complete. Pipeline always succeeds." when: branch: master event: push # --------------------------------------------------------------------------- # gitops_sync_check: ArgoCD-style cron drift check – read-only, no deploy # Detects manual changes made directly on the server between pushes. # Generates structured JSON with sync status, drift count, and changed files. # Sends JSON to gitops-status-server for continuous GitOps monitoring. # Pipeline always succeeds - check Grafana dashboard for drift status. # # ─── Woodpecker Cron UI settings ────────────────────────────────────────── # Name: gitops_sync_check # Branch: master # Schedule: */1 * * * * (every 1 minute for testing, adjust as needed) # --------------------------------------------------------------------------- gitops_sync_check: image: alpine/ansible:latest environment: ANSIBLE_CONFIG: ansible.cfg SSH_PRIVATE_KEY: from_secret: SSH_PRIVATE_KEY GITOPS_STATUS_SERVER_URL: http://gitops-status-server.observability-stack.svc.cluster.local:5000 REPO_NAME: rsyslog SERVER_NAME: rsyslog-lab # Optimize Ansible for container environment ANSIBLE_HOST_KEY_CHECKING: "False" ANSIBLE_FORCE_COLOR: "False" ANSIBLE_RETRY_FILES_ENABLED: "False" ANSIBLE_UNSAFE_WRITES: "True" ANSIBLE_FORKS: "1" commands: - | # Increase file descriptor limit for Ansible (max safe value) ulimit -n 65536 # Install dependencies: curl for HTTP requests, jq for JSON formatting apk add --no-cache curl jq bash > /dev/null 2>&1 # Setup SSH key for Ansible mkdir -p ~/.ssh printf '%s\n' "$${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa echo "==> [cron] Running continuous GitOps drift check..." # Make script executable and run it (always succeeds - just updates JSON) chmod +x update-gitops-status.sh ./update-gitops-status.sh echo "==> Cron drift check complete. JSON status updated successfully." echo " Pipeline always succeeds. Check gitops-status-server for sync status." when: event: cron