rsyslog/.woodpecker.yml
dvirlabs 380eaf175a
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
fix: Resolve OUT_OF_SYNC false positive after successful deploy
CRITICAL FIXES:

1. Fix API URL port: 5000 → 80 (.woodpecker.yml)
   - update-gitops-status step was POSTing to wrong port
   - gitops-status-server Service exposes port 80, not 5000
   - This caused silent POST failures that weren't detected

2. Initialize missing_on_server variable (drift-check.yml)
   - Variable was only set inside block scope
   - Could remain undefined if block failed or didn't execute
   - Now initialized to empty list before block runs
   - Prevents undefined variable errors in container environment

3. Fix drift detection logic (drift-check.yml)
   - Changed from: drift_detected uses extra_files_on_server flag
   - Changed to: drift_detected directly checks missing_on_server length
   - Adds safety with | default([]) filter
   - Prevents false positives when extra_files_on_server wasn't set properly

ROOT CAUSE:
The combination of port 5000, uninitialized variables, and flag-based logic
caused the playbook to report OUT_OF_SYNC without listing changed files
(drift_count=0, files=[]). After deployment, server config matches Git,
so drift_detected should be false and playbook should exit 0 with SYNCED status.

Now correctly reports SYNCED after successful deploy.
2026-04-23 13:13:07 +03:00

205 lines
7.9 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# =============================================================================
# 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:80
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 > /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 marked FAILED when drift found so it is visible in the UI.
#
# ─── Woodpecker Cron UI settings ──────────────────────────────────────────
# Name: gitops_sync_check
# Branch: master
# Schedule: */2 * * * *
# ---------------------------------------------------------------------------
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:80
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
chmod +x update-gitops-status.sh
# Capture exit code to determine if drift was detected
set +e
./update-gitops-status.sh
SCRIPT_RC=$?
set -e
if [ "$SCRIPT_RC" -ne 0 ]; then
echo "==> ERROR: Status update failed"
exit 1
fi
# Check sync status to determine pipeline result
# Read the generated JSON or re-run drift check
echo "==> Verifying drift status for pipeline result..."
set +e
ANSIBLE_FORCE_COLOR=false \
ansible-playbook -i ansible/inventory/hosts.yml ansible/playbooks/drift-check.yml > /dev/null 2>&1
DRIFT_RC=$?
set -e
if [ "$DRIFT_RC" -eq 0 ]; then
echo "==> Pipeline SUCCESS: Server is SYNCED with Git"
exit 0
else
echo "==> Pipeline FAILED: OUT OF SYNC - manual drift detected on server"
echo " Check gitops-status-server for detailed file-level drift information"
exit 1
fi
when:
event: cron