mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-08-05 05:34:22 -07:00
Merge 2707ca0732
into 84b5d38c51
This commit is contained in:
commit
4a5cb44897
3 changed files with 246 additions and 66 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
bugfixes:
|
||||||
|
- "ini_file - fixes adding or replacing a whole section (https://github.com/ansible-collections/community.general/pull/10288)."
|
|
@ -254,6 +254,16 @@ EXAMPLES = r"""
|
||||||
value: xxxxxxxxxxxxxxxxxxxx
|
value: xxxxxxxxxxxxxxxxxxxx
|
||||||
mode: '0600'
|
mode: '0600'
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
|
- name: Add or replace whole section
|
||||||
|
community.general.ini_file:
|
||||||
|
path: /etc/wireguard/wg0.conf
|
||||||
|
section: Peer
|
||||||
|
value: |
|
||||||
|
AllowedIps = 10.4.0.11/32
|
||||||
|
PublicKey = xxxxxxxxxxxxxxxxxxxx
|
||||||
|
mode: '0600'
|
||||||
|
state: present
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
@ -427,72 +437,84 @@ def do_ini(module, filename, section=None, section_has_values=None, option=None,
|
||||||
# 2. edit all the remaining lines where we have a matching option
|
# 2. edit all the remaining lines where we have a matching option
|
||||||
# 3. delete remaining lines where we have a matching option
|
# 3. delete remaining lines where we have a matching option
|
||||||
# 4. insert missing option line(s) at the end of the section
|
# 4. insert missing option line(s) at the end of the section
|
||||||
|
if state == 'present':
|
||||||
if state == 'present' and option:
|
if option:
|
||||||
for index, line in enumerate(section_lines):
|
for index, line in enumerate(section_lines):
|
||||||
if match_function(option, line):
|
if match_function(option, line):
|
||||||
match = match_function(option, line)
|
match = match_function(option, line)
|
||||||
if values and match.group(8) in values:
|
if values and match.group(8) in values:
|
||||||
matched_value = match.group(8)
|
matched_value = match.group(8)
|
||||||
if not matched_value and allow_no_value:
|
if not matched_value and allow_no_value:
|
||||||
|
# replace existing option with no value line(s)
|
||||||
|
newline = u'%s\n' % option
|
||||||
|
option_no_value_present = True
|
||||||
|
else:
|
||||||
|
# replace existing option=value line(s)
|
||||||
|
newline = assignment_format % (option, matched_value)
|
||||||
|
(changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
|
||||||
|
values.remove(matched_value)
|
||||||
|
elif not values and allow_no_value:
|
||||||
# replace existing option with no value line(s)
|
# replace existing option with no value line(s)
|
||||||
newline = u'%s\n' % option
|
newline = u'%s\n' % option
|
||||||
|
(changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
|
||||||
option_no_value_present = True
|
option_no_value_present = True
|
||||||
else:
|
|
||||||
# replace existing option=value line(s)
|
|
||||||
newline = assignment_format % (option, matched_value)
|
|
||||||
(changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
|
|
||||||
values.remove(matched_value)
|
|
||||||
elif not values and allow_no_value:
|
|
||||||
# replace existing option with no value line(s)
|
|
||||||
newline = u'%s\n' % option
|
|
||||||
(changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
|
|
||||||
option_no_value_present = True
|
|
||||||
break
|
|
||||||
|
|
||||||
if state == 'present' and exclusive and not allow_no_value:
|
|
||||||
# override option with no value to option with value if not allow_no_value
|
|
||||||
if len(values) > 0:
|
|
||||||
for index, line in enumerate(section_lines):
|
|
||||||
if not changed_lines[index] and match_function(option, line):
|
|
||||||
newline = assignment_format % (option, values.pop(0))
|
|
||||||
(changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
|
|
||||||
if len(values) == 0:
|
|
||||||
break
|
break
|
||||||
# remove all remaining option occurrences from the rest of the section
|
|
||||||
for index in range(len(section_lines) - 1, 0, -1):
|
|
||||||
if not changed_lines[index] and match_function(option, section_lines[index]):
|
|
||||||
del section_lines[index]
|
|
||||||
del changed_lines[index]
|
|
||||||
changed = True
|
|
||||||
msg = 'option changed'
|
|
||||||
|
|
||||||
if state == 'present':
|
if exclusive and not allow_no_value:
|
||||||
# insert missing option line(s) at the end of the section
|
# override option with no value to option with value if not allow_no_value
|
||||||
for index in range(len(section_lines), 0, -1):
|
if len(values) > 0:
|
||||||
# search backwards for previous non-blank or non-comment line
|
for index, line in enumerate(section_lines):
|
||||||
if not non_blank_non_comment_pattern.match(section_lines[index - 1]):
|
if not changed_lines[index] and match_function(option, line):
|
||||||
if option and values:
|
newline = assignment_format % (option, values.pop(0))
|
||||||
# insert option line(s)
|
(changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
|
||||||
for element in values[::-1]:
|
if len(values) == 0:
|
||||||
# items are added backwards, so traverse the list backwards to not confuse the user
|
break
|
||||||
# otherwise some of their options might appear in reverse order for whatever fancy reason ¯\_(ツ)_/¯
|
# remove all remaining option occurrences from the rest of the section
|
||||||
if element is not None:
|
for index in range(len(section_lines) - 1, 0, -1):
|
||||||
# insert option=value line
|
if not changed_lines[index] and match_function(
|
||||||
section_lines.insert(index, assignment_format % (option, element))
|
option, section_lines[index]
|
||||||
msg = 'option added'
|
):
|
||||||
changed = True
|
del section_lines[index]
|
||||||
elif element is None and allow_no_value:
|
del changed_lines[index]
|
||||||
# insert option with no value line
|
changed = True
|
||||||
section_lines.insert(index, u'%s\n' % option)
|
msg = 'option changed'
|
||||||
msg = 'option added'
|
|
||||||
changed = True
|
# insert missing option line(s) at the end of the section
|
||||||
elif option and not values and allow_no_value and not option_no_value_present:
|
for index in range(len(section_lines), 0, -1):
|
||||||
# insert option with no value line(s)
|
# search backwards for previous non-blank or non-comment line
|
||||||
section_lines.insert(index, u'%s\n' % option)
|
if not non_blank_non_comment_pattern.match(section_lines[index - 1]):
|
||||||
msg = 'option added'
|
if values:
|
||||||
changed = True
|
# insert option line(s)
|
||||||
break
|
for element in values[::-1]:
|
||||||
|
# items are added backwards, so traverse the list backwards to not confuse the user
|
||||||
|
# otherwise some of their options might appear in reverse order for whatever fancy reason ¯\_(ツ)_/¯
|
||||||
|
if element is not None:
|
||||||
|
# insert option=value line
|
||||||
|
section_lines.insert(
|
||||||
|
index, assignment_format % (option, element)
|
||||||
|
)
|
||||||
|
msg = 'option added'
|
||||||
|
changed = True
|
||||||
|
elif element is None and allow_no_value:
|
||||||
|
# insert option with no value line
|
||||||
|
section_lines.insert(index, u'%s\n' % option)
|
||||||
|
msg = 'option added'
|
||||||
|
changed = True
|
||||||
|
elif allow_no_value and not option_no_value_present :
|
||||||
|
# insert option with no value line(s)
|
||||||
|
section_lines.insert(index, u'%s\n' % option)
|
||||||
|
msg = 'option added'
|
||||||
|
changed = True
|
||||||
|
break
|
||||||
|
elif within_section and len(section_lines) > 0 and len(values) > 0:
|
||||||
|
original = ''.join(section_lines[1:])
|
||||||
|
replacement = ''.join(values)
|
||||||
|
if not replacement.endswith('\n'):
|
||||||
|
replacement += '\n'
|
||||||
|
if original != replacement:
|
||||||
|
section_lines = [section_lines[0], replacement]
|
||||||
|
msg = 'section replaced'
|
||||||
|
changed = True
|
||||||
|
|
||||||
if state == 'absent':
|
if state == 'absent':
|
||||||
if option:
|
if option:
|
||||||
|
@ -539,11 +561,20 @@ def do_ini(module, filename, section=None, section_has_values=None, option=None,
|
||||||
for value in condition['values']:
|
for value in condition['values']:
|
||||||
if value not in values:
|
if value not in values:
|
||||||
values.append(value)
|
values.append(value)
|
||||||
if option and values:
|
if option:
|
||||||
for value in values:
|
if values:
|
||||||
ini_lines.append(assignment_format % (option, value))
|
for value in values:
|
||||||
elif option and not values and allow_no_value:
|
ini_lines.append(assignment_format % (option, value))
|
||||||
ini_lines.append(u'%s\n' % option)
|
elif not values and allow_no_value:
|
||||||
|
ini_lines.append('%s\n' % option)
|
||||||
|
else:
|
||||||
|
msg = 'only section added'
|
||||||
|
elif len(values) > 0:
|
||||||
|
replacement = ''.join(values)
|
||||||
|
if not replacement.endswith('\n'):
|
||||||
|
replacement += '\n'
|
||||||
|
ini_lines.append(replacement)
|
||||||
|
msg = 'section added'
|
||||||
else:
|
else:
|
||||||
msg = 'only section added'
|
msg = 'only section added'
|
||||||
changed = True
|
changed = True
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
---
|
||||||
|
# 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 section selection
|
||||||
|
|
||||||
|
- name: test-section 1 - Create starting ini file
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
[drinks]
|
||||||
|
fav = lemonade
|
||||||
|
beverage = orange juice
|
||||||
|
|
||||||
|
dest: "{{ output_file }}"
|
||||||
|
|
||||||
|
- name: test-section 1 - Add new block
|
||||||
|
ini_file:
|
||||||
|
dest: "{{ output_file }}"
|
||||||
|
section: food
|
||||||
|
value: |
|
||||||
|
fav = hamburger
|
||||||
|
beverage = None
|
||||||
|
state: present
|
||||||
|
register: result1
|
||||||
|
|
||||||
|
- name: test-section 1 - Read modified file
|
||||||
|
slurp:
|
||||||
|
src: "{{ output_file }}"
|
||||||
|
register: output_content
|
||||||
|
|
||||||
|
- name: test-section 1 - Create expected result
|
||||||
|
set_fact:
|
||||||
|
expected1: |
|
||||||
|
[drinks]
|
||||||
|
fav = lemonade
|
||||||
|
beverage = orange juice
|
||||||
|
car = volvo
|
||||||
|
|
||||||
|
[food]
|
||||||
|
fav = hamburger
|
||||||
|
beverage = None
|
||||||
|
output1: "{{ output_content.content | b64decode }}"
|
||||||
|
|
||||||
|
- name: test-section 1 - Section was added at end
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result1 is changed
|
||||||
|
- result1.msg == 'section added'
|
||||||
|
- output1 == expected1
|
||||||
|
|
||||||
|
# ----------------
|
||||||
|
|
||||||
|
- name: test-section 2 - Create starting ini file
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
[drinks]
|
||||||
|
fav = lemonade
|
||||||
|
beverage = orange juice
|
||||||
|
|
||||||
|
[drinks]
|
||||||
|
fav = lemonade
|
||||||
|
beverage = pineapple juice
|
||||||
|
|
||||||
|
dest: "{{ output_file }}"
|
||||||
|
|
||||||
|
- name: test-section 2 - Modify starting ini file
|
||||||
|
ini_file:
|
||||||
|
dest: "{{ output_file }}"
|
||||||
|
section: drinks
|
||||||
|
section_has_values:
|
||||||
|
- option: beverage
|
||||||
|
value: pineapple juice
|
||||||
|
value: |
|
||||||
|
fav = lemonade
|
||||||
|
car = volvo
|
||||||
|
state: present
|
||||||
|
register: result1
|
||||||
|
|
||||||
|
- name: test-section 2 - Read modified file
|
||||||
|
slurp:
|
||||||
|
src: "{{ output_file }}"
|
||||||
|
register: output_content
|
||||||
|
|
||||||
|
- name: test-section 2 - Create expected result
|
||||||
|
set_fact:
|
||||||
|
expected1: |
|
||||||
|
[drinks]
|
||||||
|
fav = lemonade
|
||||||
|
beverage = orange juice
|
||||||
|
|
||||||
|
[drinks]
|
||||||
|
fav = lemonade
|
||||||
|
car = volvo
|
||||||
|
output1: "{{ output_content.content | b64decode }}"
|
||||||
|
|
||||||
|
- name: test-section 2 - Second section was replaced with value
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result1 is changed
|
||||||
|
- result1.msg == 'section replaced'
|
||||||
|
- output1 == expected1
|
||||||
|
|
||||||
|
# ----------------
|
||||||
|
|
||||||
|
- name: test-section 3 - Create starting ini file
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
[drinks]
|
||||||
|
fav = lemonade
|
||||||
|
beverage = orange juice
|
||||||
|
|
||||||
|
[drinks]
|
||||||
|
fav = lemonade
|
||||||
|
beverage = pineapple juice
|
||||||
|
|
||||||
|
dest: "{{ output_file }}"
|
||||||
|
|
||||||
|
- name: test-section 3 - Modify starting ini file
|
||||||
|
ini_file:
|
||||||
|
dest: "{{ output_file }}"
|
||||||
|
section: drinks
|
||||||
|
section_has_values:
|
||||||
|
- option: beverage
|
||||||
|
value: pineapple juice
|
||||||
|
state: absent
|
||||||
|
register: result1
|
||||||
|
|
||||||
|
- name: test-section 3 - Read modified file
|
||||||
|
slurp:
|
||||||
|
src: "{{ output_file }}"
|
||||||
|
register: output_content
|
||||||
|
|
||||||
|
- name: test-section 3 - Create expected result
|
||||||
|
set_fact:
|
||||||
|
expected1: |
|
||||||
|
[drinks]
|
||||||
|
fav = lemonade
|
||||||
|
beverage = orange juice
|
||||||
|
output1: "{{ output_content.content | b64decode }}"
|
||||||
|
|
||||||
|
- name: test-section 3 - Section was removed for matching section
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result1 is changed
|
||||||
|
- result1.msg == 'section removed'
|
||||||
|
- output1 == expected1
|
Loading…
Add table
Add a link
Reference in a new issue