From 4363f8764b44a6bf62f671954642f60f9e76186c Mon Sep 17 00:00:00 2001 From: Todd Lewis Date: Sun, 24 Mar 2024 13:02:13 -0400 Subject: [PATCH] ini_file - support optional spaces around section names (#8075) * ini_file - support optional spaces between section names and their surrounding brackets Some ini files have spaces between some of their section names and the brackets that enclose them. This is documented in the 'openssl.cnf(5)' man page. In order to manage files such as /etc/ssl/openssl.cnf with ini_file before now, one would have to include spaces in the section name like this: section: ' crypto_policy ' option: Options value: UnsafeLegacyRenegotiation This change implements matching section headers with such optional spaces. Existing tasks using the workaround above will continue to work, even in cases where spaces in section headers are subsequently removed. * readability improvement in the test content expressions --------- Co-authored-by: Todd Lewis --- ...5-optional-space-around-section-names.yaml | 2 + plugins/modules/ini_file.py | 4 +- .../targets/ini_file/tasks/main.yml | 3 + .../tasks/tests/07-section_name_spaces.yml | 103 ++++++++++++++++++ 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/8075-optional-space-around-section-names.yaml create mode 100644 tests/integration/targets/ini_file/tasks/tests/07-section_name_spaces.yml diff --git a/changelogs/fragments/8075-optional-space-around-section-names.yaml b/changelogs/fragments/8075-optional-space-around-section-names.yaml new file mode 100644 index 0000000000..2e44555f08 --- /dev/null +++ b/changelogs/fragments/8075-optional-space-around-section-names.yaml @@ -0,0 +1,2 @@ +minor_changes: + - "ini_file - support optional spaces between section names and their surrounding brackets (https://github.com/ansible-collections/community.general/pull/8075)." diff --git a/plugins/modules/ini_file.py b/plugins/modules/ini_file.py index 764c73cd95..ec71a94731 100644 --- a/plugins/modules/ini_file.py +++ b/plugins/modules/ini_file.py @@ -304,9 +304,11 @@ def do_ini(module, filename, section=None, option=None, values=None, before = after = [] section_lines = [] + section_pattern = re.compile(to_text(r'^\[\s*%s\s*]' % re.escape(section.strip()))) + for index, line in enumerate(ini_lines): # find start and end of section - if line.startswith(u'[%s]' % section): + if section_pattern.match(line): within_section = True section_start = index elif line.startswith(u'['): diff --git a/tests/integration/targets/ini_file/tasks/main.yml b/tests/integration/targets/ini_file/tasks/main.yml index dbd922a9c6..0ed3c28172 100644 --- a/tests/integration/targets/ini_file/tasks/main.yml +++ b/tests/integration/targets/ini_file/tasks/main.yml @@ -47,3 +47,6 @@ - name: include tasks to test modify_inactive_option include_tasks: tests/06-modify_inactive_option.yml + + - name: include tasks to test optional spaces in section headings + include_tasks: tests/07-section_name_spaces.yml diff --git a/tests/integration/targets/ini_file/tasks/tests/07-section_name_spaces.yml b/tests/integration/targets/ini_file/tasks/tests/07-section_name_spaces.yml new file mode 100644 index 0000000000..6cdcfef40f --- /dev/null +++ b/tests/integration/targets/ini_file/tasks/tests/07-section_name_spaces.yml @@ -0,0 +1,103 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +## testing support for optional spaces between brackets and section names + +- name: Test-section_name_spaces 1 (does legacy workaround still work) - create test file + ansible.builtin.copy: # noqa risky-file-permissions + dest: "{{ output_file }}" + content: | + [ foo ] + ; bar=baz + +- name: Test-section_name_spaces 1 - update with optional spaces specified + community.general.ini_file: # noqa risky-file-permissions + path: "{{ output_file }}" + section: ' foo ' + option: bar + value: frelt + register: result + +- name: Test-section_name_spaces 1 - read content from output file + ansible.builtin.slurp: + src: "{{ output_file }}" + register: output_content + +- name: Test-section_name_spaces 1 - verify results + vars: + actual_content: "{{ output_content.content | b64decode }}" + expected_content: | + [ foo ] + bar = frelt + ansible.builtin.assert: + that: + - actual_content == expected_content + - result is changed + - result.msg == 'option changed' + + +- name: Test-section_name_spaces 2 (optional spaces omitted) - create test file + ansible.builtin.copy: # noqa risky-file-permissions + dest: "{{ output_file }}" + content: | + [ foo ] + bar=baz" + +- name: Test-section_name_spaces 2 - update without optional spaces + community.general.ini_file: # noqa risky-file-permissions + path: "{{ output_file }}" + section: foo + option: bar + value: frelt + ignore_spaces: true + register: result + +- name: Test-section_name_spaces 2 - read content from output file + ansible.builtin.slurp: + src: "{{ output_file }}" + register: output_content + +- name: Test-section_name_spaces 2 - verify results + vars: + actual_content: "{{ output_content.content | b64decode }}" + expected_content: "[ foo ]\nbar = frelt\n" + ansible.builtin.assert: + that: + - actual_content == expected_content + - result is changed + - result.msg == 'option changed' + + +- name: Test-section_name_spaces 3 (legacy workaround when not required) - create test file + ansible.builtin.copy: # noqa risky-file-permissions + dest: "{{ output_file }}" + content: | + [foo] + ; bar=baz + +- name: Test-section_name_spaces 3 - update with optional spaces specified + community.general.ini_file: # noqa risky-file-permissions + path: "{{ output_file }}" + section: ' foo ' + option: bar + value: frelt + register: result + +- name: Test-section_name_spaces 3 - read content from output file + ansible.builtin.slurp: + src: "{{ output_file }}" + register: output_content + +- name: Test-section_name_spaces 3 - verify results + vars: + actual_content: "{{ output_content.content | b64decode }}" + expected_content: | + [foo] + bar = frelt + ansible.builtin.assert: + that: + - actual_content == expected_content + - result is changed + - result.msg == 'option changed'