|
|
@ -10,13 +10,12 @@ __metaclass__ = type
|
|
|
|
from ansible.cli import CLI
|
|
|
|
from ansible.cli import CLI
|
|
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
import os
|
|
|
|
|
|
|
|
import yaml
|
|
|
|
import shlex
|
|
|
|
import shlex
|
|
|
|
import subprocess
|
|
|
|
import subprocess
|
|
|
|
|
|
|
|
|
|
|
|
from collections.abc import Mapping
|
|
|
|
from collections.abc import Mapping
|
|
|
|
|
|
|
|
|
|
|
|
import yaml
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from ansible import context
|
|
|
|
from ansible import context
|
|
|
|
import ansible.plugins.loader as plugin_loader
|
|
|
|
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.config.manager import ConfigManager, Setting
|
|
|
|
from ansible.errors import AnsibleError, AnsibleOptionsError
|
|
|
|
from ansible.errors import AnsibleError, AnsibleOptionsError
|
|
|
|
from ansible.module_utils._text import to_native, to_text, to_bytes
|
|
|
|
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.module_utils.six import string_types
|
|
|
|
from ansible.parsing.quoting import is_quoted
|
|
|
|
from ansible.parsing.quoting import is_quoted
|
|
|
|
from ansible.parsing.yaml.dumper import AnsibleDumper
|
|
|
|
from ansible.parsing.yaml.dumper import AnsibleDumper
|
|
|
@ -35,6 +35,10 @@ from ansible.utils.path import unfrackpath
|
|
|
|
display = Display()
|
|
|
|
display = Display()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def yaml_dump(data, default_flow_style=True):
|
|
|
|
|
|
|
|
return yaml.dump(data, Dumper=AnsibleDumper, default_flow_style=default_flow_style)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_constants():
|
|
|
|
def get_constants():
|
|
|
|
''' helper method to ensure we can template based on existing constants '''
|
|
|
|
''' helper method to ensure we can template based on existing constants '''
|
|
|
|
if not hasattr(get_constants, 'cvars'):
|
|
|
|
if not hasattr(get_constants, 'cvars'):
|
|
|
@ -72,11 +76,15 @@ class ConfigCLI(CLI):
|
|
|
|
|
|
|
|
|
|
|
|
list_parser = subparsers.add_parser('list', help='Print all config options', parents=[common])
|
|
|
|
list_parser = subparsers.add_parser('list', help='Print all config options', parents=[common])
|
|
|
|
list_parser.set_defaults(func=self.execute_list)
|
|
|
|
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 = subparsers.add_parser('dump', help='Dump configuration', parents=[common])
|
|
|
|
dump_parser.set_defaults(func=self.execute_dump)
|
|
|
|
dump_parser.set_defaults(func=self.execute_dump)
|
|
|
|
dump_parser.add_argument('--only-changed', '--changed-only', dest='only_changed', action='store_true',
|
|
|
|
dump_parser.add_argument('--only-changed', '--changed-only', dest='only_changed', action='store_true',
|
|
|
|
help="Only show configurations that have changed from the default")
|
|
|
|
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 = subparsers.add_parser('view', help='View configuration file', parents=[common])
|
|
|
|
view_parser.set_defaults(func=self.execute_view)
|
|
|
|
view_parser.set_defaults(func=self.execute_view)
|
|
|
@ -238,7 +246,12 @@ class ConfigCLI(CLI):
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
config_entries = self._list_entries_from_args()
|
|
|
|
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):
|
|
|
|
def _get_settings_vars(self, settings, subkey):
|
|
|
|
|
|
|
|
|
|
|
@ -288,7 +301,7 @@ class ConfigCLI(CLI):
|
|
|
|
if subkey == 'env':
|
|
|
|
if subkey == 'env':
|
|
|
|
data.append('%s%s=%s' % (prefix, entry, default))
|
|
|
|
data.append('%s%s=%s' % (prefix, entry, default))
|
|
|
|
elif subkey == 'vars':
|
|
|
|
elif subkey == 'vars':
|
|
|
|
data.append(prefix + to_text(yaml.dump({entry: default}, Dumper=AnsibleDumper, default_flow_style=False), errors='surrogate_or_strict'))
|
|
|
|
data.append(prefix + to_text(yaml_dump({entry: default}, default_flow_style=False), errors='surrogate_or_strict'))
|
|
|
|
data.append('')
|
|
|
|
data.append('')
|
|
|
|
|
|
|
|
|
|
|
|
return data
|
|
|
|
return data
|
|
|
@ -377,28 +390,35 @@ class ConfigCLI(CLI):
|
|
|
|
|
|
|
|
|
|
|
|
def _render_settings(self, config):
|
|
|
|
def _render_settings(self, config):
|
|
|
|
|
|
|
|
|
|
|
|
text = []
|
|
|
|
entries = []
|
|
|
|
for setting in sorted(config):
|
|
|
|
for setting in sorted(config):
|
|
|
|
changed = False
|
|
|
|
changed = (config[setting].origin != 'default')
|
|
|
|
if isinstance(config[setting], Setting):
|
|
|
|
|
|
|
|
# proceed normally
|
|
|
|
if context.CLIARGS['format'] == 'display':
|
|
|
|
if config[setting].origin == 'default':
|
|
|
|
if isinstance(config[setting], Setting):
|
|
|
|
color = 'green'
|
|
|
|
# proceed normally
|
|
|
|
elif config[setting].origin == 'REQUIRED':
|
|
|
|
if config[setting].origin == 'default':
|
|
|
|
# should include '_terms', '_input', etc
|
|
|
|
color = 'green'
|
|
|
|
color = 'red'
|
|
|
|
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:
|
|
|
|
else:
|
|
|
|
color = 'yellow'
|
|
|
|
color = 'green'
|
|
|
|
changed = True
|
|
|
|
msg = "%s(%s) = %s" % (setting, 'default', config[setting].get('default'))
|
|
|
|
msg = "%s(%s) = %s" % (setting, config[setting].origin, config[setting].value)
|
|
|
|
|
|
|
|
|
|
|
|
entry = stringc(msg, color)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
color = 'green'
|
|
|
|
entry = {}
|
|
|
|
msg = "%s(%s) = %s" % (setting, 'default', config[setting].get('default'))
|
|
|
|
for key in config[setting]._fields:
|
|
|
|
|
|
|
|
entry[key] = getattr(config[setting], key)
|
|
|
|
|
|
|
|
|
|
|
|
if not context.CLIARGS['only_changed'] or changed:
|
|
|
|
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):
|
|
|
|
def _get_global_configs(self):
|
|
|
|
config = self.config.get_configuration_definitions(ignore_private=True).copy()
|
|
|
|
config = self.config.get_configuration_definitions(ignore_private=True).copy()
|
|
|
@ -414,7 +434,7 @@ class ConfigCLI(CLI):
|
|
|
|
loader = getattr(plugin_loader, '%s_loader' % ptype)
|
|
|
|
loader = getattr(plugin_loader, '%s_loader' % ptype)
|
|
|
|
|
|
|
|
|
|
|
|
# acumulators
|
|
|
|
# acumulators
|
|
|
|
text = []
|
|
|
|
output = []
|
|
|
|
config_entries = {}
|
|
|
|
config_entries = {}
|
|
|
|
|
|
|
|
|
|
|
|
# build list
|
|
|
|
# build list
|
|
|
@ -469,10 +489,14 @@ class ConfigCLI(CLI):
|
|
|
|
# pretty please!
|
|
|
|
# pretty please!
|
|
|
|
results = self._render_settings(config_entries[finalname])
|
|
|
|
results = self._render_settings(config_entries[finalname])
|
|
|
|
if results:
|
|
|
|
if results:
|
|
|
|
# avoid header for empty lists (only changed!)
|
|
|
|
if context.CLIARGS['format'] == 'display':
|
|
|
|
text.append('\n%s:\n%s' % (finalname, '_' * len(finalname)))
|
|
|
|
# avoid header for empty lists (only changed!)
|
|
|
|
text.extend(results)
|
|
|
|
output.append('\n%s:\n%s' % (finalname, '_' * len(finalname)))
|
|
|
|
return text
|
|
|
|
output.extend(results)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
output.append({finalname: results})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
|
|
def execute_dump(self):
|
|
|
|
def execute_dump(self):
|
|
|
|
'''
|
|
|
|
'''
|
|
|
@ -480,19 +504,34 @@ class ConfigCLI(CLI):
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
if context.CLIARGS['type'] == 'base':
|
|
|
|
if context.CLIARGS['type'] == 'base':
|
|
|
|
# deal with base
|
|
|
|
# deal with base
|
|
|
|
text = self._get_global_configs()
|
|
|
|
output = self._get_global_configs()
|
|
|
|
elif context.CLIARGS['type'] == 'all':
|
|
|
|
elif context.CLIARGS['type'] == 'all':
|
|
|
|
# deal with base
|
|
|
|
# deal with base
|
|
|
|
text = self._get_global_configs()
|
|
|
|
output = self._get_global_configs()
|
|
|
|
# deal with plugins
|
|
|
|
# deal with plugins
|
|
|
|
for ptype in C.CONFIGURABLE_PLUGINS:
|
|
|
|
for ptype in C.CONFIGURABLE_PLUGINS:
|
|
|
|
text.append('\n%s:\n%s' % (ptype.upper(), '=' * len(ptype)))
|
|
|
|
plugin_list = self._get_plugin_configs(ptype, context.CLIARGS['args'])
|
|
|
|
text.extend(self._get_plugin_configs(ptype, context.CLIARGS['args']))
|
|
|
|
if context.CLIARGS['format'] == 'display':
|
|
|
|
|
|
|
|
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:
|
|
|
|
else:
|
|
|
|
# deal with plugins
|
|
|
|
# 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):
|
|
|
|
def main(args=None):
|
|
|
|