--- - 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: # ------------------------------------------------------------------------- # 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" - name: Copy new rsyslog.d configs from repo copy: src: ../../files/rsyslog.d/ dest: "{{ rsyslog_config_dir }}/" owner: root group: root mode: "0644" # ------------------------------------------------------------------------- # 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 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: validation_result.rc == 0 - name: Print success status debug: msg: | ✓ rsyslog configuration deployed successfully. Validation passed. Service restarted. when: validation_result.rc == 0