diff options
Diffstat (limited to 'bin/ansible-config')
-rwxr-xr-x | bin/ansible-config | 125 |
1 files changed, 89 insertions, 36 deletions
diff --git a/bin/ansible-config b/bin/ansible-config index 7dfad9ca..3a5c2421 100755 --- a/bin/ansible-config +++ b/bin/ansible-config @@ -10,13 +10,12 @@ __metaclass__ = type from ansible.cli import CLI import os +import yaml import shlex import subprocess from collections.abc import Mapping -import yaml - from ansible import context import ansible.plugins.loader as plugin_loader @@ -25,6 +24,7 @@ from ansible.cli.arguments import option_helpers as opt_help from ansible.config.manager import ConfigManager, Setting from ansible.errors import AnsibleError, AnsibleOptionsError from ansible.module_utils._text import to_native, to_text, to_bytes +from ansible.module_utils.common.json import json_dump from ansible.module_utils.six import string_types from ansible.parsing.quoting import is_quoted from ansible.parsing.yaml.dumper import AnsibleDumper @@ -35,6 +35,21 @@ from ansible.utils.path import unfrackpath display = Display() +def yaml_dump(data, default_flow_style=False, default_style=None): + return yaml.dump(data, Dumper=AnsibleDumper, default_flow_style=default_flow_style, default_style=default_style) + + +def yaml_short(data): + return yaml_dump(data, default_flow_style=True, default_style="''") + + +def get_constants(): + ''' helper method to ensure we can template based on existing constants ''' + if not hasattr(get_constants, 'cvars'): + get_constants.cvars = {k: getattr(C, k) for k in dir(C) if not k.startswith('__')} + return get_constants.cvars + + class ConfigCLI(CLI): """ Config command line class """ @@ -65,11 +80,15 @@ class ConfigCLI(CLI): list_parser = subparsers.add_parser('list', help='Print all config options', parents=[common]) list_parser.set_defaults(func=self.execute_list) + list_parser.add_argument('--format', '-f', dest='format', action='store', choices=['json', 'yaml'], default='yaml', + help='Output format for list') dump_parser = subparsers.add_parser('dump', help='Dump configuration', parents=[common]) dump_parser.set_defaults(func=self.execute_dump) dump_parser.add_argument('--only-changed', '--changed-only', dest='only_changed', action='store_true', help="Only show configurations that have changed from the default") + dump_parser.add_argument('--format', '-f', dest='format', action='store', choices=['json', 'yaml', 'display'], default='display', + help='Output format for dump') view_parser = subparsers.add_parser('view', help='View configuration file', parents=[common]) view_parser.set_defaults(func=self.execute_view) @@ -231,7 +250,12 @@ class ConfigCLI(CLI): ''' config_entries = self._list_entries_from_args() - self.pager(to_text(yaml.dump(config_entries, Dumper=AnsibleDumper), errors='surrogate_or_strict')) + if context.CLIARGS['format'] == 'yaml': + output = yaml_dump(config_entries) + elif context.CLIARGS['format'] == 'json': + output = json_dump(config_entries) + + self.pager(to_text(output, errors='surrogate_or_strict')) def _get_settings_vars(self, settings, subkey): @@ -279,9 +303,13 @@ class ConfigCLI(CLI): # TODO: might need quoting and value coercion depending on type if subkey == 'env': + if entry.startswith('_ANSIBLE_'): + continue data.append('%s%s=%s' % (prefix, entry, default)) elif subkey == 'vars': - data.append(prefix + to_text(yaml.dump({entry: default}, Dumper=AnsibleDumper, default_flow_style=False), errors='surrogate_or_strict')) + if entry.startswith('_ansible_'): + continue + data.append(prefix + '%s: %s' % (entry, to_text(yaml_short(default), errors='surrogate_or_strict'))) data.append('') return data @@ -370,34 +398,41 @@ class ConfigCLI(CLI): def _render_settings(self, config): - text = [] + entries = [] for setting in sorted(config): - changed = False - if isinstance(config[setting], Setting): - # proceed normally - if config[setting].origin == 'default': - color = 'green' - elif config[setting].origin == 'REQUIRED': - # should include '_terms', '_input', etc - color = 'red' + changed = (config[setting].origin not in ('default', 'REQUIRED')) + + if context.CLIARGS['format'] == 'display': + if isinstance(config[setting], Setting): + # proceed normally + if config[setting].origin == 'default': + color = 'green' + elif config[setting].origin == 'REQUIRED': + # should include '_terms', '_input', etc + color = 'red' + else: + color = 'yellow' + msg = "%s(%s) = %s" % (setting, config[setting].origin, config[setting].value) else: - color = 'yellow' - changed = True - msg = "%s(%s) = %s" % (setting, config[setting].origin, config[setting].value) + color = 'green' + msg = "%s(%s) = %s" % (setting, 'default', config[setting].get('default')) + + entry = stringc(msg, color) else: - color = 'green' - msg = "%s(%s) = %s" % (setting, 'default', config[setting].get('default')) + entry = {} + for key in config[setting]._fields: + entry[key] = getattr(config[setting], key) if not context.CLIARGS['only_changed'] or changed: - text.append(stringc(msg, color)) + entries.append(entry) - return text + return entries def _get_global_configs(self): config = self.config.get_configuration_definitions(ignore_private=True).copy() - for setting in self.config.data.get_settings(): - if setting.name in config: - config[setting.name] = setting + for setting in config.keys(): + v, o = C.config.get_config_value_and_origin(setting, cfile=self.config_file, variables=get_constants()) + config[setting] = Setting(setting, v, o, None) return self._render_settings(config) @@ -407,7 +442,7 @@ class ConfigCLI(CLI): loader = getattr(plugin_loader, '%s_loader' % ptype) # acumulators - text = [] + output = [] config_entries = {} # build list @@ -445,7 +480,7 @@ class ConfigCLI(CLI): # actually get the values for setting in config_entries[finalname].keys(): try: - v, o = C.config.get_config_value_and_origin(setting, plugin_type=ptype, plugin_name=name) + v, o = C.config.get_config_value_and_origin(setting, cfile=self.config_file, plugin_type=ptype, plugin_name=name, variables=get_constants()) except AnsibleError as e: if to_text(e).startswith('No setting was provided for required configuration'): v = None @@ -462,10 +497,14 @@ class ConfigCLI(CLI): # pretty please! results = self._render_settings(config_entries[finalname]) if results: - # avoid header for empty lists (only changed!) - text.append('\n%s:\n%s' % (finalname, '_' * len(finalname))) - text.extend(results) - return text + if context.CLIARGS['format'] == 'display': + # avoid header for empty lists (only changed!) + output.append('\n%s:\n%s' % (finalname, '_' * len(finalname))) + output.extend(results) + else: + output.append({finalname: results}) + + return output def execute_dump(self): ''' @@ -473,21 +512,35 @@ class ConfigCLI(CLI): ''' if context.CLIARGS['type'] == 'base': # deal with base - text = self._get_global_configs() + output = self._get_global_configs() elif context.CLIARGS['type'] == 'all': # deal with base - text = self._get_global_configs() + output = self._get_global_configs() # deal with plugins for ptype in C.CONFIGURABLE_PLUGINS: plugin_list = self._get_plugin_configs(ptype, context.CLIARGS['args']) - if not context.CLIARGS['only_changed'] or plugin_list: - text.append('\n%s:\n%s' % (ptype.upper(), '=' * len(ptype))) - text.extend(plugin_list) + if context.CLIARGS['format'] == 'display': + if not context.CLIARGS['only_changed'] or plugin_list: + output.append('\n%s:\n%s' % (ptype.upper(), '=' * len(ptype))) + output.extend(plugin_list) + else: + if ptype in ('modules', 'doc_fragments'): + pname = ptype.upper() + else: + pname = '%s_PLUGINS' % ptype.upper() + output.append({pname: plugin_list}) else: # deal with plugins - text = self._get_plugin_configs(context.CLIARGS['type'], context.CLIARGS['args']) + output = self._get_plugin_configs(context.CLIARGS['type'], context.CLIARGS['args']) + + if context.CLIARGS['format'] == 'display': + text = '\n'.join(output) + if context.CLIARGS['format'] == 'yaml': + text = yaml_dump(output) + elif context.CLIARGS['format'] == 'json': + text = json_dump(output) - self.pager(to_text('\n'.join(text), errors='surrogate_or_strict')) + self.pager(to_text(text, errors='surrogate_or_strict')) def main(args=None): |