class TestConfigData(unittest.TestCase): def setUp(self): self.manager = ConfigManager(os.path.join(curdir, 'test.cfg'), os.path.join(curdir, 'test.yml')) def tearDown(self): self.manager = None def test_initial_load(self): self.assertEquals(self.manager.data._global_settings, expected_ini) def test_value_and_origin_from_ini(self): self.assertEquals( self.manager.get_config_value_and_origin('config_entry'), ('fromini', cfg_file)) def test_value_from_ini(self): self.assertEquals(self.manager.get_config_value('config_entry'), 'fromini') def test_value_and_origin_from_alt_ini(self): self.assertEquals( self.manager.get_config_value_and_origin('config_entry', cfile=cfg_file2), ('fromini2', cfg_file2)) def test_value_from_alt_ini(self): self.assertEquals( self.manager.get_config_value('config_entry', cfile=cfg_file2), 'fromini2')
def run(self): super(ConfigCLI, self).run() if context.CLIARGS['config_file']: self.config_file = unfrackpath(context.CLIARGS['config_file'], follow=False) b_config = to_bytes(self.config_file) if os.path.exists(b_config) and os.access(b_config, os.R_OK): self.config = ConfigManager(self.config_file) else: raise AnsibleOptionsError('The provided configuration file is missing or not accessible: %s' % to_native(self.config_file)) else: self.config = ConfigManager() self.config_file = find_ini_config_file() if self.config_file: try: if not os.path.exists(self.config_file): raise AnsibleOptionsError("%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = to_native(self.config_file) except Exception: if context.CLIARGS['action'] in ['view']: raise elif context.CLIARGS['action'] in ['edit', 'update']: display.warning("File does not exist, used empty file: %s" % self.config_file) elif context.CLIARGS['action'] == 'view': raise AnsibleError('Invalid or no config file was supplied') context.CLIARGS['func']()
def run(self): super(ConfigCLI, self).run() if context.CLIARGS['config_file']: self.config_file = unfrackpath(context.CLIARGS['config_file'], follow=False) self.config = ConfigManager(self.config_file) else: self.config = ConfigManager() self.config_file = find_ini_config_file() if self.config_file: try: if not os.path.exists(self.config_file): raise AnsibleOptionsError("%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = to_native(self.config_file) except Exception: if self.action in ['view']: raise elif self.action in ['edit', 'update']: display.warning("File does not exist, used empty file: %s" % self.config_file) elif self.action == 'view': raise AnsibleError('Invalid or no config file was supplied') self.execute()
def run(self): super(ConfigCLI, self).run() if self.options.config_file: self.config_file = unfrackpath(self.options.config_file, follow=False) self.config = ConfigManager(self.config_file) else: self.config = ConfigManager() self.config_file = find_ini_config_file() if self.config_file: try: if not os.path.exists(self.config_file): raise AnsibleOptionsError("%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = to_native(self.config_file) except: if self.action in ['view']: raise elif self.action in ['edit', 'update']: display.warning("File does not exist, used empty file: %s" % self.config_file) elif self.action == 'view': raise AnsibleError('Invalid or no config file was supplied') self.execute()
def run(self): super(ConfigCLI, self).run() if self.options.config_file: self.config_file = unfrackpath(self.options.config_file, follow=False) self.config = ConfigManager(self.config_file) else: self.config = ConfigManager() self.config_file = self.config.data.get_setting('ANSIBLE_CONFIG') try: if not os.path.exists(self.config_file): raise AnsibleOptionsError( "%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = self.config_file except: if self.action in ['view']: raise elif self.action in ['edit', 'update']: display.warning( "File does not exist, used empty file: %s" % self.config_file) self.execute()
def main(): config_manager = ConfigManager() username = config_manager.data.get_setting('vault.username') if not username: username = getpass.getuser() keyname = config_manager.data.get_setting('vault.keyname') if not keyname: keyname = 'ansible' arg_parser = build_arg_parser() args = arg_parser.parse_args() username = args.username or username keyname = args.vault_id or keyname # lookup the file if os.path.exists('environments/local/vault-password'): with open('environments/local/vault-password', 'r') as stream: sys.stdout.write('%s\n' % stream.readline()) sys.exit(0) else: # provide fake password sys.stdout.write('%s\n' % 'nevairbe') sys.exit(0) sys.exit(0)
def main(): config = ConfigManager() username = get_ini_config_value( config._parsers[config._config_file], dict(section='vault', key='username') ) or getpass.getuser() keyname = get_ini_config_value( config._parsers[config._config_file], dict(section='vault', key='keyname') ) or 'ansible' if len(sys.argv) == 2 and sys.argv[1] == 'set': intro = 'Storing password in "{}" user keyring using key name: {}\n' sys.stdout.write(intro.format(username, keyname)) password = getpass.getpass() confirm = getpass.getpass('Confirm password: '******'Passwords do not match\n') sys.exit(1) else: sys.stdout.write('{0}\n'.format(keyring.get_password(keyname, username))) sys.exit(0)
def __init__(self): initial_dir = os.getcwd() ansible_basedir = os.path.join( os.environ.get("PROJECT_ENVIRONMENT_FILES_PATH"), "ansible") # Move to project directory os.chdir(os.environ.get("PROJECT_ENVIRONMENT_FILES_PATH")) # Load list of inventories from config:w config = ConfigManager('/etc/ansible/ansible.cfg') sources = config.data.get_setting('DEFAULT_HOST_LIST').value loader = CustomLoader() loader.set_basedir(ansible_basedir) # load the inventory, set the basic playbook directory self._inventory = CustomInventoryManager(loader=loader, sources=sources) var_manager = VariableManager(loader=loader, inventory=self._inventory) play = Play.load(dict(hosts=['all']), loader=loader, variable_manager=var_manager) # Move back to directory of origin os.chdir(initial_dir) control_host = None if 'control' in self._inventory.groups: control_group = self._inventory.groups['control'] if len(control_group.get_hosts()) > 0: control_host = control_group.get_hosts()[0] # Hostvars hostvars = {} for host in self._inventory.get_hosts(): hostvars[host.name] = host.vars # make sure we load all magic variables on top of the global variables self._vars = combine_vars( var_manager.get_vars(play=play, task=Task(), host=control_host), { 'hostvars': hostvars, 'env': os.environ }) # create the template renderer self._templar = Templar(loader=loader, variables=self._vars) # setup some easy variables that we use a lot self._vars['control_ip'] = self.get_var( "hostvars[groups['control'][0]]['ansible_host']") self._vars['edge_ip'] = self.get_var( "hostvars[groups['edge'][0]]['ansible_host']") self._vars['monitor_ip'] = self.get_var( "hostvars[groups['monitor'][0]]['ansible_host']")
def main(): config_manager = ConfigManager() username = config_manager.data.get_setting("vault.storedir") if not username: username = "******" keyprefix = config_manager.data.get_setting("vault.keyprefix") if not keyprefix: keyprefix = None keyname = config_manager.data.get_setting("vault.keyname") if not keyname: keyname = "dev" key = keyprefix + keyname if keyprefix else keyname arg_parser = build_arg_parser() args = arg_parser.parse_args() username = args.username or username keyname = args.vault_id or key print("username: %s keyname: %s" % (username, key)) if args.set_password: # intro = 'Storing password in "{}" user keyring using key name: {}\n' # sys.stdout.write(intro.format(username, key)) # password = getpass.getpass() # confirm = getpass.getpass("Confirm password: "******"Storing Passwords is not supported with 'pass'\n") sys.exit(1) else: qpass.DEFAULT_DIRECTORY = username s = qpass.PasswordStore() e = qpass.PasswordEntry(store=s, name=key) secret = e.text if secret is None: sys.stderr.write( 'vault-keyring-client could not find key="%s" for user="******" via backend="%s"\n' % (keyname, username, s.repr())) sys.exit(KEYNAME_UNKNOWN_RC) # print('secret: %s' % secret) sys.stdout.write("%s\n" % secret) sys.exit(0)
def __init__(self, options=None): if not options: options = {} self.options = options self.loader = DataLoader() if "inventory_path" in self.options: sources = self.options["inventory_path"] else: sources = None self.inventory_manager = InventoryManager(self.loader, sources=sources) self.variable_manager = VariableManager( loader=self.loader, inventory=self.inventory_manager) # TODO load ansible configuration self.config_manager = ConfigManager()
def main(): config_manager = ConfigManager() username = config_manager.data.get_setting('vault.username') if not username: username = getpass.getuser() keyname = config_manager.data.get_setting('vault.keyname') if not keyname: keyname = 'ansible' arg_parser = build_arg_parser() args = arg_parser.parse_args() username = args.username or username keyname = args.vault_id or keyname # print('username: %s keyname: %s' % (username, keyname)) if args.set_password: intro = 'Storing password in "{}" user keyring using key name: {}\n' sys.stdout.write(intro.format(username, keyname)) password = getpass.getpass() confirm = getpass.getpass('Confirm password: '******'Passwords do not match\n') sys.exit(1) else: secret = keyring.get_password(keyname, username) if secret is None: sys.stderr.write( 'vault-keyring-client could not find key="%s" for user="******" via backend="%s"\n' % (keyname, username, keyring.get_keyring().name)) sys.exit(KEYNAME_UNKNOWN_RC) # print('secret: %s' % secret) sys.stdout.write('%s\n' % secret) sys.exit(0)
def get_default_config(self, key=None): """getting the default configuration defined by ansible.cfg (Uses default values if there is no ansible.cfg). :param key: get a value of a specific key of the ansible.cfg file :type key: str :return: key/values of the default ansible configuration or a specifc value of the config :rtype: dict if key not defined or string if defined """ returndict = {} acm = ConfigManager() a_settings = acm.data.get_settings() if key: for setting in a_settings: if setting.name == key: return setting.value return None else: for setting in a_settings: if setting.name == "CONFIG_FILE": self.logger.debug("Using %s for default configuration" % setting.value) elif setting.name == "DEFAULT_BECOME": returndict["become"] = setting.value elif setting.name == "DEFAULT_BECOME_METHOD": returndict["become_method"] = setting.value elif setting.name == "DEFAULT_BECOME_USER": returndict["become_user"] = setting.value elif setting.name == "DEFAULT_REMOTE_USER": returndict["remote_user"] = setting.value elif setting.name == "DEFAULT_FORKS": returndict["forks"] = setting.value elif setting.name == 'DEFAULT_TRANSPORT': returndict["connection"] = setting.value return returndict
class ConfigCLI(CLI): """ Config command line class """ VALID_ACTIONS = frozenset(("view", "dump", "list")) # TODO: edit, update, search def __init__(self, args, callback=None): self.config_file = None self.config = None super(ConfigCLI, self).__init__(args, callback) def init_parser(self): super(ConfigCLI, self).init_parser( usage="usage: %%prog [%s] [--help] [options] [ansible.cfg]" % "|".join(sorted(self.VALID_ACTIONS)), epilog="\nSee '%s <command> --help' for more information on a specific command.\n\n" % os.path.basename(sys.argv[0]), desc="View, edit, and manage ansible configuration.", ) self.parser.add_option('-c', '--config', dest='config_file', help="path to configuration file, defaults to first file found in precedence.") self.set_action() # options specific to self.actions if self.action == "list": self.parser.set_usage("usage: %prog list [options] ") elif self.action == "dump": self.parser.add_option('--only-changed', dest='only_changed', action='store_true', help="Only show configurations that have changed from the default") elif self.action == "update": self.parser.add_option('-s', '--setting', dest='setting', help="config setting, the section defaults to 'defaults'") self.parser.set_usage("usage: %prog update [options] [-c ansible.cfg] -s '[section.]setting=value'") elif self.action == "search": self.parser.set_usage("usage: %prog update [options] [-c ansible.cfg] <search term>") def post_process_args(self, options, args): options, args = super(ConfigCLI, self).post_process_args(options, args) display.verbosity = options.verbosity return options, args def run(self): super(ConfigCLI, self).run() if context.CLIARGS['config_file']: self.config_file = unfrackpath(context.CLIARGS['config_file'], follow=False) self.config = ConfigManager(self.config_file) else: self.config = ConfigManager() self.config_file = find_ini_config_file() if self.config_file: try: if not os.path.exists(self.config_file): raise AnsibleOptionsError("%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = to_native(self.config_file) except Exception: if self.action in ['view']: raise elif self.action in ['edit', 'update']: display.warning("File does not exist, used empty file: %s" % self.config_file) elif self.action == 'view': raise AnsibleError('Invalid or no config file was supplied') self.execute() def execute_update(self): ''' Updates a single setting in the specified ansible.cfg ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable if context.CLIARGS['setting'] is None: raise AnsibleOptionsError("update option requires a setting to update") (entry, value) = context.CLIARGS['setting'].split('=') if '.' in entry: (section, option) = entry.split('.') else: section = 'defaults' option = entry subprocess.call([ 'ansible', '-m', 'ini_file', 'localhost', '-c', 'local', '-a', '"dest=%s section=%s option=%s value=%s backup=yes"' % (self.config_file, section, option, value) ]) def execute_view(self): ''' Displays the current config file ''' try: with open(self.config_file, 'rb') as f: self.pager(to_text(f.read(), errors='surrogate_or_strict')) except Exception as e: raise AnsibleError("Failed to open config file: %s" % to_native(e)) def execute_edit(self): ''' Opens ansible.cfg in the default EDITOR ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable try: editor = shlex.split(os.environ.get('EDITOR', 'vi')) editor.append(self.config_file) subprocess.call(editor) except Exception as e: raise AnsibleError("Failed to open editor: %s" % to_native(e)) def execute_list(self): ''' list all current configs reading lib/constants.py and shows env and config file setting names ''' self.pager(to_text(yaml.dump(self.config.get_configuration_definitions(), Dumper=AnsibleDumper), errors='surrogate_or_strict')) def execute_dump(self): ''' Shows the current settings, merges ansible.cfg if specified ''' # FIXME: deal with plugins, not just base config text = [] defaults = self.config.get_configuration_definitions().copy() for setting in self.config.data.get_settings(): if setting.name in defaults: defaults[setting.name] = setting for setting in sorted(defaults): if isinstance(defaults[setting], Setting): if defaults[setting].origin == 'default': color = 'green' else: color = 'yellow' msg = "%s(%s) = %s" % (setting, defaults[setting].origin, defaults[setting].value) else: color = 'green' msg = "%s(%s) = %s" % (setting, 'default', defaults[setting].get('default')) if not context.CLIARGS['only_changed'] or color == 'yellow': text.append(stringc(msg, color)) self.pager(to_text('\n'.join(text), errors='surrogate_or_strict'))
class TestConfigData(unittest.TestCase): def setUp(self): self.manager = ConfigManager(cfg_file, os.path.join(curdir, 'test.yml')) def tearDown(self): self.manager = None def test_initial_load(self): self.assertEquals(self.manager.data._global_settings, expected_ini) def test_ensure_type_list(self): self.assertIsInstance(ensure_type('a,b', 'list'), list) self.assertIsInstance(ensure_type(['a', 'b'], 'list'), list) def test_ensure_type_bool(self): self.assertIsInstance(ensure_type('yes', 'bool'), bool) self.assertIsInstance(ensure_type(True, 'bool'), bool) def test_ensure_type_int(self): self.assertIsInstance(ensure_type('10', 'int'), int) self.assertIsInstance(ensure_type(20, 'int'), int) def test_ensure_type_float(self): self.assertIsInstance(ensure_type('0.10', 'float'), float) self.assertIsInstance(ensure_type(0.2, 'float'), float) def test_find_ini_file(self): cur_config = os.environ['ANSIBLE_CONFIG'] os.environ['ANSIBLE_CONFIG'] = cfg_file self.assertEquals(cfg_file, find_ini_config_file()) os.environ['ANSIBLE_CONFIG'] = cur_config def test_resolve_path(self): self.assertEquals(os.path.join(curdir, 'test.yml'), resolve_path('./test.yml', cfg_file)) def test_resolve_path_cwd(self): self.assertEquals(os.path.join(os.getcwd(), 'test.yml'), resolve_path('{{CWD}}/test.yml')) self.assertEquals(os.path.join(os.getcwd(), 'test.yml'), resolve_path('./test.yml')) def test_get_config_dest(self): pass def test_value_and_origin_from_ini(self): self.assertEquals(self.manager.get_config_value_and_origin('config_entry'), ('fromini', cfg_file)) def test_value_from_ini(self): self.assertEquals(self.manager.get_config_value('config_entry'), 'fromini') def test_value_and_origin_from_alt_ini(self): self.assertEquals(self.manager.get_config_value_and_origin('config_entry', cfile=cfg_file2), ('fromini2', cfg_file2)) def test_value_from_alt_ini(self): self.assertEquals(self.manager.get_config_value('config_entry', cfile=cfg_file2), 'fromini2') def test_value_and_origin_from_yaml(self): pass def test_value_from_yaml(self): pass def test_value_and_origin_from_alt_yaml(self): pass def test_value_from_alt_yaml(self): pass def test_config_type_bool(self): pass def test_config_type_list(self): pass def test_config_default(self): pass def test_deprecated_config(self): pass def test_deprecated_config_source(self): pass def test_multi_precedence(self): pass def test_initialize_plugin_config(self): pass def test_update_config_data(self): pass
class ConfigCLI(CLI): """ Config command line class """ def __init__(self, args, callback=None): self.config_file = None self.config = None super(ConfigCLI, self).__init__(args, callback) def init_parser(self): super(ConfigCLI, self).init_parser( desc="View ansible configuration.", ) common = opt_help.argparse.ArgumentParser(add_help=False) opt_help.add_verbosity_options(common) common.add_argument('-c', '--config', dest='config_file', help="path to configuration file, defaults to first file found in precedence.") subparsers = self.parser.add_subparsers(dest='action') subparsers.required = True list_parser = subparsers.add_parser('list', help='Print all config options', parents=[common]) list_parser.set_defaults(func=self.execute_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', dest='only_changed', action='store_true', help="Only show configurations that have changed from the default") view_parser = subparsers.add_parser('view', help='View configuration file', parents=[common]) view_parser.set_defaults(func=self.execute_view) # update_parser = subparsers.add_parser('update', help='Update configuration option') # update_parser.set_defaults(func=self.execute_update) # update_parser.add_argument('-s', '--setting', dest='setting', # help="config setting, the section defaults to 'defaults'", # metavar='[section.]setting=value') # search_parser = subparsers.add_parser('search', help='Search configuration') # search_parser.set_defaults(func=self.execute_search) # search_parser.add_argument('args', help='Search term', metavar='<search term>') def post_process_args(self, options): options = super(ConfigCLI, self).post_process_args(options) display.verbosity = options.verbosity return options def run(self): super(ConfigCLI, self).run() if context.CLIARGS['config_file']: self.config_file = unfrackpath(context.CLIARGS['config_file'], follow=False) b_config = to_bytes(self.config_file) if os.path.exists(b_config) and os.access(b_config, os.R_OK): self.config = ConfigManager(self.config_file) else: raise AnsibleOptionsError('The provided configuration file is missing or not accessible: %s' % to_native(self.config_file)) else: self.config = ConfigManager() self.config_file = find_ini_config_file() if self.config_file: try: if not os.path.exists(self.config_file): raise AnsibleOptionsError("%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = to_native(self.config_file) except Exception: if context.CLIARGS['action'] in ['view']: raise elif context.CLIARGS['action'] in ['edit', 'update']: display.warning("File does not exist, used empty file: %s" % self.config_file) elif context.CLIARGS['action'] == 'view': raise AnsibleError('Invalid or no config file was supplied') context.CLIARGS['func']() def execute_update(self): ''' Updates a single setting in the specified ansible.cfg ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable if context.CLIARGS['setting'] is None: raise AnsibleOptionsError("update option requires a setting to update") (entry, value) = context.CLIARGS['setting'].split('=') if '.' in entry: (section, option) = entry.split('.') else: section = 'defaults' option = entry subprocess.call([ 'ansible', '-m', 'ini_file', 'localhost', '-c', 'local', '-a', '"dest=%s section=%s option=%s value=%s backup=yes"' % (self.config_file, section, option, value) ]) def execute_view(self): ''' Displays the current config file ''' try: with open(self.config_file, 'rb') as f: self.pager(to_text(f.read(), errors='surrogate_or_strict')) except Exception as e: raise AnsibleError("Failed to open config file: %s" % to_native(e)) def execute_edit(self): ''' Opens ansible.cfg in the default EDITOR ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable try: editor = shlex.split(os.environ.get('EDITOR', 'vi')) editor.append(self.config_file) subprocess.call(editor) except Exception as e: raise AnsibleError("Failed to open editor: %s" % to_native(e)) def execute_list(self): ''' list all current configs reading lib/constants.py and shows env and config file setting names ''' self.pager(to_text(yaml.dump(self.config.get_configuration_definitions(ignore_private=True), Dumper=AnsibleDumper), errors='surrogate_or_strict')) def execute_dump(self): ''' Shows the current settings, merges ansible.cfg if specified ''' # FIXME: deal with plugins, not just base config text = [] defaults = self.config.get_configuration_definitions(ignore_private=True).copy() for setting in self.config.data.get_settings(): if setting.name in defaults: defaults[setting.name] = setting for setting in sorted(defaults): if isinstance(defaults[setting], Setting): if defaults[setting].origin == 'default': color = 'green' else: color = 'yellow' msg = "%s(%s) = %s" % (setting, defaults[setting].origin, defaults[setting].value) else: color = 'green' msg = "%s(%s) = %s" % (setting, 'default', defaults[setting].get('default')) if not context.CLIARGS['only_changed'] or color == 'yellow': text.append(stringc(msg, color)) self.pager(to_text('\n'.join(text), errors='surrogate_or_strict'))
def setUp(self): self.manager = ConfigManager(os.path.join(curdir, 'test.cfg'), os.path.join(curdir, 'test.yml'))
def setUp(self): self.manager = ConfigManager(cfg_file, os.path.join(curdir, 'test.yml'))
def setup_class(cls): cls.manager = ConfigManager(cfg_file, os.path.join(curdir, 'test.yml'))
import argparse import base64 import getpass import binascii from ansible import errors from ansible.config.manager import ConfigManager, get_ini_config_value from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC # Section in config file CONFIG_SECTION = 'vault_filter' # Read config values config_manager = ConfigManager() config_parser = config_manager._parsers.values()[0] VAULT_FILTER_KEY = get_ini_config_value( config_parser, dict(section=CONFIG_SECTION, key='key')) or 'vault.key' VAULT_FILTER_SALT = get_ini_config_value( config_parser, dict(section=CONFIG_SECTION, key='salt')) or None VAULT_FILTER_ITERATIONS = get_ini_config_value( config_parser, dict(section=CONFIG_SECTION, key='iterations')) or 1000000 VAULT_FILTER_GENERATE_KEY = get_ini_config_value( config_parser, dict(section=CONFIG_SECTION, key='generate_key')) or False DEFAULT_VAULT_PASSWORD_FILE = config_manager.data.get_setting( 'DEFAULT_VAULT_PASSWORD_FILE').value # Read environment variables VAULT_FILTER_KEY = os.getenv('VAULT_FILTER_KEY', VAULT_FILTER_KEY)
class ConfigCLI(CLI): """ Config command line class """ def __init__(self, args, callback=None): self.config_file = None self.config = None super(ConfigCLI, self).__init__(args, callback) def init_parser(self): super(ConfigCLI, self).init_parser( desc="View ansible configuration.", ) common = opt_help.argparse.ArgumentParser(add_help=False) opt_help.add_verbosity_options(common) common.add_argument('-c', '--config', dest='config_file', help="path to configuration file, defaults to first file found in precedence.") common.add_argument("-t", "--type", action="store", default='base', dest='type', choices=['all', 'base'] + list(C.CONFIGURABLE_PLUGINS), help="Show configuration for a plugin type, for a specific plugin's options see ansible-doc.") subparsers = self.parser.add_subparsers(dest='action') subparsers.required = True list_parser = subparsers.add_parser('list', help='Print all config options', parents=[common]) list_parser.set_defaults(func=self.execute_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") view_parser = subparsers.add_parser('view', help='View configuration file', parents=[common]) view_parser.set_defaults(func=self.execute_view) # update_parser = subparsers.add_parser('update', help='Update configuration option') # update_parser.set_defaults(func=self.execute_update) # update_parser.add_argument('-s', '--setting', dest='setting', # help="config setting, the section defaults to 'defaults'", # metavar='[section.]setting=value') # search_parser = subparsers.add_parser('search', help='Search configuration') # search_parser.set_defaults(func=self.execute_search) # search_parser.add_argument('args', help='Search term', metavar='<search term>') def post_process_args(self, options): options = super(ConfigCLI, self).post_process_args(options) display.verbosity = options.verbosity return options def run(self): super(ConfigCLI, self).run() if context.CLIARGS['config_file']: self.config_file = unfrackpath(context.CLIARGS['config_file'], follow=False) b_config = to_bytes(self.config_file) if os.path.exists(b_config) and os.access(b_config, os.R_OK): self.config = ConfigManager(self.config_file) else: raise AnsibleOptionsError('The provided configuration file is missing or not accessible: %s' % to_native(self.config_file)) else: self.config = C.config self.config_file = self.config._config_file if self.config_file: try: if not os.path.exists(self.config_file): raise AnsibleOptionsError("%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = to_native(self.config_file) except Exception: if context.CLIARGS['action'] in ['view']: raise elif context.CLIARGS['action'] in ['edit', 'update']: display.warning("File does not exist, used empty file: %s" % self.config_file) elif context.CLIARGS['action'] == 'view': raise AnsibleError('Invalid or no config file was supplied') context.CLIARGS['func']() def execute_update(self): ''' Updates a single setting in the specified ansible.cfg ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable if context.CLIARGS['setting'] is None: raise AnsibleOptionsError("update option requires a setting to update") (entry, value) = context.CLIARGS['setting'].split('=') if '.' in entry: (section, option) = entry.split('.') else: section = 'defaults' option = entry subprocess.call([ 'ansible', '-m', 'ini_file', 'localhost', '-c', 'local', '-a', '"dest=%s section=%s option=%s value=%s backup=yes"' % (self.config_file, section, option, value) ]) def execute_view(self): ''' Displays the current config file ''' try: with open(self.config_file, 'rb') as f: self.pager(to_text(f.read(), errors='surrogate_or_strict')) except Exception as e: raise AnsibleError("Failed to open config file: %s" % to_native(e)) def execute_edit(self): ''' Opens ansible.cfg in the default EDITOR ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable try: editor = shlex.split(os.environ.get('EDITOR', 'vi')) editor.append(self.config_file) subprocess.call(editor) except Exception as e: raise AnsibleError("Failed to open editor: %s" % to_native(e)) def _list_plugin_settings(self, ptype): entries = {} loader = getattr(plugin_loader, '%s_loader' % ptype) for plugin in loader.all(class_only=True): finalname = name = plugin._load_name if name.startswith('_'): # alias or deprecated if os.path.islink(plugin._original_path): continue else: finalname = name.replace('_', '', 1) + ' (DEPRECATED)' entries[finalname] = self.config.get_configuration_definitions(ptype, name) return entries def execute_list(self): ''' list all current configs reading lib/constants.py and shows env and config file setting names ''' config_entries = {} if context.CLIARGS['type'] == 'base': # this dumps main/common configs config_entries = self.config.get_configuration_definitions(ignore_private=True) elif context.CLIARGS['type'] == 'all': # get global config_entries = self.config.get_configuration_definitions(ignore_private=True) config_entries['PLUGINS'] = {} # now each plugin type for ptype in C.CONFIGURABLE_PLUGINS: config_entries['PLUGINS'][ptype.upper()] = self._list_plugin_settings(ptype) else: config_entries = self._list_plugin_settings(context.CLIARGS['type']) self.pager(to_text(yaml.dump(config_entries, Dumper=AnsibleDumper), errors='surrogate_or_strict')) def _render_settings(self, config): text = [] for setting in sorted(config): if isinstance(config[setting], Setting): if config[setting].origin == 'default': color = 'green' elif config[setting].origin == 'REQUIRED': color = 'red' else: color = 'yellow' msg = "%s(%s) = %s" % (setting, config[setting].origin, config[setting].value) else: color = 'green' msg = "%s(%s) = %s" % (setting, 'default', config[setting].get('default')) if not context.CLIARGS['only_changed'] or color == 'yellow': text.append(stringc(msg, color)) return text 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 return self._render_settings(config) def _get_plugin_configs(self, ptype): # prep loading loader = getattr(plugin_loader, '%s_loader' % ptype) # acumulators text = [] config_entries = {} for plugin in loader.all(class_only=True): # in case of deprecastion they diverge finalname = name = plugin._load_name if name.startswith('_'): if os.path.islink(plugin._original_path): # skip alias continue # deprecated, but use 'nice name' finalname = name.replace('_', '', 1) + ' (DEPRECATED)' # default entries per plugin config_entries[finalname] = self.config.get_configuration_definitions(ptype, name) try: # populate config entries by loading plugin dump = loader.get(name, class_only=True) except Exception as e: display.warning('Skipping "%s" %s plugin, as we cannot load plugin to check config due to : %s' % (name, ptype, to_native(e))) continue # 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) except AnsibleError as e: if to_text(e).startswith('No setting was provided for required configuration'): v = None o = 'REQUIRED' else: raise e config_entries[finalname][setting] = Setting(setting, v, o, None) # 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 def execute_dump(self): ''' Shows the current settings, merges ansible.cfg if specified ''' if context.CLIARGS['type'] == 'base': # deal with base text = self._get_global_configs() elif context.CLIARGS['type'] == 'all': # deal with base text = self._get_global_configs() # deal with plugins for ptype in C.CONFIGURABLE_PLUGINS: text.append('\n%s:\n%s' % (ptype.upper(), '=' * len(ptype))) text.extend(self._get_plugin_configs(ptype)) else: # deal with plugins text = self._get_plugin_configs(context.CLIARGS['type']) self.pager(to_text('\n'.join(text), errors='surrogate_or_strict'))
def __init__(self): self._config = ConfigManager() self._loader = DataLoader() self._file_vault_secrets = {} self._inventory: InventoryManager = None self._variables: VariableManager = None
class TestConfigData(unittest.TestCase): def setUp(self): self.manager = ConfigManager(cfg_file, os.path.join(curdir, 'test.yml')) def tearDown(self): self.manager = None def test_initial_load(self): self.assertEquals(self.manager.data._global_settings, expected_ini) def test_ensure_type_list(self): self.assertIsInstance(ensure_type('a,b', 'list'), list) self.assertIsInstance(ensure_type(['a', 'b'], 'list'), list) def test_ensure_type_bool(self): self.assertIsInstance(ensure_type('yes', 'bool'), bool) self.assertIsInstance(ensure_type(True, 'bool'), bool) def test_ensure_type_int(self): self.assertIsInstance(ensure_type('10', 'int'), int) self.assertIsInstance(ensure_type(20, 'int'), int) def test_ensure_type_float(self): self.assertIsInstance(ensure_type('0.10', 'float'), float) self.assertIsInstance(ensure_type(0.2, 'float'), float) def test_find_ini_file(self): cur_config = os.environ['ANSIBLE_CONFIG'] os.environ['ANSIBLE_CONFIG'] = cfg_file self.assertEquals(cfg_file, find_ini_config_file()) os.environ['ANSIBLE_CONFIG'] = cur_config def test_resolve_path(self): self.assertEquals(os.path.join(curdir, 'test.yml'), resolve_path('./test.yml', cfg_file)) def test_resolve_path_cwd(self): self.assertEquals(os.path.join(os.getcwd(), 'test.yml'), resolve_path('{{CWD}}/test.yml')) self.assertEquals(os.path.join(os.getcwd(), 'test.yml'), resolve_path('./test.yml')) def test_get_config_dest(self): pass def test_value_and_origin_from_ini(self): self.assertEquals( self.manager.get_config_value_and_origin('config_entry'), ('fromini', cfg_file)) def test_value_from_ini(self): self.assertEquals(self.manager.get_config_value('config_entry'), 'fromini') def test_value_and_origin_from_alt_ini(self): self.assertEquals( self.manager.get_config_value_and_origin('config_entry', cfile=cfg_file2), ('fromini2', cfg_file2)) def test_value_from_alt_ini(self): self.assertEquals( self.manager.get_config_value('config_entry', cfile=cfg_file2), 'fromini2') def test_value_and_origin_from_yaml(self): pass def test_value_from_yaml(self): pass def test_value_and_origin_from_alt_yaml(self): pass def test_value_from_alt_yaml(self): pass def test_config_type_bool(self): pass def test_config_type_list(self): pass def test_config_default(self): pass def test_deprecated_config(self): pass def test_deprecated_config_source(self): pass def test_multi_precedence(self): pass def test_initialize_plugin_config(self): pass def test_update_config_data(self): pass
# ssh TODO: remove ssh_executable=('ansible_ssh_executable', ), ssh_common_args=('ansible_ssh_common_args', ), sftp_extra_args=('ansible_sftp_extra_args', ), scp_extra_args=('ansible_scp_extra_args', ), ssh_extra_args=('ansible_ssh_extra_args', ), ssh_transfer_method=('ansible_ssh_transfer_method', ), # docker TODO: remove docker_extra_args=('ansible_docker_extra_args', ), # become become=('ansible_become', ), become_method=('ansible_become_method', ), become_user=('ansible_become_user', ), become_pass=('ansible_become_password', 'ansible_become_pass'), become_exe=('ansible_become_exe', ), become_flags=('ansible_become_flags', ), ) # POPULATE SETTINGS FROM CONFIG ### config = ConfigManager() # Generate constants from config for setting in config.get_configuration_definitions(): set_constant(setting, config.get_config_value(setting, variables=vars())) for warn in config.WARNINGS: _warning(warn)
# deprecated sudo=('ansible_sudo', ), sudo_user=('ansible_sudo_user', ), sudo_pass=('ansible_sudo_password', 'ansible_sudo_pass'), sudo_exe=('ansible_sudo_exe', ), sudo_flags=('ansible_sudo_flags', ), su=('ansible_su', ), su_user=('ansible_su_user', ), su_pass=('ansible_su_password', 'ansible_su_pass'), su_exe=('ansible_su_exe', ), su_flags=('ansible_su_flags', ), ) # POPULATE SETTINGS FROM CONFIG ### config = ConfigManager() # Generate constants from config for setting in config.data.get_settings(): value = setting.value if setting.origin == 'default' and \ isinstance(setting.value, string_types) and \ (setting.value.startswith('{{') and setting.value.endswith('}}')): try: t = Template(setting.value) value = t.render(vars()) try: value = literal_eval(value) except ValueError: pass # not a python data structure
class ConfigCLI(CLI): """ Config command line class """ name = 'ansible-config' def __init__(self, args, callback=None): self.config_file = None self.config = None super(ConfigCLI, self).__init__(args, callback) def init_parser(self): super(ConfigCLI, self).init_parser(desc="View ansible configuration.", ) common = opt_help.argparse.ArgumentParser(add_help=False) opt_help.add_verbosity_options(common) common.add_argument( '-c', '--config', dest='config_file', help= "path to configuration file, defaults to first file found in precedence." ) common.add_argument("-t", "--type", action="store", default='base', dest='type', choices=['all', 'base'] + list(C.CONFIGURABLE_PLUGINS), help="Filter down to a specific plugin type.") common.add_argument( 'args', help='Specific plugin to target, requires type of plugin to be set', nargs='*') subparsers = self.parser.add_subparsers(dest='action') subparsers.required = True list_parser = subparsers.add_parser('list', help='Print all config options', parents=[common]) list_parser.set_defaults(func=self.execute_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") view_parser = subparsers.add_parser('view', help='View configuration file', parents=[common]) view_parser.set_defaults(func=self.execute_view) init_parser = subparsers.add_parser( 'init', help='Create initial configuration', parents=[common]) init_parser.set_defaults(func=self.execute_init) init_parser.add_argument('--format', '-f', dest='format', action='store', choices=['ini', 'env', 'vars'], default='ini', help='Output format for init') init_parser.add_argument( '--disabled', dest='commented', action='store_true', default=False, help='Prefixes all entries with a comment character to disable them' ) # search_parser = subparsers.add_parser('find', help='Search configuration') # search_parser.set_defaults(func=self.execute_search) # search_parser.add_argument('args', help='Search term', metavar='<search term>') def post_process_args(self, options): options = super(ConfigCLI, self).post_process_args(options) display.verbosity = options.verbosity return options def run(self): super(ConfigCLI, self).run() if context.CLIARGS['config_file']: self.config_file = unfrackpath(context.CLIARGS['config_file'], follow=False) b_config = to_bytes(self.config_file) if os.path.exists(b_config) and os.access(b_config, os.R_OK): self.config = ConfigManager(self.config_file) else: raise AnsibleOptionsError( 'The provided configuration file is missing or not accessible: %s' % to_native(self.config_file)) else: self.config = C.config self.config_file = self.config._config_file if self.config_file: try: if not os.path.exists(self.config_file): raise AnsibleOptionsError( "%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = to_native(self.config_file) except Exception: if context.CLIARGS['action'] in ['view']: raise elif context.CLIARGS['action'] in ['edit', 'update']: display.warning( "File does not exist, used empty file: %s" % self.config_file) elif context.CLIARGS['action'] == 'view': raise AnsibleError('Invalid or no config file was supplied') # run the requested action context.CLIARGS['func']() def execute_update(self): ''' Updates a single setting in the specified ansible.cfg ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable if context.CLIARGS['setting'] is None: raise AnsibleOptionsError( "update option requires a setting to update") (entry, value) = context.CLIARGS['setting'].split('=') if '.' in entry: (section, option) = entry.split('.') else: section = 'defaults' option = entry subprocess.call([ 'ansible', '-m', 'ini_file', 'localhost', '-c', 'local', '-a', '"dest=%s section=%s option=%s value=%s backup=yes"' % (self.config_file, section, option, value) ]) def execute_view(self): ''' Displays the current config file ''' try: with open(self.config_file, 'rb') as f: self.pager(to_text(f.read(), errors='surrogate_or_strict')) except Exception as e: raise AnsibleError("Failed to open config file: %s" % to_native(e)) def execute_edit(self): ''' Opens ansible.cfg in the default EDITOR ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable try: editor = shlex.split(os.environ.get('EDITOR', 'vi')) editor.append(self.config_file) subprocess.call(editor) except Exception as e: raise AnsibleError("Failed to open editor: %s" % to_native(e)) def _list_plugin_settings(self, ptype, plugins=None): entries = {} loader = getattr(plugin_loader, '%s_loader' % ptype) # build list if plugins: plugin_cs = [] for plugin in plugins: p = loader.get(plugin, class_only=True) if p is None: display.warning( "Skipping %s as we could not find matching plugin" % plugin) else: plugin_cs.append(p) else: plugin_cs = loader.all(class_only=True) # iterate over class instances for plugin in plugin_cs: finalname = name = plugin._load_name if name.startswith('_'): # alias or deprecated if os.path.islink(plugin._original_path): continue else: finalname = name.replace('_', '', 1) + ' (DEPRECATED)' entries[finalname] = self.config.get_configuration_definitions( ptype, name) return entries def _list_entries_from_args(self): ''' build a dict with the list requested configs ''' config_entries = {} if context.CLIARGS['type'] in ('base', 'all'): # this dumps main/common configs config_entries = self.config.get_configuration_definitions( ignore_private=True) if context.CLIARGS['type'] != 'base': config_entries['PLUGINS'] = {} if context.CLIARGS['type'] == 'all': # now each plugin type for ptype in C.CONFIGURABLE_PLUGINS: config_entries['PLUGINS'][ ptype.upper()] = self._list_plugin_settings(ptype) elif context.CLIARGS['type'] != 'base': config_entries['PLUGINS'][ context.CLIARGS['type']] = self._list_plugin_settings( context.CLIARGS['type'], context.CLIARGS['args']) return config_entries def execute_list(self): ''' list and output available configs ''' config_entries = self._list_entries_from_args() self.pager( to_text(yaml.dump(config_entries, Dumper=AnsibleDumper), errors='surrogate_or_strict')) def _get_settings_vars(self, settings, subkey): data = [] if context.CLIARGS['commented']: prefix = '#' else: prefix = '' for setting in settings: if not settings[setting].get('description'): continue default = settings[setting].get('default', '') if subkey == 'env': stype = settings[setting].get('type', '') if stype == 'boolean': if default: default = '1' else: default = '0' elif default: if stype == 'list': if not isinstance(default, string_types): # python lists are not valid env ones try: default = ', '.join(default) except Exception as e: # list of other stuff default = '%s' % to_native(default) if isinstance(default, string_types) and not is_quoted(default): default = shlex.quote(default) elif default is None: default = '' if subkey in settings[setting] and settings[setting][subkey]: entry = settings[setting][subkey][-1]['name'] if isinstance(settings[setting]['description'], string_types): desc = settings[setting]['description'] else: desc = '\n#'.join(settings[setting]['description']) name = settings[setting].get('name', setting) data.append( '# %s(%s): %s' % (name, settings[setting].get('type', 'string'), desc)) # TODO: might need quoting and value coercion depending on type if subkey == 'env': 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')) data.append('') return data def _get_settings_ini(self, settings): sections = {} for o in sorted(settings.keys()): opt = settings[o] if not isinstance(opt, Mapping): # recursed into one of the few settings that is a mapping, now hitting it's strings continue if not opt.get('description'): # its a plugin new_sections = self._get_settings_ini(opt) for s in new_sections: if s in sections: sections[s].extend(new_sections[s]) else: sections[s] = new_sections[s] continue if isinstance(opt['description'], string_types): desc = '# (%s) %s' % (opt.get('type', 'string'), opt['description']) else: desc = "# (%s) " % opt.get('type', 'string') desc += "\n# ".join(opt['description']) if 'ini' in opt and opt['ini']: entry = opt['ini'][-1] 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 = '' if context.CLIARGS['commented']: entry['key'] = ';%s' % entry['key'] key = desc + '\n%s=%s' % (entry['key'], default) sections[entry['section']].append(key) return sections def execute_init(self): 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) if plugin_types: for ptype in plugin_types: plugin_sections = self._get_settings_ini( plugin_types[ptype]) for s in plugin_sections: if s in sections: sections[s].extend(plugin_sections[s]) else: sections[s] = plugin_sections[s] if sections: for section in sections.keys(): data.append('[%s]' % section) for key in sections[section]: data.append(key) data.append('') data.append('') elif context.CLIARGS['format'] in ( 'env', 'vars'): # TODO: add yaml once that config option is added data = self._get_settings_vars(config_entries, context.CLIARGS['format']) if plugin_types: for ptype in plugin_types: for plugin in plugin_types[ptype].keys(): data.extend( self._get_settings_vars( plugin_types[ptype][plugin], context.CLIARGS['format'])) self.pager(to_text('\n'.join(data), errors='surrogate_or_strict')) def _render_settings(self, config): text = [] 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' else: color = 'yellow' changed = True msg = "%s(%s) = %s" % (setting, config[setting].origin, config[setting].value) else: color = 'green' msg = "%s(%s) = %s" % (setting, 'default', config[setting].get('default')) if not context.CLIARGS['only_changed'] or changed: text.append(stringc(msg, color)) return text 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 return self._render_settings(config) def _get_plugin_configs(self, ptype, plugins): # prep loading loader = getattr(plugin_loader, '%s_loader' % ptype) # acumulators text = [] config_entries = {} # build list if plugins: plugin_cs = [] for plugin in plugins: p = loader.get(plugin, class_only=True) if p is None: display.warning( "Skipping %s as we could not find matching plugin" % plugin) else: plugin_cs.append(loader.get(plugin, class_only=True)) else: plugin_cs = loader.all(class_only=True) for plugin in plugin_cs: # in case of deprecastion they diverge finalname = name = plugin._load_name if name.startswith('_'): if os.path.islink(plugin._original_path): # skip alias continue # deprecated, but use 'nice name' finalname = name.replace('_', '', 1) + ' (DEPRECATED)' # default entries per plugin config_entries[ finalname] = self.config.get_configuration_definitions( ptype, name) try: # populate config entries by loading plugin dump = loader.get(name, class_only=True) except Exception as e: display.warning( 'Skipping "%s" %s plugin, as we cannot load plugin to check config due to : %s' % (name, ptype, to_native(e))) continue # 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) except AnsibleError as e: if to_text(e).startswith( 'No setting was provided for required configuration' ): v = None o = 'REQUIRED' else: raise e if v is None and o is None: # not all cases will be error o = 'REQUIRED' config_entries[finalname][setting] = Setting( setting, v, o, None) # 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 def execute_dump(self): ''' Shows the current settings, merges ansible.cfg if specified ''' if context.CLIARGS['type'] == 'base': # deal with base text = self._get_global_configs() elif context.CLIARGS['type'] == 'all': # deal with base text = self._get_global_configs() # deal with plugins for ptype in C.CONFIGURABLE_PLUGINS: text.append('\n%s:\n%s' % (ptype.upper(), '=' * len(ptype))) text.extend( self._get_plugin_configs(ptype, context.CLIARGS['args'])) else: # deal with plugins text = self._get_plugin_configs(context.CLIARGS['type'], context.CLIARGS['args']) self.pager(to_text('\n'.join(text), errors='surrogate_or_strict'))
class ConfigCLI(CLI): """ Config command line class """ VALID_ACTIONS = ("view", "dump", "list") # TODO: edit, update, search def __init__(self, args, callback=None): self.config_file = None self.config = None super(ConfigCLI, self).__init__(args, callback) def parse(self): self.parser = CLI.base_parser( usage="usage: %%prog [%s] [--help] [options] [ansible.cfg]" % "|".join(self.VALID_ACTIONS), epilog="\nSee '%s <command> --help' for more information on a specific command.\n\n" % os.path.basename(sys.argv[0]), desc="View, edit, and manage ansible configuration.", ) self.parser.add_option('-c', '--config', dest='config_file', help="path to configuration file, defaults to first file found in precedence.") self.set_action() # options specific to self.actions if self.action == "list": self.parser.set_usage("usage: %prog list [options] ") if self.action == "dump": self.parser.add_option('--only-changed', dest='only_changed', action='store_true', help="Only show configurations that have changed from the default") elif self.action == "update": self.parser.add_option('-s', '--setting', dest='setting', help="config setting, the section defaults to 'defaults'") self.parser.set_usage("usage: %prog update [options] [-c ansible.cfg] -s '[section.]setting=value'") elif self.action == "search": self.parser.set_usage("usage: %prog update [options] [-c ansible.cfg] <search term>") self.options, self.args = self.parser.parse_args() display.verbosity = self.options.verbosity def run(self): super(ConfigCLI, self).run() if self.options.config_file: self.config_file = unfrackpath(self.options.config_file, follow=False) self.config = ConfigManager(self.config_file) else: self.config = ConfigManager() self.config_file = find_ini_config_file() if self.config_file: try: if not os.path.exists(self.config_file): raise AnsibleOptionsError("%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = to_native(self.config_file) except: if self.action in ['view']: raise elif self.action in ['edit', 'update']: display.warning("File does not exist, used empty file: %s" % self.config_file) elif self.action == 'view': raise AnsibleError('Invalid or no config file was supplied') self.execute() def execute_update(self): ''' Updates a single setting in the specified ansible.cfg ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable if self.options.setting is None: raise AnsibleOptionsError("update option requries a setting to update") (entry, value) = self.options.setting.split('=') if '.' in entry: (section, option) = entry.split('.') else: section = 'defaults' option = entry subprocess.call([ 'ansible', '-m', 'ini_file', 'localhost', '-c', 'local', '-a', '"dest=%s section=%s option=%s value=%s backup=yes"' % (self.config_file, section, option, value) ]) def execute_view(self): ''' Displays the current config file ''' try: with open(self.config_file, 'rb') as f: self.pager(to_text(f.read(), errors='surrogate_or_strict')) except Exception as e: raise AnsibleError("Failed to open config file: %s" % to_native(e)) def execute_edit(self): ''' Opens ansible.cfg in the default EDITOR ''' raise AnsibleError("Option not implemented yet") # pylint: disable=unreachable try: editor = shlex.split(os.environ.get('EDITOR', 'vi')) editor.append(self.config_file) subprocess.call(editor) except Exception as e: raise AnsibleError("Failed to open editor: %s" % to_native(e)) def execute_list(self): ''' list all current configs reading lib/constants.py and shows env and config file setting names ''' self.pager(to_text(yaml.dump(self.config.get_configuration_definitions(), Dumper=AnsibleDumper), errors='surrogate_or_strict')) def execute_dump(self): ''' Shows the current settings, merges ansible.cfg if specified ''' # FIXME: deal with plugins, not just base config text = [] defaults = self.config.get_configuration_definitions().copy() for setting in self.config.data.get_settings(): if setting.name in defaults: defaults[setting.name] = setting for setting in sorted(defaults): if isinstance(defaults[setting], Setting): if defaults[setting].origin == 'default': color = 'green' else: color = 'yellow' msg = "%s(%s) = %s" % (setting, defaults[setting].origin, defaults[setting].value) else: color = 'green' msg = "%s(%s) = %s" % (setting, 'default', defaults[setting].get('default')) if not self.options.only_changed or color == 'yellow': text.append(stringc(msg, color)) self.pager(to_text('\n'.join(text), errors='surrogate_or_strict'))
def setUp(self): self.manager = ConfigManager(cfg_file, os.path.join(curdir, 'test.yml'))
class Loader: def __init__(self): self._config = ConfigManager() self._loader = DataLoader() self._file_vault_secrets = {} self._inventory: InventoryManager = None self._variables: VariableManager = None def _load_file_vault_secrets(self, password_file_path=None): if password_file_path is None: password_file_path = self._config.get_config_value( "DEFAULT_VAULT_PASSWORD_FILE") password_file = Path(password_file_path) if password_file.name in self._file_vault_secrets: return if not password_file.is_file(): raise FileNotFoundError(password_file) self._file_vault_secrets[password_file.name] = get_file_vault_secret( filename=password_file, loader=self._loader) self._file_vault_secrets[password_file.name].load() self._loader.set_vault_secrets([ (password_file.name, self._file_vault_secrets[password_file.name]) ]) def _get_inventory(self, source=None): if source is None: source = self._config.get_config_value("DEFAULT_HOST_LIST") if self._inventory is None: self._inventory = InventoryManager(loader=self._loader, sources=source) else: sources = source if isinstance(source, list) else [source] (self._inventory.parse_source(s) for s in sources) self._inventory.reconcile_inventory() return self._inventory def _get_variables(self, source=None): self._load_file_vault_secrets() if self._variables is None: self._variables = VariableManager( loader=self._loader, inventory=self._get_inventory(source)) return self._variables def get_hosts(self, pattern='all', source=None): return self._get_inventory(source).get_hosts(pattern) def get_host(self, hostname, source=None): return self._get_inventory(source).get_host(hostname) def get_vars(self, host, data={}): play = Play.load(data, loader=self._loader, variable_manager=self._get_variables()) return self._get_variables().get_vars(host=host, play=play)