diff --git a/README.md b/README.md index 0ded2853..837e7825 100644 --- a/README.md +++ b/README.md @@ -403,8 +403,13 @@ These variables are set in the same level of the `logging_inputs`, `logging_outp - `logging_enabled`: When 'true', logging role will deploy specified configuration file set. Default to 'true'. - `logging_mark`: Mark message periodically by immark, if set to `true`. Default to `false`. - `logging_mark_interval`: Interval for `logging_mark` in seconds. Default to `3600`. -- `logging_purge_confs`: `true` or `false`. If `logging_purge_confs` is set to `true`, remove files in rsyslog.d which do not belong to any rpm packages. That includes config files generated by the previous logging role run. -- `logging_reset_confs`: `true` or `false`. If `logging_reset_confs` is set to `true`, reinstall rsyslog package, and restore the pre-existing config files, which restores the default `/etc/rsyslog.conf`. +- `logging_purge_confs`: `true` or `false`. If `logging_purge_confs` is set to + `true`, remove files in rsyslog.d which do not belong to any rpm packages. + That includes config files generated by the previous logging role run. NOTE: + If `/etc/rsyslog.conf` was modified, and you use `logging_purge_confs: true`, + and you are not providing any `logging_inputs`, then the `rsyslog` package + will be uninstalled and reinstalled in order to revert back to the original + system default configuration. - `logging_system_log_dir`: Directory where the local log output files are placed. Default to `/var/log`. ### Update and Delete @@ -430,7 +435,7 @@ logging_flows: outputs: [output_name1] ``` -If you want to remove all the configuration files previously configured, in addition to setting `state: absent` to each logging_inputs and logging_outputs item, add `logging_enabled: false` to the configuration variables as follows. It will eliminate the global and common configuration files, as well. +If you want to remove all the configuration files previously configured, in addition to setting `state: absent` to each logging_inputs and logging_outputs item, add `logging_enabled: false` to the configuration variables as follows. It will eliminate the global and common configuration files, as well. Or, use `logging_purge_confs: true` to wipe out all previous configuration and replace it with your given configuration. ```yaml logging_enabled: false diff --git a/defaults/main.yml b/defaults/main.yml index 9b46a48e..7c6ae2df 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -16,14 +16,11 @@ logging_flows: [] # `logging_purge_confs` is set to `true`, remove files in rsyslog.d which do # not belong to any rpm packages. That includes config files generated by the -# previous logging role run. +# previous logging role run. This will also remove and install the rsyslog +# package in order to revert to the system default /etc/rsyslog.conf if you +# do not provide any logging_inputs logging_purge_confs: false -# If `logging_reset_confs` is set to `true`, reinstall rsyslog package, and -# restore the pre-existing config files, which restores the default -# `/etc/rsyslog.conf`. -logging_reset_confs: false - # Variable to specify the directory to put the local output files to store logs. logging_system_log_dir: /var/log diff --git a/roles/rsyslog/tasks/deploy.yml b/roles/rsyslog/tasks/deploy.yml index d0e96b04..d7699018 100644 --- a/roles/rsyslog/tasks/deploy.yml +++ b/roles/rsyslog/tasks/deploy.yml @@ -31,6 +31,12 @@ - inner_item.options | d() or inner_item.sections | d() - inner_item.state is undefined or inner_item.state != 'absent' notify: restart rsyslogd + register: __rsyslog_deploy_templates + +- name: add deployed templates to global list + set_fact: + __rsyslog_template_results: "{{ + __rsyslog_template_results + [__rsyslog_deploy_templates] }}" - name: Remove role config files from rsyslog.d file: diff --git a/roles/rsyslog/tasks/deploy_nolog.yml b/roles/rsyslog/tasks/deploy_nolog.yml index b6d86762..80f7f37f 100644 --- a/roles/rsyslog/tasks/deploy_nolog.yml +++ b/roles/rsyslog/tasks/deploy_nolog.yml @@ -36,6 +36,12 @@ - inner_item.filename | d() or inner_item.name | d() - inner_item.options | d() or inner_item.sections | d() notify: restart rsyslogd + register: __rsyslog_deploy_nolog_templates + +- name: add deployed templates to global list + set_fact: + __rsyslog_template_results: "{{ + __rsyslog_template_results + [__rsyslog_deploy_nolog_templates] }}" - name: Remove role config files from rsyslog.d with no_log file: diff --git a/roles/rsyslog/tasks/main.yml b/roles/rsyslog/tasks/main.yml index 0f0a4782..8934e443 100644 --- a/roles/rsyslog/tasks/main.yml +++ b/roles/rsyslog/tasks/main.yml @@ -13,6 +13,35 @@ {{ ansible_facts['distribution_version'] }}.yml" when: item is file +# if inputs are given and rsyslog_enabled is true, rsyslog.conf will be +# overwritten, so no need to reinstall package +- name: Reinstall package to restore rsyslog config if purging + when: + - logging_purge_confs | bool | d(false) + - not (rsyslog_inputs and __rsyslog_enabled | bool) + block: + # it is assumed that the only packages providing config files that might + # be modified are the base packages - if this is not so, then additional + # packages will need to be added to this check + - name: Get status of rsyslog packages + command: rpm -V {{ item }} + loop: "{{ __rsyslog_base_packages }}" + register: __rsyslog_package_status + failed_when: false + changed_when: false + args: + warn: false + + - name: Reset original confs - logging package is absent + package: + name: "{{ __rsyslog_base_packages }}" + state: absent + register: __rsyslog_erased + when: __rsyslog_package_status.results | + rejectattr('stdout', 'match', '^package .* is not installed') | + selectattr('stdout', 'search', ' /etc/rsyslog[.]conf($|\n)') | + list | length > 0 + - name: Install/Update required packages package: name: "{{ __rsyslog_base_packages }} + {{ __rsyslog_tls_packages @@ -20,7 +49,14 @@ {{ rsyslog_extra_packages | flatten }}" state: present when: - - __rsyslog_enabled | bool + - __rsyslog_enabled | bool or + (__rsyslog_erased is success and __rsyslog_erased is changed) + +# make sure we do not pollute the global namespace for subsequent runs +# of this role +- name: Reset erased flag + set_fact: + __rsyslog_erased: false - name: Gather package facts package_facts: @@ -66,46 +102,6 @@ path: '{{ __rsyslog_work_dir }}' mode: '0700' - # If logging_purge_confs is set to true, remove files in rsyslog.d - # which do not belong to any rpm packages. That includes config - # files generated by the previous logging role run. - # If logging_reset_confs is set to true, reinstall rsyslog package, - # and restore the pre-existing config files, which restores the - # default /etc/rsyslog.conf. - - name: >- - Purge original conf - remove confs with no owner package and - confs generated by previous logging role. - shell: |- - set -euo pipefail - for conf in $( ls "{{ __rsyslog_config_dir }}" ); do - rstr=$( rpm -qf "{{ __rsyslog_config_dir }}/$conf" 2>&1 || : ) - if [[ $rstr == *"not owned by any package"* ]]; then - # confs generated by the logging role do not belong to - # any rpm packages. - /usr/bin/rm -f "{{ __rsyslog_config_dir }}/$conf" - fi - done - when: logging_purge_confs | bool | d(false) - - - block: - - name: Reset original confs - logging package is absent - package: - name: "{{ __rsyslog_base_packages }}" - state: absent - - - name: Reset original confs - logging package is present - package: - name: "{{ __rsyslog_base_packages }}" - state: present - rescue: - - name: Reset original configuration files failed - fail: - msg: > - Error: Reset {{ __rsyslog_base_packages }} failed. - Please ensure the package(s) are available to install - from the repository. - when: logging_reset_confs | bool | d(false) - - name: "Create logging directory if it does not exist or the ownership and/or modes are different." file: @@ -175,6 +171,11 @@ - inner_item.state is undefined or inner_item.state != 'absent' - inner_item.options | d() or inner_item.sections | d() notify: restart rsyslogd + register: __rsyslog_templates + + - name: Initialize list of template results + set_fact: + __rsyslog_template_results: "{{ [__rsyslog_templates] }}" - name: Remove common config files in rsyslog.d file: @@ -194,6 +195,96 @@ - inner_item.options | d() or inner_item.sections | d() notify: stop rsyslogd + - name: Include input sub-vars + include_vars: + file: "{{ role_path }}/vars/{{ varfile }}" + vars: + varfile: "inputs/{{ input_item.type }}/main.yml" + loop: "{{ rsyslog_inputs }}" + loop_control: + loop_var: input_item + when: + - input_item | d([]) + + - name: Run input sub-tasks + include_tasks: + file: "{{ tasks }}" + vars: + tasks: "{{ role_path }}/tasks/inputs/{{ input_item.type }}/main.yml" + __rsyslog_input: "{{ input_item }}" + loop: '{{ rsyslog_inputs | sort(attribute="type") }}' + loop_control: + extended: yes + loop_var: input_item + when: + - input_item | d([]) + - input_item.type | d() + - input_item.type != "basics" or + (input_item.type == "basics" and + (ansible_loop.previtem is not defined or + (ansible_loop.previtem is defined and + ansible_loop.previtem.type != 'basics'))) + + - name: Include output sub-vars + include_vars: + file: "{{ role_path }}/vars/{{ varfile }}" + vars: + varfile: "outputs/{{ output_item.type }}/main.yml" + loop: "{{ rsyslog_outputs }}" + loop_control: + loop_var: output_item + when: + - output_item | d([]) + - output_item.type | d() + + - name: Run output sub-tasks + include_tasks: + file: "{{ tasks }}" + vars: + tasks: "{{ role_path }}/tasks/outputs/{{ output_item.type }}/main.yml" + __rsyslog_output: "{{ output_item }}" + loop: "{{ rsyslog_outputs }}" + loop_control: + loop_var: output_item + when: + - output_item | d([]) + + - name: Get rsyslog config files not owned by any package + shell: | + set -euo pipefail + for conf in $( ls "{{ __rsyslog_config_dir }}" ); do + rstr=$( rpm -qf "{{ __rsyslog_config_dir }}/$conf" 2>&1 || : ) + if [[ "$rstr" == *"not owned by any package"* ]]; then + echo "{{ __rsyslog_config_dir }}/$conf" + fi + done + register: __rsyslog_confs + failed_when: false + changed_when: false + when: logging_purge_confs | bool | d(false) + + # If logging_purge_confs is set to true, remove files in rsyslog.d + # which do not belong to any rpm packages. That includes config + # files generated by the previous logging role run. + - name: Purge - remove files not generated by current state + file: + path: "{{ item }}" + state: absent + loop: "{{ __rsyslog_files_to_remove }}" + notify: "{{ 'restart rsyslogd' if logging_enabled else 'stop rsyslogd' }}" + when: + - logging_purge_confs | bool | d(false) + - __rsyslog_files_to_remove | length > 0 + vars: + __rsyslog_current_files: "{{ __rsyslog_template_results | + selectattr('results', 'defined') | map(attribute='results') | + flatten | selectattr('dest', 'defined') | map(attribute='dest') | + list | to_nice_json + }}" + __rsyslog_files_to_remove: "{{ + __rsyslog_confs.stdout_lines | difference(__rsyslog_current_files) + }}" + # How to set rsyslog_custom_config_files: # rsyslog_custom_config_files: # - /path/to/custom0.conf @@ -292,60 +383,6 @@ when: - __rsyslog_enabled | bool - - name: Include input sub-vars - include_vars: - file: "{{ role_path }}/vars/{{ varfile }}" - vars: - varfile: "inputs/{{ input_item.type }}/main.yml" - loop: "{{ rsyslog_inputs }}" - loop_control: - loop_var: input_item - when: - - input_item | d([]) - - - name: Run input sub-tasks - include_tasks: - file: "{{ tasks }}" - vars: - tasks: "{{ role_path }}/tasks/inputs/{{ input_item.type }}/main.yml" - __rsyslog_input: "{{ input_item }}" - loop: '{{ rsyslog_inputs | sort(attribute="type") }}' - loop_control: - extended: yes - loop_var: input_item - when: - - input_item | d([]) - - input_item.type | d() - - input_item.type != "basics" or - (input_item.type == "basics" and - (ansible_loop.previtem is not defined or - (ansible_loop.previtem is defined and - ansible_loop.previtem.type != 'basics'))) - - - name: Include output sub-vars - include_vars: - file: "{{ role_path }}/vars/{{ varfile }}" - vars: - varfile: "outputs/{{ output_item.type }}/main.yml" - loop: "{{ rsyslog_outputs }}" - loop_control: - loop_var: output_item - when: - - output_item | d([]) - - output_item.type | d() - - - name: Run output sub-tasks - include_tasks: - file: "{{ tasks }}" - vars: - tasks: "{{ role_path }}/tasks/outputs/{{ output_item.type }}/main.yml" - __rsyslog_output: "{{ output_item }}" - loop: "{{ rsyslog_outputs }}" - loop_control: - loop_var: output_item - when: - - output_item | d([]) - - name: Enable rsyslog service service: name: rsyslog diff --git a/tests/tests_basics_files.yml b/tests/tests_basics_files.yml index 49b71661..ac04a282 100644 --- a/tests/tests_basics_files.yml +++ b/tests/tests_basics_files.yml @@ -386,7 +386,6 @@ - name: END TEST CASE 3; Clean up the deployed config vars: - logging_reset_confs: true logging_enabled: false logging_outputs: - name: files_output0 diff --git a/tests/tests_basics_forwards.yml b/tests/tests_basics_forwards.yml index cf21f3b3..ce9929cd 100644 --- a/tests/tests_basics_forwards.yml +++ b/tests/tests_basics_forwards.yml @@ -569,8 +569,8 @@ - name: END TEST CASE 2; Clean up the deployed config vars: - logging_reset_confs: true logging_enabled: false + logging_purge_confs: true logging_pki_files: - ca_cert_src: "{{ __test_ca_cert }}" cert_src: "{{ __test_cert }}" diff --git a/tests/tests_purge_reset.yml b/tests/tests_purge_reset.yml index ce8ee60d..50a34e19 100644 --- a/tests/tests_purge_reset.yml +++ b/tests/tests_purge_reset.yml @@ -1,14 +1,86 @@ # Test to ensure the logging role successfully runs with # logging_purge_confs and logging_reset_confs set to true. # -- name: Ensure that the role runs with default parameters +- name: Test purge and reset functionality hosts: all - + vars: + __test_default_files_conf: /etc/rsyslog.d/30-output-files-default_files.conf tasks: - - name: default run with purge and reset + - name: ensure rsyslog is installed + package: + name: rsyslog + state: present + + - name: create some unowned config files + copy: + dest: "{{ item }}" + content: "# this is file {{ item }}" + mode: "0444" + loop: + - "/etc/rsyslog.d/unowned1.conf" + - "/etc/rsyslog.d/unowned2.conf" + + - name: modify /etc/rsyslog.conf + lineinfile: + path: /etc/rsyslog.conf + insertafter: EOF + state: present + line: "# this is a modification" + + - name: configure with basics + purge vars: logging_purge_confs: true - logging_reset_confs: true + logging_inputs: + - name: basic_input + type: basics + include_role: + name: linux-system-roles.logging + + # notify restart rsyslogd is executed at the end of this test task. + # thus we have to force to invoke handlers + - name: "Force all notified handlers to run at this point, + not waiting for normal sync points" + meta: flush_handlers + + - name: Ensure config file size and counts + vars: + __conf_count: 5 + __conf_size: less + __conf_files: + - "{{ __test_default_files_conf }}" + __check_systemctl_status: true + include_tasks: tasks/check_daemon_config_files.yml + + - name: Ensure previous test config files are removed + stat: + path: "{{ item }}" + register: __result + failed_when: __result.stat.exists + loop: + - "/etc/rsyslog.d/unowned1.conf" + - "/etc/rsyslog.d/unowned2.conf" + + - name: check1 rsyslog config files + command: ls /etc/rsyslog.d + changed_when: false + + - name: configure with basics + purge again - check for idempotency + vars: + logging_purge_confs: true + logging_inputs: + - name: basic_input + type: basics + include_role: + name: linux-system-roles.logging + + - name: check11 rsyslog config files + command: ls /etc/rsyslog.d + changed_when: false + + - name: run again with purge to erase all config + vars: + logging_purge_confs: true + logging_enabled: false include_role: name: linux-system-roles.logging @@ -25,3 +97,26 @@ __conf_size: more __check_systemctl_status: true include_tasks: tasks/check_daemon_config_files.yml + + - name: Ensure test config files are removed + stat: + path: "{{ item }}" + register: __result + failed_when: __result.stat.exists + loop: + - "{{ __test_default_files_conf }}" + + - name: check2 rsyslog config files + command: ls /etc/rsyslog.d + changed_when: false + + - name: run again with purge and reset to test idempotency + vars: + logging_purge_confs: true + logging_enabled: false + include_role: + name: linux-system-roles.logging + + - name: check3 rsyslog config files + command: ls /etc/rsyslog.d + changed_when: false