def build_inventory(self): self.clear_caches() loader = DataLoader() # Ansible 2.2 and 2.3 specific fixes if ansible_version.startswith('2.2.') or ansible_version.startswith( '2.3.'): variable_manager = ansible.vars.VariableManager() variable_manager.extra_vars = load_extra_vars( loader=loader, options=EmptyOptions()) inventory = ansible.inventory.Inventory( loader=loader, variable_manager=variable_manager, host_list=self.inventory_path.strpath) variable_manager.set_inventory(inventory) # Ansible 2.4+ else: inventory = InventoryManager(loader=loader, sources=self.inventory_path.strpath) variable_manager = VariableManager(loader=loader, inventory=inventory) variable_manager.extra_vars = load_extra_vars( loader=loader, options=EmptyOptions()) return inventory
def clear_caches(self): # Ansible 2.2 and 2.3 specific fixes if ansible_version.startswith('2.2.') or ansible_version.startswith( '2.3.'): # unfortunately we have to reset caches as these are kept as module state ansible.inventory.HOSTS_PATTERNS_CACHE.clear() ansible.vars.HOSTVARS_CACHE.clear() # Ansible 2.4+ elif self.inventory is not None: self.inventory.clear_caches()
def run(self): try: output = self.output if isinstance(output, logging.Logger): output = None if ansible_version.startswith("1."): self.result.put((0, self.launch_playbook_v1(), output)) elif ansible_version.startswith("2."): self.result.put((0, self.launch_playbook_v2(), output)) else: display("ERROR: Unknown Ansible version.", output=self.output) self.result.put((0, (1, []), output)) except errors.AnsibleError, e: display("ERROR: %s" % e, output=self.output) self.result.put((0, (1, []), output))
def run(self): try: if ansible_version.startswith("1."): self.results = self.launch_playbook_v1() else: self.results = self.launch_playbook_v2() except errors.AnsibleError, e: display("ERROR: %s" % e, output=self.output) self.results = (1, [])
def __init__( self, servers, ignore_unreachable=False, ignore_errors=False, **runner_args ): """ Initializes the api. :servers: A list of servers or a string with space-delimited servers. The api instances will operate on these servers only. Servers which cannot be reached or whose use triggers an error are taken out of the list for the lifetime of the object. e.g: ['server1', 'server2'] or 'server' or 'server1 server2'. :ignore_unreachable: If true, unreachable servers will not trigger an exception. They are however still taken out of the list for the lifetime of the object. :ignore_errors: If true, errors on servers will not trigger an exception. Servers who trigger an error are still ignored for the lifteime of the object. :**runner_args: All remining keyword arguments are passed to the Ansible runner initializiation. A common option would be sudo: Api('myserver', sudo=True) """ if isinstance(servers, basestring): self.servers = servers.split(u' ') else: self.servers = list(servers) # if the target is the local host but the transport is not set default # to transport = 'local' as it's usually what you want if 'transport' not in runner_args: if set(self.servers).issubset(set(('localhost', '127.0.0.1'))): runner_args['transport'] = 'local' # Ansible 1.9+ changed the way the API does sudo. To support old code # we automatically switch to the new scheme if we need to. if 'sudo' in runner_args and __version__.startswith('1.9.'): runner_args['become'] = runner_args.pop('sudo') self.runner_args = runner_args self._valid_return_codes = (0, ) self.ignore_unreachable = ignore_unreachable self.ignore_errors = ignore_errors for runner in (ModuleRunner(m) for m in list_ansible_modules()): runner.hookup(self)
def worker(pending_queue: multiprocessing.Queue, completed_queue: multiprocessing.Queue) -> None: """Extract the documentation from a plugin, place in completed queue. :param pending_queue: A queue with plugins to process :param completed_queue: The queue in which extracted documentation will be placed """ # pylint: disable=import-outside-toplevel # load the fragment_loader _after_ the path is set from ansible.plugins.loader import fragment_loader while True: entry = pending_queue.get() if entry is None: break collection_name, checksum, plugin_path = entry try: if ansible_version.startswith("2.9"): (doc, examples, returndocs, metadata) = get_docstring( filename=str(plugin_path), fragment_loader=fragment_loader, ) else: (doc, examples, returndocs, metadata) = get_docstring( filename=str(plugin_path), fragment_loader=fragment_loader, collection_name=collection_name, ) except Exception as exc: # pylint: disable=broad-except err_message = f"{type(exc).__name__} (get_docstring): {str(exc)}" completed_queue.put( ("error", (checksum, plugin_path, err_message))) continue try: q_message = { "plugin": { "doc": doc, "examples": examples, "returndocs": returndocs, "metadata": metadata, }, "timestamp": datetime.utcnow().isoformat(), } completed_queue.put( ("plugin", (checksum, json.dumps(q_message, default=str)))) except JSONDecodeError as exc: err_message = f"{type(exc).__name__} (json_decode_doc): {str(exc)}" completed_queue.put( ("error", (checksum, plugin_path, err_message)))
# # Some parts of this code are taken from the Ansible code # (c) 2012-2014, Michael DeHaan <*****@*****.**> # import sys import time import os from multiprocessing import Process import subprocess import signal import logging from ansible import errors from ansible import __version__ as ansible_version if ansible_version.startswith("1."): import ansible.playbook import ansible.inventory import ansible.constants as C from ansible import utils from ansible_callbacks import banner, AggregateStats, PlaybookCallbacks, PlaybookRunnerCallbacks else: from ansible.cli import CLI from ansible.parsing.dataloader import DataLoader from ansible.vars import VariableManager import ansible.inventory from ansible_executor_v2 import IMPlaybookExecutor
from __future__ import (absolute_import, division, print_function) __metaclass__ = type from ansible import __version__ from ansible.errors import AnsibleError if __version__.startswith('1'): raise AnsibleError( 'Trellis no longer supports Ansible 1.x. Please upgrade to Ansible 2.x.' ) # These imports will produce Traceback in Ansible 1.x, so place after version check from __main__ import cli from ansible.compat.six import iteritems class VarsModule(object): ''' Creates and modifies host variables ''' def __init__(self, inventory): self.inventory = inventory self.inventory_basedir = inventory.basedir() self._options = cli.options if cli else None # Wrap salts and keys variables in {% raw %} to prevent jinja templating errors def wrap_salts_in_raw(self, host, hostvars): if 'vault_wordpress_sites' in hostvars: for name, site in hostvars['vault_wordpress_sites'].iteritems(): for key, value in site['env'].iteritems(): if key.endswith( ('_key', '_salt')) and not value.startswith(
if self._play_context.become and self._play_context.become_method == 'dockerexec': exec_user = self._play_context.become_user else: exec_user = self.remote_user if exec_user is not None: local_cmd += ['-u', exec_user] # -i is needed to keep stdin open which allows pipelining to work local_cmd += ['-i', self._play_context.remote_addr] + cmd return local_cmd # Ansible 2.2 specific fixes if ansible_version.startswith('2.2.'): @staticmethod def _sanitize_version(version): return re.sub(b'[^0-9a-zA-Z\.]', b'', version) def _get_docker_version(self): cmd, cmd_output, err, returncode = self._old_docker_version() if returncode == 0: for line in cmd_output.split(b'\n'): if line.startswith(b'Server version:'): # old docker versions return self._sanitize_version(line.split()[2]).decode('utf-8') cmd, cmd_output, err, returncode = self._new_docker_version() if returncode: raise AnsibleError('Docker version check (%s) failed: %s' % (cmd, err))
from __future__ import (absolute_import, division, print_function) __metaclass__ = type from ansible import __version__ from ansible.errors import AnsibleError if __version__.startswith('1'): raise AnsibleError('Trellis no longer supports Ansible 1.x. Please upgrade to Ansible 2.x.') # This import will produce Traceback in Ansible 1.x, so place after version check from __main__ import cli class VarsModule(object): ''' Creates and modifies host variables ''' def __init__(self, inventory): self.inventory = inventory self.inventory_basedir = inventory.basedir() self._options = cli.options if cli else None # Wrap salts and keys variables in {% raw %} to prevent jinja templating errors def wrap_salts_in_raw(self, host, hostvars): if 'vault_grav_sites' in hostvars: for name, site in hostvars['vault_grav_sites'].iteritems(): for key, value in site['env'].iteritems(): if key.endswith(('_key', '_salt')) and not value.startswith(('{% raw', '{%raw')): hostvars['vault_grav_sites'][name]['env'][key] = ''.join(['{% raw %}', value, '{% endraw %}']) host.vars['vault_grav_sites'] = hostvars['vault_grav_sites'] def cli_args_vault(self):
def main(): module = AnsibleModule( argument_spec=dict( dest=dict(required=True, aliases=['name', 'destfile']), state=dict(default='present', choices=['absent', 'present']), marker=dict(default='# {mark} ANSIBLE MANAGED BLOCK', type='str'), block=dict(default='', type='str', aliases=['content']), insertafter=dict(default=None), insertbefore=dict(default=None), create=dict(default=False, type='bool'), backup=dict(default=False, type='bool'), validate=dict(default=None, type='str'), ), mutually_exclusive=[['insertbefore', 'insertafter']], add_file_common_args=True, supports_check_mode=True ) params = module.params dest = os.path.expanduser(params['dest']) if module.boolean(params.get('follow', None)): dest = os.path.realpath(dest) if os.path.isdir(dest): module.fail_json(rc=256, msg='Destination %s is a directory !' % dest) if not os.path.exists(dest): if not module.boolean(params['create']): module.fail_json(rc=257, msg='Destination %s does not exist !' % dest) original = None lines = [] else: f = open(dest, 'rb') original = f.read() f.close() lines = original.splitlines() insertbefore = params['insertbefore'] insertafter = params['insertafter'] block = params['block'] marker = params['marker'] present = params['state'] == 'present' if insertbefore is None and insertafter is None: insertafter = 'EOF' if insertafter not in (None, 'EOF'): insertre = re.compile(insertafter) elif insertbefore not in (None, 'BOF'): insertre = re.compile(insertbefore) else: insertre = None marker0 = re.sub(r'{mark}', 'BEGIN', marker) marker1 = re.sub(r'{mark}', 'END', marker) if present and block: # Escape seqeuences like '\n' need to be handled in Ansible 1.x if __version__.startswith('1.'): block = re.sub('', block, '') blocklines = [marker0] + block.splitlines() + [marker1] else: blocklines = [] n0 = n1 = None for i, line in enumerate(lines): if line.startswith(marker0): n0 = i if line.startswith(marker1): n1 = i if None in (n0, n1): n0 = None if insertre is not None: for i, line in enumerate(lines): if insertre.search(line): n0 = i if n0 is None: n0 = len(lines) elif insertafter is not None: n0 += 1 elif insertbefore is not None: n0 = 0 # insertbefore=BOF else: n0 = len(lines) # insertafter=EOF elif n0 < n1: lines[n0:n1+1] = [] else: lines[n1:n0+1] = [] n0 = n1 lines[n0:n0] = blocklines if lines: result = '\n'.join(lines)+'\n' else: result = '' if original == result: msg = '' changed = False elif original is None: msg = 'File created' changed = True elif not blocklines: msg = 'Block removed' changed = True else: msg = 'Block inserted' changed = True if changed and not module.check_mode: if module.boolean(params['backup']) and os.path.exists(dest): module.backup_local(dest) write_changes(module, result, dest) msg, changed = check_file_attrs(module, changed, msg) module.exit_json(changed=changed, msg=msg)
# add current dir to import path import sys import os sys.path.append(os.path.dirname(__file__)) # import the right plugin for the right ansible major version from ansible import __version__ as ansible_version if ansible_version.startswith('2.'): from ansible2_nested_dict import LookupModule elif ansible_version.startswith('1.'): from ansible1_nested_dict import LookupModule
for thedef in cls.body: assert isinstance(thedef, ast.Assign), thedef assert len(thedef.targets) == 1 key = thedef.targets[0].id assert isinstance(thedef.value, ast.Str) data = AnsibleLoader(thedef.value.s, file_name=path).get_single_data() fragments[key] = data return fragments # TODO: figure out how to make this not crazy hacky target_pythonpath = os.path.join('target', 'ansible_collections') for namespace in os.listdir(target_pythonpath): namespace_dir = os.path.join(target_pythonpath, namespace) for name in os.listdir(namespace_dir): if namespace == 'ansible' and name == 'base' and __version__.startswith( '2.9'): print('skipping ansible.base b/c not a thing in 2.9') continue fqcn = f'{namespace}.{name}' req_data.setdefault(fqcn, []) collection_dir = os.path.join(namespace_dir, name) top_content = os.listdir(collection_dir) collection_dir = os.path.join(target_pythonpath, namespace, name) for candidate in os.listdir(collection_dir): # no thanks to python2 if ('requirement' in candidate) and ('txt' in candidate) and ( '2.7' not in candidate): with open(os.path.join(collection_dir, candidate), 'r') as f: req_text = f.read() req_text = req_text.strip()