Skip to content

Commit

Permalink
ansible-config dedupe ini plugin entries
Browse files Browse the repository at this point in the history
 added test for ini file integrity, also ensuring no dupes
  • Loading branch information
bcoca committed Jan 8, 2024
1 parent c75624f commit c5e950c
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 14 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/dedupe_config_init.yml
@@ -0,0 +1,2 @@
bugfixes:
- ansible-config init will now dedupe ini entries from plugins.
36 changes: 22 additions & 14 deletions lib/ansible/cli/config.py
Expand Up @@ -313,7 +313,7 @@ def _get_settings_vars(self, settings, subkey):

return data

def _get_settings_ini(self, settings):
def _get_settings_ini(self, settings, seen):

sections = {}
for o in sorted(settings.keys()):
Expand All @@ -326,7 +326,7 @@ def _get_settings_ini(self, settings):

if not opt.get('description'):
# its a plugin
new_sections = self._get_settings_ini(opt)
new_sections = self._get_settings_ini(opt, seen)
for s in new_sections:
if s in sections:
sections[s].extend(new_sections[s])
Expand All @@ -342,37 +342,45 @@ def _get_settings_ini(self, settings):

if 'ini' in opt and opt['ini']:
entry = opt['ini'][-1]
if entry['section'] not in seen:
seen[entry['section']] = []
if entry['section'] not in sections:
sections[entry['section']] = []

default = opt.get('default', '')
if opt.get('type', '') == 'list' and not isinstance(default, string_types):
# python lists are not valid ini ones
default = ', '.join(default)
elif default is None:
default = ''
# avoid dupes
if entry['key'] not in seen[entry['section']]:
seen[entry['section']].append(entry['key'])

default = opt.get('default', '')
if opt.get('type', '') == 'list' and not isinstance(default, string_types):
# python lists are not valid ini ones
default = ', '.join(default)
elif default is None:
default = ''

if context.CLIARGS['commented']:
entry['key'] = ';%s' % entry['key']

if context.CLIARGS['commented']:
entry['key'] = ';%s' % entry['key']
key = desc + '\n%s=%s' % (entry['key'], default)

key = desc + '\n%s=%s' % (entry['key'], default)
sections[entry['section']].append(key)
sections[entry['section']].append(key)

return sections

def execute_init(self):
"""Create initial configuration"""

seen = {}
data = []
config_entries = self._list_entries_from_args()
plugin_types = config_entries.pop('PLUGINS', None)

if context.CLIARGS['format'] == 'ini':
sections = self._get_settings_ini(config_entries)
sections = self._get_settings_ini(config_entries, seen)

if plugin_types:
for ptype in plugin_types:
plugin_sections = self._get_settings_ini(plugin_types[ptype])
plugin_sections = self._get_settings_ini(plugin_types[ptype], seen)
for s in plugin_sections:
if s in sections:
sections[s].extend(plugin_sections[s])
Expand Down
2 changes: 2 additions & 0 deletions test/integration/targets/ansible-config/aliases
@@ -0,0 +1,2 @@
shippable/posix/group5
context/controller
10 changes: 10 additions & 0 deletions test/integration/targets/ansible-config/files/ini_dupes.py
@@ -0,0 +1,10 @@
#!/usr/bin/env python

import configparser
import sys


ini_file = sys.argv[1]
print(ini_file)
c = configparser.ConfigParser(strict=True, inline_comment_prefixes=(';',))
c.read_file(open(ini_file))
21 changes: 21 additions & 0 deletions test/integration/targets/ansible-config/tasks/main.yml
@@ -0,0 +1,21 @@
- name: test ansible-config for valid output and no dupes
block:
- name: Create temporary file
tempfile:
path: '{{output_dir}}'
state: file
suffix: temp.ini
register: ini_tempfile

- name: run config full dump
shell: ansible-config init -t all > {{ini_tempfile.path}}

- name: run ini tester
shell: "{{ansible_playbook_python}} '{{role_path}}/files/ini_dupes.py' '{{ini_tempfile.path}}'"
ignore_errors: true
register: test_ini

- name: check results
assert:
that:
- test_ini is success
1 change: 1 addition & 0 deletions test/sanity/ignore.txt
Expand Up @@ -89,6 +89,7 @@ lib/ansible/plugins/inventory/advanced_host_list.py pylint:arguments-renamed
lib/ansible/plugins/inventory/host_list.py pylint:arguments-renamed
lib/ansible/utils/collection_loader/_collection_finder.py pylint:deprecated-class
lib/ansible/utils/collection_loader/_collection_meta.py pylint:deprecated-class
test/integration/targets/ansible-config/files/ini_dupes.py boilerplate
test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/tests/integration/targets/hello/files/bad.py pylint:ansible-bad-function # ignore, required for testing
test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import-from # ignore, required for testing
test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import # ignore, required for testing
Expand Down

0 comments on commit c5e950c

Please sign in to comment.