mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Adding a new filter: from_ini, which allows conversion of INI content to a dictionary (#7743)
* Adding a new filter: from_ini, which allows conversion of INI content to a dictionary * Adding from_ini maintainers into BOTMETA * Adding error handling; Removing quotes from examples; Fixing RETURN documentation * Adding integration tests * Moving imports below documentation; Adding a more general exception handling
This commit is contained in:
parent
702dd9bbda
commit
ec6dfe2fcd
4 changed files with 169 additions and 0 deletions
2
.github/BOTMETA.yml
vendored
2
.github/BOTMETA.yml
vendored
|
@ -133,6 +133,8 @@ files:
|
||||||
maintainers: giner
|
maintainers: giner
|
||||||
$filters/from_csv.py:
|
$filters/from_csv.py:
|
||||||
maintainers: Ajpantuso
|
maintainers: Ajpantuso
|
||||||
|
$filters/from_ini.py:
|
||||||
|
maintainers: sscheib
|
||||||
$filters/groupby_as_dict.py:
|
$filters/groupby_as_dict.py:
|
||||||
maintainers: felixfontein
|
maintainers: felixfontein
|
||||||
$filters/hashids.py:
|
$filters/hashids.py:
|
||||||
|
|
99
plugins/filter/from_ini.py
Normal file
99
plugins/filter/from_ini.py
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
|
||||||
|
# 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
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
name: from_ini
|
||||||
|
short_description: Converts INI text input into a dictionary
|
||||||
|
version_added: 8.2.0
|
||||||
|
author: Steffen Scheib (@sscheib)
|
||||||
|
description:
|
||||||
|
- Converts INI text input into a dictionary.
|
||||||
|
options:
|
||||||
|
_input:
|
||||||
|
description: A string containing an INI document.
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Slurp an INI file
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: /etc/rhsm/rhsm.conf
|
||||||
|
register: rhsm_conf
|
||||||
|
|
||||||
|
- name: Display the INI file as dictionary
|
||||||
|
ansible.builtin.debug:
|
||||||
|
var: rhsm_conf.content | b64decode | community.general.from_ini
|
||||||
|
|
||||||
|
- name: Set a new dictionary fact with the contents of the INI file
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
rhsm_dict: >-
|
||||||
|
{{
|
||||||
|
rhsm_conf.content | b64decode | community.general.from_ini
|
||||||
|
}}
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
_value:
|
||||||
|
description: A dictionary representing the INI file.
|
||||||
|
type: dictionary
|
||||||
|
'''
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleFilterError
|
||||||
|
from ansible.module_utils.six import string_types
|
||||||
|
from ansible.module_utils.six.moves import StringIO
|
||||||
|
from ansible.module_utils.six.moves.configparser import ConfigParser
|
||||||
|
from ansible.module_utils.common.text.converters import to_native
|
||||||
|
|
||||||
|
|
||||||
|
class IniParser(ConfigParser):
|
||||||
|
''' Implements a configparser which is able to return a dict '''
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.optionxform = str
|
||||||
|
|
||||||
|
def as_dict(self):
|
||||||
|
d = dict(self._sections)
|
||||||
|
for k in d:
|
||||||
|
d[k] = dict(self._defaults, **d[k])
|
||||||
|
d[k].pop('__name__', None)
|
||||||
|
|
||||||
|
if self._defaults:
|
||||||
|
d['DEFAULT'] = dict(self._defaults)
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def from_ini(obj):
|
||||||
|
''' Read the given string as INI file and return a dict '''
|
||||||
|
|
||||||
|
if not isinstance(obj, string_types):
|
||||||
|
raise AnsibleFilterError(f'from_ini requires a str, got {type(obj)}')
|
||||||
|
|
||||||
|
parser = IniParser()
|
||||||
|
|
||||||
|
try:
|
||||||
|
parser.read_file(StringIO(obj))
|
||||||
|
except Exception as ex:
|
||||||
|
raise AnsibleFilterError(f'from_ini failed to parse given string: '
|
||||||
|
f'{to_native(ex)}', orig_exc=ex)
|
||||||
|
|
||||||
|
return parser.as_dict()
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
''' Query filter '''
|
||||||
|
|
||||||
|
def filters(self):
|
||||||
|
|
||||||
|
return {
|
||||||
|
'from_ini': from_ini
|
||||||
|
}
|
60
tests/integration/targets/filter_from_ini/tasks/main.yml
Normal file
60
tests/integration/targets/filter_from_ini/tasks/main.yml
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
|
||||||
|
# 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
|
||||||
|
|
||||||
|
- name: 'Define ini_test_dict'
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
ini_test_dict:
|
||||||
|
section_name:
|
||||||
|
key_name: 'key value'
|
||||||
|
|
||||||
|
another_section:
|
||||||
|
connection: 'ssh'
|
||||||
|
|
||||||
|
- name: 'Write INI file that reflects ini_test_dict to {{ ini_test_file }}'
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: '{{ ini_test_file }}'
|
||||||
|
content: |
|
||||||
|
[section_name]
|
||||||
|
key_name=key value
|
||||||
|
|
||||||
|
[another_section]
|
||||||
|
connection=ssh
|
||||||
|
|
||||||
|
- name: 'Slurp the test file: {{ ini_test_file }}'
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: '{{ ini_test_file }}'
|
||||||
|
register: 'ini_file_content'
|
||||||
|
|
||||||
|
- name: >-
|
||||||
|
Ensure defined ini_test_dict is the same when retrieved
|
||||||
|
from {{ ini_test_file }}
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- 'ini_file_content.content | b64decode | community.general.from_ini ==
|
||||||
|
ini_test_dict'
|
||||||
|
|
||||||
|
- name: 'Create a file that is not INI formatted: {{ ini_bad_file }}'
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: '{{ ini_bad_file }}'
|
||||||
|
content: |
|
||||||
|
Testing a not INI formatted file.
|
||||||
|
|
||||||
|
- name: 'Slurp the file that is not INI formatted: {{ ini_bad_file }}'
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: '{{ ini_bad_file }}'
|
||||||
|
register: 'ini_bad_file_content'
|
||||||
|
|
||||||
|
- name: 'Try parsing the bad file with from_ini: {{ ini_bad_file }}'
|
||||||
|
ansible.builtin.debug:
|
||||||
|
var: ini_bad_file_content | b64decode | community.general.from_ini
|
||||||
|
register: 'ini_bad_file_debug'
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: 'Ensure from_ini raised the correct exception'
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- "'from_ini failed to parse given string' in ini_bad_file_debug.msg"
|
||||||
|
- "'File contains no section headers' in ini_bad_file_debug.msg"
|
||||||
|
...
|
8
tests/integration/targets/filter_from_ini/vars/main.yml
Normal file
8
tests/integration/targets/filter_from_ini/vars/main.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
|
||||||
|
# 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
|
||||||
|
|
||||||
|
ini_test_file: '/tmp/test.ini'
|
||||||
|
ini_bad_file: '/tmp/bad.file'
|
||||||
|
...
|
Loading…
Reference in a new issue