From 2f580459d43dc2cbf78e52c44d653d2b895499d9 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Fri, 17 Apr 2026 18:16:46 +0300 Subject: [PATCH] test --- .woodpecker.yml | 3 + ansible/playbooks/apply.yml | 112 +++++++++++++++++++++++++++++++----- 2 files changed, 101 insertions(+), 14 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 6150a34..01a4d3b 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -8,6 +8,7 @@ steps: validate: image: alpine/ansible:latest + depends_on: [syntax-check] environment: ANSIBLE_CONFIG: ansible.cfg SSH_PRIVATE_KEY: @@ -20,6 +21,7 @@ steps: drift-check: image: alpine/ansible:latest + depends_on: [syntax-check] environment: ANSIBLE_CONFIG: ansible.cfg SSH_PRIVATE_KEY: @@ -34,6 +36,7 @@ steps: deploy: image: alpine/ansible:latest + depends_on: [syntax-check, validate] environment: ANSIBLE_CONFIG: ansible.cfg SSH_PRIVATE_KEY: diff --git a/ansible/playbooks/apply.yml b/ansible/playbooks/apply.yml index d562293..3f5d324 100644 --- a/ansible/playbooks/apply.yml +++ b/ansible/playbooks/apply.yml @@ -1,39 +1,123 @@ --- -- name: Apply rsyslog configuration +- name: Apply rsyslog configuration (safe staged deployment) hosts: rsyslog_servers become: true + vars: + backup_dir: /var/backups/rsyslog-ansible + backup_conf: "{{ backup_dir }}/rsyslog.conf.bak" + backup_confd: "{{ backup_dir }}/rsyslog.d.bak" + tasks: - - name: Copy rsyslog main configuration + + # ------------------------------------------------------------------------- + # STAGE 1 — Backup current working configuration + # ------------------------------------------------------------------------- + + - name: Ensure backup directory exists + file: + path: "{{ backup_dir }}" + state: directory + mode: "0700" + + - name: Backup current rsyslog.conf + copy: + src: "{{ rsyslog_main_config }}" + dest: "{{ backup_conf }}" + remote_src: true + mode: "0600" + + - name: Remove stale rsyslog.d backup + file: + path: "{{ backup_confd }}" + state: absent + + - name: Backup current rsyslog.d directory + copy: + src: "{{ rsyslog_config_dir }}/" + dest: "{{ backup_confd }}/" + remote_src: true + + # ------------------------------------------------------------------------- + # STAGE 2 — Deploy new configuration files from repo + # ------------------------------------------------------------------------- + + - name: Copy new rsyslog.conf from repo copy: src: ../../files/rsyslog.conf dest: "{{ rsyslog_main_config }}" owner: root group: root - mode: '0644' - backup: true - register: main_config_copied + mode: "0644" - - name: Copy rsyslog.d configurations + - name: Copy new rsyslog.d configs from repo copy: src: ../../files/rsyslog.d/ dest: "{{ rsyslog_config_dir }}/" owner: root group: root - mode: '0644' - register: config_dir_copied + mode: "0644" - - name: Validate rsyslog configuration - command: rsyslogd -N1 + # ------------------------------------------------------------------------- + # STAGE 3 — Validate against the full real config tree on the remote host + # Runs rsyslogd -N1 against the actual /etc/rsyslog.conf so all includes, + # modules, and templates are resolved in the real environment. + # ------------------------------------------------------------------------- + + - name: Validate new configuration on remote host + command: rsyslogd -N1 -f "{{ rsyslog_main_config }}" + register: validation_result changed_when: false - when: main_config_copied.changed or config_dir_copied.changed + failed_when: false # We handle failure manually below + + # ------------------------------------------------------------------------- + # STAGE 4a — Validation FAILED: restore backup and abort + # ------------------------------------------------------------------------- + + - name: Print validation error output + debug: + msg: | + ✗ Validation failed! + stdout: {{ validation_result.stdout | default('(empty)') }} + stderr: {{ validation_result.stderr | default('(empty)') }} + when: validation_result.rc != 0 + + - name: Restore rsyslog.conf from backup + copy: + src: "{{ backup_conf }}" + dest: "{{ rsyslog_main_config }}" + remote_src: true + mode: "0644" + when: validation_result.rc != 0 + + - name: Restore rsyslog.d from backup + copy: + src: "{{ backup_confd }}/" + dest: "{{ rsyslog_config_dir }}/" + remote_src: true + when: validation_result.rc != 0 + + - name: Fail pipeline — config restored to previous working state + fail: + msg: > + rsyslog configuration validation failed (rc={{ validation_result.rc }}). + The previous working config has been restored. No service restart was performed. + stderr: {{ validation_result.stderr | default('(empty)') }} + when: validation_result.rc != 0 + + # ------------------------------------------------------------------------- + # STAGE 4b — Validation PASSED: restart rsyslog and report success + # ------------------------------------------------------------------------- - name: Restart rsyslog service service: name: "{{ rsyslog_service }}" state: restarted - when: main_config_copied.changed or config_dir_copied.changed + when: validation_result.rc == 0 - - name: Display apply result + - name: Print success status debug: - msg: "✓ rsyslog configuration applied successfully" \ No newline at end of file + msg: | + ✓ rsyslog configuration deployed successfully. + Validation passed. Service restarted. + when: validation_result.rc == 0 \ No newline at end of file