rsyslog/.woodpecker.yml
dvirlabs 1cbe3d4de7
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
fix: Use checksum-based content comparison to avoid permission-based drift false positives
CRITICAL FIX:

Problem: drift-check.yml was using 'copy' module in check_mode, which compares:
  - File content ✓
  - Permissions (owner, group, mode) ✗
  - Ownership ✗

After deploy, files have root:root 0644 permissions. Even though content matches,
the copy module marked files as 'changed' because permissions were being compared.
This caused false OUT_OF_SYNC reports even when configuration was actually synced.

Solution: Use MD5 checksum-based comparison instead:
  - Compare only file CONTENT using stat checksums
  - Ignore permissions/ownership differences
  - This is what matters for config management

Also fixed URLs:
  - Changed back from port 80 to port 5000 (API only)
  - Updated service name to gitops-status-api

Now drift detection only triggers on actual config changes, not permission differences.
After successful deploy, should correctly report SYNCED status.
2026-04-23 13:21:20 +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-api.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 > /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-api.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
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