Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clickhouse_cfg_info: add XML files support #86

Merged
merged 3 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 86 additions & 12 deletions plugins/modules/clickhouse_cfg_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

description:
- Retrieves ClickHouse config file content and returns it as JSON.
- Only config files in YAML format are supported at the moment.
- Supports config files in the YAML and XML formats.
- Does not change server state.

attributes:
Expand All @@ -36,11 +36,10 @@
required: true

requirements:
- pyyaml
- pyyaml (for YAML config files)
- xmltodict (for XML config files)
'''

# TODO: it should also handle xml configs

EXAMPLES = r'''
- name: Get server information
register: result
Expand All @@ -52,31 +51,94 @@
var: result
'''

RETURN = r''' # '''
RETURN = r'''
config:
description:
- The content of the config file.
returned: success
type: dict
'''

try:
import yaml
HAS_PYYAML = True
except ImportError:
HAS_PYYAML = False

try:
import xmltodict
HAS_XMLTODICT = True
except ImportError:
HAS_XMLTODICT = False

from ansible.module_utils.basic import (
AnsibleModule,
missing_required_lib,
)


def load_from_yaml(module, path):
def load_config(module, load_func, path):
try:
f = open(path, 'r')
content = yaml.safe_load(f)
content = load_func(f)
except Exception as e:
module.fail_json(msg="Could not open/load YAML from the file %s: %s" % (path, e))
fail_msg = "Could not open/load from file %s: %s" % (path, e)
module.fail_json(msg=fail_msg)
else:
f.close()
return content


def load_from_yaml(f):
return yaml.safe_load(f)


def load_from_xml(f):
content = xmltodict.parse(f.read())['clickhouse']
# This lib loads all values including boolean
# or numerical as strings. Let's convert if possible.
return convert_str_vals_in_dict(content)


def is_xml(path):
return True if len(path) > 4 and path[-4:] == '.xml' else False


def convert_str_vals_in_dict(d):
"""Recursively traverse a dict and covert
string values to appropirate types.
"""
for key, val in d.items():
if isinstance(val, dict):
convert_str_vals_in_dict(val)

elif isinstance(val, list):
for i, v in enumerate(val):
if isinstance(v, dict):
convert_str_vals_in_dict(val[i])
else:
d[key] = convert(val)

return d


def convert(val):
# Try to convert or just return it back
try:
if val == 'false':
val = False
elif val == 'true':
val = True
elif val.isnumeric():
val = int(val)
else:
val = float(val)
except Exception:
return val

return val


def main():
argument_spec = {}
argument_spec.update(
Expand All @@ -89,13 +151,25 @@ def main():
supports_check_mode=True,
)

if not HAS_PYYAML:
module.fail_json(msg=missing_required_lib('pyyaml'))
path = module.params['path']

# When XML
if is_xml(path):
if not HAS_XMLTODICT:
module.fail_json(msg=missing_required_lib('xmltodict'))
load_func = load_from_xml

# When YAML, the default
else:
if not HAS_PYYAML:
module.fail_json(msg=missing_required_lib('pyyaml'))
load_func = load_from_yaml

cfg_content = load_from_yaml(module, module.params['path'])
# Load content as dict
cfg_content = load_config(module, load_func, path)

# Users will get this in JSON output after execution
module.exit_json(changed=False, **cfg_content)
module.exit_json(changed=False, config=cfg_content)


if __name__ == '__main__':
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
clickhouse_driver
pyyaml
xmltodict
Loading
Loading