From a6a428135088eeb723c9585716dc451057246744 Mon Sep 17 00:00:00 2001 From: Eduard Karacharov Date: Tue, 5 Nov 2024 16:24:51 +0200 Subject: [PATCH] Handle deletion of stale configuration files Now at pre-configure stage, for each directory managed by the role, a task sequence is launched that lists checks for any difference between actual directory contents and expected list of files, and deletes any files not present in expected list. The behavior is controlled by `clickhouse_delete_stale_files` role variable, and enabled by default. Tested via emulation of stale config files presence (side-effect playbook) and additional run of the role on top of it. --- defaults/main.yml | 4 + .../helpers/assert_config_not_exists.yml | 10 +++ molecule/default/molecule.yml | 1 + molecule/default/side_effect.yml | 19 +++++ molecule/default/verify.yml | 11 +++ tasks/helpers/cleanup_stale_files.yml | 32 ++++++++ tasks/pre_configure.yml | 76 ++++++++++++++----- 7 files changed, 135 insertions(+), 18 deletions(-) create mode 100644 molecule/default/helpers/assert_config_not_exists.yml create mode 100644 molecule/default/side_effect.yml create mode 100644 tasks/helpers/cleanup_stale_files.yml diff --git a/defaults/main.yml b/defaults/main.yml index 792e9fc..44a4cac 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -4,6 +4,10 @@ # client - setup only client clickhouse_setup: full +# If deletion of stale configuration files (once managed by the role, +# but deleted from inventory variable later) is allowed +clickhouse_delete_stale_files: true + # NOTE: It is not recommended to use "latest", you should always pin version! # clickhouse_version: "" diff --git a/molecule/default/helpers/assert_config_not_exists.yml b/molecule/default/helpers/assert_config_not_exists.yml new file mode 100644 index 0000000..5e35b80 --- /dev/null +++ b/molecule/default/helpers/assert_config_not_exists.yml @@ -0,0 +1,10 @@ +--- +- name: Collect config file stats + stat: + path: "{{ item }}" + register: __config_exists__ + +- name: Assert config file not exists + assert: + that: "{{ not __config_exists__.stat.exists }}" + fail_msg: "Configuration file {{ item }} exists" diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 44776ce..fdcb35f 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -48,6 +48,7 @@ scenario: - converge - idempotence - side_effect + - converge - verify - cleanup - destroy diff --git a/molecule/default/side_effect.yml b/molecule/default/side_effect.yml new file mode 100644 index 0000000..aad777f --- /dev/null +++ b/molecule/default/side_effect.yml @@ -0,0 +1,19 @@ +--- +- name: Side effect + hosts: all + gather_facts: false + + tasks: + - name: Emulating stale configuration files + file: + path: "{{ item }}" + state: touch + with_items: + - /etc/clickhouse-server/config.d/00-stale-role-defined-override.yml + - /etc/clickhouse-server/config.d/99-stale-user-defined-override.yml + - /etc/clickhouse-server/users.d/99-stale-user-configuration.yml + - /etc/clickhouse-server/dictionary.d/stale-dictionary.xml + - /var/lib/clickhouse/format_schemas/stale.proto + - /var/lib/clickhouse/top_level_domains/stale_tld.dat + - /etc/clickhouse-client/format_schemas/stale.proto + when: clickhouse_setup == "full" diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 8b798c2..43158de 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -162,6 +162,17 @@ with_items: - "{{ user_defined_user_overrides }}" + - name: Assert stale configuration files have been deleted + include_tasks: ./helpers/assert_config_not_exists.yml + with_items: + - /etc/clickhouse-server/config.d/00-stale-role-defined-override.yml + - /etc/clickhouse-server/config.d/99-stale-user-defined-override.yml + - /etc/clickhouse-server/users.d/99-stale-user-configuration.yml + - /etc/clickhouse-server/dictionary.d/stale-dictionary.xml + - /var/lib/clickhouse/format_schemas/stale.proto + - /var/lib/clickhouse/top_level_domains/stale_tld.dat + - /etc/clickhouse-client/format_schemas/stale.proto + - name: Assert configuration has been applied correctly include_tasks: ./helpers/assert_query_result.yml with_items: diff --git a/tasks/helpers/cleanup_stale_files.yml b/tasks/helpers/cleanup_stale_files.yml new file mode 100644 index 0000000..21d5836 --- /dev/null +++ b/tasks/helpers/cleanup_stale_files.yml @@ -0,0 +1,32 @@ +--- +# Sequence of tasks to detect and delete, if allowed, the files not +# managed by the role anymore +- name: List files + find: + paths: "{{ item.cleanup_directory }}" + patterns: "{{ item.pattern }}" + register: __cleanup_directory_files__ +- name: Check for stale files + set_fact: + __stale_files__: "{{ + __cleanup_directory_files__.files | map(attribute='path') | map('basename') | + difference(item.expected_files) + }}" +- name: Files found, but cannot be deleted + fail: + msg: | + Following stale files are found in {{ item.cleanup_directory }}: + {{ _stale_files | join(', ') }}, but file deletion is not allowed. + To delete these files, set `clickhouse_delete_stale_files` variable + to `true`. + when: __stale_files__ | length != 0 and not clickhouse_delete_stale_files + ignore_errors: true +- name: Delete stale files + file: + path: "{{ item.cleanup_directory }}/{{ stale }}" + state: absent + with_items: "{{ __stale_files__ }}" + loop_control: + loop_var: stale + notify: "{{ item.restart | ternary(['restart-clickhouse'], []) }}" + when: clickhouse_delete_stale_files diff --git a/tasks/pre_configure.yml b/tasks/pre_configure.yml index ec7594e..c5d9f2d 100644 --- a/tasks/pre_configure.yml +++ b/tasks/pre_configure.yml @@ -106,7 +106,7 @@ - name: Install attributes for the configuration files no_log: true vars: - common: + common_server_configs: # NOTE: role has "00-" prefix to give this override lowest priority - clickhouse-server/config.d/00-logger.yml - clickhouse-server/config.d/00-system_log.yml @@ -131,11 +131,11 @@ - file: clickhouse-server/config.d/00-memory.yml no_restart: true set_fact: - _configs: "{{ _configs | default([]) + ((item is mapping) | ternary( + _server_configs: "{{ _server_configs | default([]) + ((item is mapping) | ternary( [{'file': item.file, 'no_log': item.no_log | default(False), 'no_restart': item.no_restart | default(False)}], [{'file': item, 'no_log': False, 'no_restart': False}] )) }}" # noqa: jinja[spacing] - loop: "{{ common + clickhouse_configuration_files + _config_no_restart | default([]) }}" + loop: "{{ common_server_configs + clickhouse_configuration_files + _config_no_restart | default([]) }}" - name: Deploy clickhouse-server config overrides (requires restart) template: src: "{{ item.file }}.j2" @@ -145,7 +145,7 @@ mode: "u=r,go=" notify: restart-clickhouse no_log: "{{ item.no_log }}" - loop: "{{ _configs | selectattr('no_restart', 'eq', False) }}" + loop: "{{ _server_configs | selectattr('no_restart', 'eq', False) }}" - name: Deploy clickhouse-server config overrides (without restart) template: src: "{{ item.file }}.j2" @@ -154,18 +154,21 @@ group: clickhouse mode: "u=r,go=" no_log: "{{ item.no_log }}" - loop: "{{ _configs | selectattr('no_restart', 'eq', True) }}" - - name: Deploy role default clickhouse-server users overrides (requires restart) - template: - src: "{{ item }}.j2" - dest: "/etc/clickhouse-server/users.d/{{ item | basename }}" - owner: clickhouse - group: clickhouse - mode: "u=r,go=" - notify: restart-clickhouse - loop: - - clickhouse-server/users.d/00-overrides.yml - - name: Deploy user provided clickhouse-server users overrides (requires restart) + loop: "{{ _server_configs | selectattr('no_restart', 'eq', True) }}" + - name: Set attributes for user configuration files + no_log: true + vars: + common_user_configs: + - clickhouse-server/users.d/00-overrides.yml + set_fact: + _user_configs: "{{ + _user_configs | default([]) + ((item is mapping) | ternary( + [{'file': item.file, 'no_log': item.no_log | default(False)}], + [{'file': item, 'no_log': False}] + )) + }}" # noqa: jinja[spacing] + loop: "{{ common_user_configs + clickhouse_user_files | default([]) }}" + - name: Deploy clickhouse-server users overrides (requires restart) template: src: "{{ (item is mapping) | ternary(item.file, item) }}.j2" dest: "/etc/clickhouse-server/users.d/{{ (item is mapping) | ternary(item.file, item) | basename }}" @@ -173,8 +176,8 @@ group: clickhouse mode: "u=r,go=" notify: restart-clickhouse - no_log: "{{ (item is mapping) | ternary(item.no_log, False) }}" - loop: "{{ clickhouse_user_files }}" + no_log: "{{ item.no_log }}" + loop: "{{ _user_configs }}" - name: Deploy dictionaries configuration (requires restart) template: src: "{{ item }}.j2" @@ -185,6 +188,23 @@ loop: "{{ clickhouse_dictionaries_config_files }}" notify: restart-clickhouse +- name: Cleanup stale server configuration files + when: clickhouse_setup == "full" + include_tasks: ./helpers/cleanup_stale_files.yml + with_items: + - cleanup_directory: /etc/clickhouse-server/config.d + expected_files: "{{ _server_configs | map(attribute='file') | map('basename') }}" + pattern: "*.yml" + restart: true + - cleanup_directory: /etc/clickhouse-server/users.d + expected_files: "{{ _user_configs | map(attribute='file') | map('basename') }}" + pattern: "*.yml" + restart: true + - cleanup_directory: "{{ clickhouse_dictionaries_config_path }}" + expected_files: "{{ clickhouse_dictionaries_config_files | map('basename') }}" + pattern: "*" + restart: true + # format_schemas and top_level_domains by default are created by server process # according to `umask` server configuration parameter. # The role follows default ClickHouse umask value and gives full permissions to @@ -223,6 +243,19 @@ notify: restart-clickhouse loop: "{{ clickhouse_format_schema_files }}" +- name: Cleanup stale user files + when: clickhouse_setup == "full" + include_tasks: ./helpers/cleanup_stale_files.yml + with_items: + - cleanup_directory: "{{ clickhouse_top_level_domains_path }}" + expected_files: "{{ clickhouse_top_level_domains_lists_files | map('basename') }}" + pattern: "*" + restart: true + - cleanup_directory: "{{ clickhouse_format_schema_path }}" + expected_files: "{{ clickhouse_format_schema_files | map('basename') }}" + pattern: "*" + restart: true + - name: Create clickhouse-server additional data directories file: dest: "{{ item.path }}" @@ -269,3 +302,10 @@ group: root loop: - clickhouse-client/config.xml + - name: Cleanup stale format schemas + include_tasks: ./helpers/cleanup_stale_files.yml + with_items: + - cleanup_directory: /etc/clickhouse-client/format_schemas + expected_files: "{{ clickhouse_format_schema_files | map('basename') }}" + pattern: "*" + restart: false