def _run_playbook(playbook, service, node): # Unfortunately, there's no good way to get the options instance # with proper defaults since it's generated by argparse inside # PlaybookCLI. Due to the fact that the options can't be empty # and must contain proper values we have not choice but extract # them from PlaybookCLI instance. playbook_cli = PlaybookCLI(['to-be-stripped', playbook]) playbook_cli.parse() options = playbook_cli.options # Get others required options. loader = DataLoader() variable_manager = VariableManager() inventory = Inventory(loader, variable_manager) variable_manager.set_inventory(inventory) variable_manager.extra_vars = _get_user_settings(loader) # OpenStack Ansible deploys control plane services in LXC containers, # and use those as native hosts in its inventory. However, from # Kostyor's POV we are interested in baremetal node-by-node upgrade, # so we need to limit playbook execution only to baremetal node under # upgrade and its service's containers. inventory.subset([ host.get_vars()['inventory_hostname'] for host in _get_component_hosts_on_node(inventory, service, node) ]) # Finally, we can create a playbook executor and run the playbook. executor = PlaybookExecutor(playbooks=[playbook], inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords={}) executor.run()
class Runner(object): def __init__(self, playbook, display, hosts=None, options={}, passwords={}, vault_pass=None): self.options = Options() for k, v in options.iteritems(): setattr(self.options, k, v) self.display = display self.display.verbosity = self.options.verbosity # executor has its own verbosity setting playbook_executor.verbosity = self.options.verbosity # gets data from YAML/JSON files self.loader = DataLoader() if vault_pass is not None: self.loader.set_vault_password(vault_pass) elif 'VAULT_PASS' in os.environ: self.loader.set_vault_password(os.environ['VAULT_PASS']) # all the variables from all the various places self.variable_manager = VariableManager() if self.options.python_interpreter is not None: self.variable_manager.extra_vars = { 'ansible_python_interpreter': self.options.python_interpreter } # set inventory, using most of above objects self.inventory = Inventory( loader=self.loader, variable_manager=self.variable_manager, host_list=hosts) if len(self.inventory.list_hosts()) == 0: self.display.error("Provided hosts list is empty.") sys.exit(1) self.inventory.subset(self.options.subset) if len(self.inventory.list_hosts()) == 0: self.display.error("Specified limit does not match any hosts.") sys.exit(1) self.variable_manager.set_inventory(self.inventory) # setup playbook executor, but don't run until run() called self.pbex = playbook_executor.PlaybookExecutor( playbooks=[playbook], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=passwords) def run(self): # run playbook and get stats self.pbex.run() stats = self.pbex._tqm._stats return stats
def ansible_inventory(ansiblehosts, subset=None): if os.path.isdir(ansiblehosts) or os.path.isfile(ansiblehosts): inventory = Inventory(ansiblehosts) if subset: inventory.subset(subset) else: print >> sys.stderr, "### ERROR ansible-hosts %s not found" % ( ansiblehosts) return (inventory)
def run_embebed_playb(self, options, passwords): # initialize needed objects variable_manager = VariableManager() loader = DataLoader() # Instantiate our ResultCallback for handling results as they come in results_callback = ResultCallback() # create inventory and pass to var manager inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.inventory['hosts']) inventory.subset(self.inventory['subset']) variable_manager.set_inventory(inventory) variable_manager.extra_vars = { 'ansible_connection': self.ansible_cnx['ansible_connection'] } # create play with tasks play_source = dict( name="RUN PLAY", hosts=self.target, #remote_user = self.ansible_cnx['ansible_user'], gather_facts='false', tasks=[ dict(action=dict(module=self.module, args=self.pargs), register='module_out'), ]) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # actually run it tqm = None try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, stdout_callback=results_callback, # custom callback ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() return results_callback.results
def run_task(self, group, gather_facts=u'no', tasks=[], frmt=u'json'): """ """ # set options self.options.tags = [] # Set inventory, using most of above objects #inventory = InventoryManager(self.loader, sources=self.inventory) inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=self.inventory) inventory.subset(group) self.variable_manager.set_inventory(inventory) # create play with tasks play_source = dict(name=u'Ansible Play', hosts=group, gather_facts=gather_facts, tasks=tasks) play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) # Instantiate our ResultCallback for handling results as they come in results_callback = ResultCallback(frmt=frmt) # run it tqm = None result = None try: # Use our custom callback instead of the ``default`` callback plugin tqm = TaskQueueManager( inventory=inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=results_callback, ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() return result
def _run_playbook_impl(playbook, hosts_fn=None, cwd=None, ignore_errors=False): # Unfortunately, there's no good way to get the options instance # with proper defaults since it's generated by argparse inside # PlaybookCLI. Due to the fact that the options can't be empty # and must contain proper values we have not choice but extract # them from PlaybookCLI instance. playbook_cli = PlaybookCLI(['to-be-stripped', playbook]) playbook_cli.parse() options = playbook_cli.options # Get others required options. loader = DataLoader() variable_manager = VariableManager() inventory = Inventory(loader, variable_manager) variable_manager.set_inventory(inventory) variable_manager.extra_vars = _get_user_settings(loader) # Limit playbook execution to hosts returned by 'hosts_fn'. if hosts_fn is not None: inventory.subset([ host.get_vars()['inventory_hostname'] for host in hosts_fn(inventory) ]) # Finally, we can create a playbook executor and run the playbook. executor = PlaybookExecutor(playbooks=[playbook], inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords={}) # Some playbooks may rely on current working directory, so better allow # to change it before execution. with _setcwd(cwd): exitcode = executor.run() # Celery treats exceptions from task as way to mark it failed. So let's # throw one to do so in case return code is not zero. if all([not ignore_errors, exitcode is not None, exitcode != 0]): raise Exception('Playbook "%s" has been finished with errors. ' 'Exit code is "%d".' % (playbook, exitcode)) return exitcode
def run_yml_playb(self, options, passwords, playbook=None): # initialize needed objects variable_manager = VariableManager() loader = DataLoader() # Instantiate our ResultCallback for handling results as they come in results_callback = ResultCallback() # create inventory and pass to var manager inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.inventory['hosts']) inventory.subset(self.inventory['subset']) variable_manager.set_inventory(inventory) # Currently support target = servers, cmd = commands, dir = args: dir variable_manager.extra_vars = { 'target': self.target, 'cmd': self.pargs, 'dir': '/bin' } # Playbook if playbook is None: playbook_path = 'playbooks/commands.yml' else: playbook_path = 'playbooks/' + playbook if not os.path.exists(playbook_path): print '[INFO] The playbook does not exist' sys.exit() pexec = PlaybookExecutor(playbooks=[playbook_path], inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords) results = pexec.run()
class Runner(object): def __init__(self, playbook, options={}, passwords={}, vault_pass=None): display = Display() ansible_root = '/opt/emc' pb_dir = "{0}/playbooks".format(ansible_root) playbook = "{0}/{1}".format(pb_dir, playbook) hosts = "{0}/hosts.ini".format(ansible_root) # Set options self.options = Options() for k, v in options.iteritems(): setattr(self.options, k, v) self.options.verbosity = 0 # Set global verbosity self.display = display self.display.verbosity = self.options.verbosity # Executor has its own verbosity setting playbook_executor.verbosity = self.options.verbosity # Gets data from YAML/JSON files self.loader = DataLoader() # Set vault password if vault_pass is not None: self.loader.set_vault_password(vault_pass) elif 'VAULT_PASS' in os.environ: self.loader.set_vault_password(os.environ['VAULT_PASS']) # All the variables from all the various places self.variable_manager = VariableManager() if self.options.python_interpreter is not None: self.variable_manager.extra_vars = { 'ansible_python_interpreter': self.options.python_interpreter } # Set inventory, using most of above objects self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=hosts) if len(self.inventory.list_hosts()) == 0: # Empty inventory self.display.error("Provided hosts list is empty.") sys.exit(1) self.inventory.subset(self.options.subset) if len(self.inventory.list_hosts()) == 0: # Invalid limit self.display.error("Specified limit does not match any hosts.") sys.exit(1) self.variable_manager.set_inventory(self.inventory) # Setup playbook executor, but don't run until run() called self.pbex = playbook_executor.PlaybookExecutor( playbooks=[playbook], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=passwords) def run(self): # Run Playbook and get stats self.pbex.run() stats = self.pbex._tqm._stats run_success = True hosts = sorted(stats.processed.keys()) for h in hosts: t = stats.summarize(h) if t['unreachable'] > 0 or t['failures'] > 0: run_success = False # Do the callback # self.pbex._tqm.send_callback( # 'record_logs', # success=run_success # ) return run_success
def run(self): # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None vault_pass = None passwords = {} # don't deal with privilege escalation or passwords when we don't need to if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax: self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() passwords = {'conn_pass': sshpass, 'become_pass': becomepass} if self.options.vault_password_file: # read vault_pass from a file vault_pass = read_vault_file(self.options.vault_password_file) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords(ask_vault_pass=True, ask_new_vault_pass=False, confirm_new=False)[0] loader = DataLoader(vault_password=vault_pass) extra_vars = {} for extra_vars_opt in self.options.extra_vars: extra_vars_opt = to_unicode(extra_vars_opt, errors='strict') if extra_vars_opt.startswith(u"@"): # Argument is a YAML file (JSON is a subset of YAML) data = loader.load_from_file(extra_vars_opt[1:]) elif extra_vars_opt and extra_vars_opt[0] in u'[{': # Arguments as YAML data = loader.load(extra_vars_opt) else: # Arguments as Key-value data = parse_kv(extra_vars_opt) extra_vars = combine_vars(extra_vars, data) # FIXME: this should be moved inside the playbook executor code only_tags = self.options.tags.split(",") skip_tags = self.options.skip_tags if self.options.skip_tags is not None: skip_tags = self.options.skip_tags.split(",") # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor for playbook in self.args: if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError( "the playbook: %s does not appear to be a file" % playbook) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() variable_manager.extra_vars = extra_vars # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory self.display.warning( "provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor(playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, display=self.display, options=self.options, passwords=passwords) results = pbex.run() if isinstance(results, list): for p in results: self.display.display('\nplaybook: %s\n' % p['playbook']) for play in p['plays']: if self.options.listhosts: self.display.display("\n %s (%s): host count=%d" % (play['name'], play['pattern'], len(play['hosts']))) for host in play['hosts']: self.display.display(" %s" % host) if self.options.listtasks: #TODO: do we want to display block info? self.display.display("\n %s" % (play['name'])) for task in play['tasks']: self.display.display(" %s" % task) if self.options.listtags: #TODO: fix once we figure out block handling above self.display.display("\n %s: tags count=%d" % (play['name'], len(play['tags']))) for tag in play['tags']: self.display.display(" %s" % tag) return 0 else: return results
def run(self): super(PlaybookCLI, self).run() # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None vault_pass = None passwords = {} # don't deal with privilege escalation or passwords when we don't need to if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax: self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() passwords = { 'conn_pass': sshpass, 'become_pass': becomepass } if self.options.vault_password_file: # read vault_pass from a file vault_pass = CLI.read_vault_password_file(self.options.vault_password_file) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords(ask_vault_pass=True, ask_new_vault_pass=False, confirm_new=False)[0] loader = DataLoader(vault_password=vault_pass) # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor for playbook in self.args: if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError("the playbook: %s does not appear to be a file" % playbook) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options) # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory self.display.warning("provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor(playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, display=self.display, options=self.options, passwords=passwords) results = pbex.run() if isinstance(results, list): for p in results: self.display.display('\nplaybook: %s' % p['playbook']) i = 1 for play in p['plays']: if play.name: playname = play.name else: playname = '#' + str(i) msg = "\n PLAY: %s" % (playname) mytags = set() if self.options.listtags and play.tags: mytags = mytags.union(set(play.tags)) msg += ' TAGS: [%s]' % (','.join(mytags)) if self.options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % (play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host self.display.display(msg) if self.options.listtags or self.options.listtasks: taskmsg = ' tasks:' for block in play.compile(): if not block.has_tasks(): continue j = 1 for task in block.block: taskmsg += "\n %s" % task if self.options.listtags and task.tags: taskmsg += " TAGS: [%s]" % ','.join(mytags.union(set(task.tags))) j = j + 1 self.display.display(taskmsg) i = i + 1 return 0 else: return results
def run(self): super(PlaybookCLI, self).run() # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None vault_pass = None passwords = {} # don't deal with privilege escalation or passwords when we don't need to if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax: self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() passwords = { 'conn_pass': sshpass, 'become_pass': becomepass } loader = DataLoader() if self.options.vault_password_file: # read vault_pass from a file vault_pass = CLI.read_vault_password_file(self.options.vault_password_file, loader=loader) loader.set_vault_password(vault_pass) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords()[0] loader.set_vault_password(vault_pass) # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor for playbook in self.args: if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError("the playbook: %s does not appear to be a file" % playbook) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options) variable_manager.options_vars = load_options_vars(self.options) # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory display.warning("provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor(playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.options, passwords=passwords) results = pbex.run() if isinstance(results, list): for p in results: display.display('\nplaybook: %s' % p['playbook']) for idx, play in enumerate(p['plays']): msg = "\n play #%d (%s): %s" % (idx + 1, ','.join(play.hosts), play.name) mytags = set(play.tags) msg += '\tTAGS: [%s]' % (','.join(mytags)) if self.options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % (play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host display.display(msg) all_tags = set() if self.options.listtags or self.options.listtasks: taskmsg = '' if self.options.listtasks: taskmsg = ' tasks:\n' def _process_block(b): taskmsg = '' for task in b.block: if isinstance(task, Block): taskmsg += _process_block(task) else: if task.action == 'meta': continue all_tags.update(task.tags) if self.options.listtasks: cur_tags = list(mytags.union(set(task.tags))) cur_tags.sort() if task.name: taskmsg += " %s" % task.get_name() else: taskmsg += " %s" % task.action taskmsg += "\tTAGS: [%s]\n" % ', '.join(cur_tags) return taskmsg all_vars = variable_manager.get_vars(loader=loader, play=play) play_context = PlayContext(play=play, options=self.options) for block in play.compile(): block = block.filter_tagged_tasks(play_context, all_vars) if not block.has_tasks(): continue taskmsg += _process_block(block) if self.options.listtags: cur_tags = list(mytags.union(all_tags)) cur_tags.sort() taskmsg += " TASK TAGS: [%s]\n" % ', '.join(cur_tags) display.display(taskmsg) return 0 else: return results
def run(self): super(PlaybookCLI, self).run() # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None vault_pass = None passwords = {} # don't deal with privilege escalation or passwords when we don't need to if ( not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax ): self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() passwords = {"conn_pass": sshpass, "become_pass": becomepass} loader = DataLoader() if self.options.vault_password_file: # read vault_pass from a file vault_pass = CLI.read_vault_password_file(self.options.vault_password_file, loader=loader) loader.set_vault_password(vault_pass) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords(ask_vault_pass=True, ask_new_vault_pass=False, confirm_new=False)[0] loader.set_vault_password(vault_pass) # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor for playbook in self.args: if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError("the playbook: %s does not appear to be a file" % playbook) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options) # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory self.display.warning("provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor( playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, display=self.display, options=self.options, passwords=passwords, ) results = pbex.run() if isinstance(results, list): for p in results: self.display.display("\nplaybook: %s" % p["playbook"]) i = 1 for play in p["plays"]: if play.name: playname = play.name else: playname = "#" + str(i) msg = "\n PLAY: %s" % (playname) mytags = set() if self.options.listtags and play.tags: mytags = mytags.union(set(play.tags)) msg += " TAGS: [%s]" % (",".join(mytags)) if self.options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % (play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host self.display.display(msg) if self.options.listtags or self.options.listtasks: taskmsg = " tasks:" for block in play.compile(): if not block.has_tasks(): continue j = 1 for task in block.block: taskmsg += "\n %s" % task if self.options.listtags and task.tags: taskmsg += " TAGS: [%s]" % ",".join(mytags.union(set(task.tags))) j = j + 1 self.display.display(taskmsg) i = i + 1 return 0 else: return results
class Runner(object): def __init__( self, playbook, options={}, passwords={}, vault_pass=None): display = Display() ansible_root = '/opt/emc' pb_dir = "{0}/playbooks".format(ansible_root) playbook = "{0}/{1}".format(pb_dir, playbook) hosts = "{0}/hosts.ini".format(ansible_root) # Set options self.options = Options() for k, v in options.iteritems(): setattr(self.options, k, v) self.options.verbosity = 0 # Set global verbosity self.display = display self.display.verbosity = self.options.verbosity # Executor has its own verbosity setting playbook_executor.verbosity = self.options.verbosity # Gets data from YAML/JSON files self.loader = DataLoader() # Set vault password if vault_pass is not None: self.loader.set_vault_password(vault_pass) elif 'VAULT_PASS' in os.environ: self.loader.set_vault_password(os.environ['VAULT_PASS']) # All the variables from all the various places self.variable_manager = VariableManager() if self.options.python_interpreter is not None: self.variable_manager.extra_vars = { 'ansible_python_interpreter': self.options.python_interpreter } # Set inventory, using most of above objects self.inventory = Inventory( loader=self.loader, variable_manager=self.variable_manager, host_list=hosts) if len(self.inventory.list_hosts()) == 0: # Empty inventory self.display.error("Provided hosts list is empty.") sys.exit(1) self.inventory.subset(self.options.subset) if len(self.inventory.list_hosts()) == 0: # Invalid limit self.display.error("Specified limit does not match any hosts.") sys.exit(1) self.variable_manager.set_inventory(self.inventory) # Setup playbook executor, but don't run until run() called self.pbex = playbook_executor.PlaybookExecutor( playbooks=[playbook], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=passwords) def run(self): # Run Playbook and get stats self.pbex.run() stats = self.pbex._tqm._stats run_success = True hosts = sorted(stats.processed.keys()) for h in hosts: t = stats.summarize(h) if t['unreachable'] > 0 or t['failures'] > 0: run_success = False # Do the callback # self.pbex._tqm.send_callback( # 'record_logs', # success=run_success # ) return run_success
def run_playbook(self, group, playbook, private_key_file, run_data, become_pas, tags=[]): """ """ # All the variables from all the various places self.variable_manager.extra_vars = run_data self.variable_manager.group_vars_files = u'%s/group_vars' % self.inventory #print self.variable_manager.get_vars(self.loader) # set options self.options.tags = tags self.options.limit = group #self.options.become = True #self.options.become_user = u'root' #self.options.private_key_file = u'%s/.ssh/id_rsa' % self.inventory # Parse hosts '''hosts = NamedTemporaryFile(delete=False) hosts.write(u'[%s]\n' % group) for host in self.get_inventory(group): hosts.write(u'%s ansible_ssh_private_key_file=%s ansible_user=root\n' % (host, self.options.private_key_file)) hosts.close() # copy .ssh key in tmp os.symlink(u'%s/.ssh' % self.inventory, u'/tmp/.ssh')''' # Set inventory, using most of above objects #inventory = InventoryManager(self.loader, sources=self.inventory) inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=self.inventory) #logger.warn(inventory.list_groups()) inventory.subset(group) logger.warn(inventory.list_groups()) logger.warn(inventory.list_hosts(group)) self.variable_manager.set_inventory(inventory) # Setup playbook executor, but don't run until run() called self.pbex = playbook_executor.PlaybookExecutor( playbooks=[playbook], inventory=inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=None) # Results of PlaybookExecutor self.pbex.run() stats = self.pbex._tqm._stats # Test if success for record_logs run_success = True ihosts = sorted(stats.processed.keys()) for h in ihosts: t = stats.summarize(h) if t[u'unreachable'] > 0 or t[u'failures'] > 0: run_success = False # Remove created temporary files #os.remove(hosts.name) #os.remove(u'/tmp/.ssh') return stats
def run(self): # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None b_vault_pass = None passwords = {} # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor for playbook in self.playbooks: if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError( "the playbook: %s does not appear to be a file" % playbook) # don't deal with privilege escalation or passwords when we don't need to if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax: self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() passwords = {'conn_pass': sshpass, 'become_pass': becomepass} loader = DataLoader() if self.options.vault_password_file: # read vault_pass from a file b_vault_pass = CLI.read_vault_password_file( self.options.vault_password_file, loader=loader) loader.set_vault_password(b_vault_pass) elif self.options.ask_vault_pass: b_vault_pass = self.ask_vault_passwords() loader.set_vault_password(b_vault_pass) elif 'VAULT_PASS' in os.environ: loader.set_vault_password(os.environ['VAULT_PASS']) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() # Subspace injection option_extra_vars = load_extra_vars(loader=loader, options=self.options) option_extra_vars.update(self.extra_vars) variable_manager.extra_vars = option_extra_vars # End Subspace injection variable_manager.options_vars = load_options_vars(self.options) # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory display.warning( "provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # flush fact cache if requested if self.options.flush_cache: self._flush_cache(inventory, variable_manager) hosts = inventory.get_hosts() if self.options.subset and not hosts: raise NoValidHosts( "The limit <%s> is not included in the inventory: %s" % (self.options.subset, inventory.host_list)) # create the playbook executor, which manages running the plays via a task queue manager # Subspace injection pbex = PlaybookExecutor(playbooks=self.playbooks, inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.options, passwords=passwords) playbook_map = self._get_playbook_map() pbex._tqm._stats = SubspaceAggregateStats(playbook_map) pbex._tqm.load_callbacks() pbex._tqm.send_callback( 'start_logging', logger=self.options.logger, username=self.extra_vars.get('ATMOUSERNAME', "No-User"), ) for host in inventory._subset: variables = inventory.get_vars(host) self.options.logger.info("Vars found for hostname %s: %s" % (host, variables)) # End Subspace injection results = pbex.run() # Subspace injection stats = pbex._tqm._stats self.stats = stats # Nonpersistent fact cache stores 'register' variables. We would like # to get access to stdout/stderr for specific commands and relay # some of that information back to the end user. self.results = dict(pbex._variable_manager._nonpersistent_fact_cache) # End Subspace injection if isinstance(results, list): for p in results: display.display('\nplaybook: %s' % p['playbook']) for idx, play in enumerate(p['plays']): if play._included_path is not None: loader.set_basedir(play._included_path) else: pb_dir = os.path.realpath( os.path.dirname(p['playbook'])) loader.set_basedir(pb_dir) msg = "\n play #%d (%s): %s" % (idx + 1, ','.join( play.hosts), play.name) mytags = set(play.tags) msg += '\tTAGS: [%s]' % (','.join(mytags)) if self.options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % ( play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host display.display(msg) all_tags = set() if self.options.listtags or self.options.listtasks: taskmsg = '' if self.options.listtasks: taskmsg = ' tasks:\n' def _process_block(b): taskmsg = '' for task in b.block: if isinstance(task, Block): taskmsg += _process_block(task) else: if task.action == 'meta': continue all_tags.update(task.tags) if self.options.listtasks: cur_tags = list( mytags.union(set(task.tags))) cur_tags.sort() if task.name: taskmsg += " %s" % task.get_name( ) else: taskmsg += " %s" % task.action taskmsg += "\tTAGS: [%s]\n" % ', '.join( cur_tags) return taskmsg all_vars = variable_manager.get_vars(loader=loader, play=play) play_context = PlayContext(play=play, options=self.options) for block in play.compile(): block = block.filter_tagged_tasks( play_context, all_vars) if not block.has_tasks(): continue taskmsg += _process_block(block) if self.options.listtags: cur_tags = list(mytags.union(all_tags)) cur_tags.sort() taskmsg += " TASK TAGS: [%s]\n" % ', '.join( cur_tags) display.display(taskmsg) return 0 else: return results
class Runner(object): def __init__(self, inventory_filename, playbook, extra_vars, verbosity=0, subset=constants.DEFAULT_SUBSET): if not os.path.exists(inventory_filename): raise Exception("Cannot find inventory_filename: {}. Current dir: {}".format(inventory_filename, os.getcwd())) if not os.path.exists(playbook): raise Exception("Cannot find playbook: {}. Current dir: {}".format(playbook, os.getcwd())) self.options = Options() self.options.verbosity = verbosity self.options.connection = 'ssh' # Need a connection type "smart" or "ssh" self.options.subset = subset # Propagate defaults from ANSIBLE_CONFIG into options self.options.module_path = constants.DEFAULT_MODULE_PATH self.options.forks = constants.DEFAULT_FORKS self.options.ask_vault_pass = constants.DEFAULT_ASK_VAULT_PASS self.options.vault_password_files = [constants.DEFAULT_VAULT_PASSWORD_FILE] self.options.sudo = constants.DEFAULT_SUDO self.options.become = constants.DEFAULT_BECOME self.options.become_method = constants.DEFAULT_BECOME_METHOD self.options.become_user = constants.DEFAULT_BECOME_USER self.options.ask_sudo_pass = constants.DEFAULT_ASK_SUDO_PASS self.options.ask_su_pass = constants.DEFAULT_ASK_SU_PASS self.options.ask_pass = constants.DEFAULT_ASK_PASS self.options.private_key_file = constants.DEFAULT_PRIVATE_KEY_FILE self.options.remote_user = constants.DEFAULT_REMOTE_USER self.options.timeout = constants.DEFAULT_TIMEOUT self.options.poll_interval = constants.DEFAULT_POLL_INTERVAL self.options.force_handlers = constants.DEFAULT_FORCE_HANDLERS # Set global verbosity self.display = Display() self.display.verbosity = self.options.verbosity # Executor appears to have it's own # verbosity object/setting as well playbook_executor.verbosity = self.options.verbosity # Become Pass Needed if not logging in as user root passwords = {} # Gets data from YAML/JSON files self.loader = DataLoader() # All the variables from all the various places self.variable_manager = VariableManager() self.variable_manager.extra_vars = extra_vars # WARNING: this is a dirty hack to avoid a situation where creating multiple # instance of this Runner each with it's own Inventory instance was creating # a situation where we ended up with different UUID's for hosts and comparisons # were failing (see http://bit.ly/1qKmV3x) ansible.inventory.HOSTS_PATTERNS_CACHE = {} # Set inventory, using most of above objects self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=inventory_filename) self.inventory.subset(self.options.subset) self.variable_manager.set_inventory(self.inventory) # Setup playbook executor, but don't run until run() called log_info("Running playbook: {}".format(playbook)) self.pbex = playbook_executor.PlaybookExecutor( playbooks=[playbook], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=passwords) def run(self): # Results of PlaybookExecutor self.pbex.run() stats = self.pbex._tqm._stats return stats
class Base(): def __init__(self, exec_mode, work_name, username, options_dict, describe, mongoclient=None): ''' ansible的基类,为adhoc、playbook等父类 :parm: exec_mode:ansible工作类型,接受adhoc、palybook等 work_name:该任务的名称,用于日志 username:执行者 options_dict:该任务的特定设置 mongoclient:初始化mongo连接类 ''' self.logger = logging.getLogger("ansible") if exec_mode in ('adhoc', 'playbook'): self.exec_mode = exec_mode else: self.logger.warn( '正在准备执行ansible任务,准备工作失败,原因:参数exec_mode必须是adhoc或者是playbook') return (False, '参数exec_mode必须是adhoc或者是playbook') if isinstance(work_name, str) and work_name: self.work_name = work_name else: self.logger.warn('正在准备执行ansible任务,准备工作失败,原因:参数work_name必须是非字符串') return (False, '参数work_name必须是非字符串') if isinstance(username, str) and username: self.username = username else: self.logger.warn('正在准备执行ansible任务,准备工作失败,原因:参数username必须是非字符串') return (False, '参数username必须是非字符串') if isinstance(options_dict, dict) and options_dict: self.options_dict = options_dict else: self.logger.warn('正在准备执行ansible任务,准备工作失败,原因:参数options_dict必须是非空字典') return (False, '参数options_dict必须是非空字典') if mongoclient is None: self.mongoclient = Op_Mongo() else: self.mongoclient = mongoclient self.work_uuid = str(uuid.uuid4()) self.log_router = Routing_Logging() self.describe = describe if exec_mode == 'adhoc': self.log_prefix = '正在执行用户' + username + '的名为' + work_name + 'uuid为' + self.work_uuid + '的ansible临时任务,' else: self.log_prefix = '正在执行用户' + username + '的名为' + work_name + 'uuid为' + self.work_uuid + '的ansible-playbook任务,' # 下面是加载和初始化相关类 self._parse_options() self.passwords = { 'conn_pass': self.options.ask_pass, 'become_pass': self.options.become_ask_pass } # 设置passwords self.inventory_file = self.options_dict.get('inventory', '') self.loader = DataLoader() self._get_vault_pwd() self.variable_manager = VariableManager() self.variable_manager.extra_vars = load_extra_vars( loader=self.loader, options=self.options) self.variable_manager.options_vars = load_options_vars(self.options) self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=self.inventory_file) self.variable_manager.set_inventory(self.inventory) self.inventory.subset(self.options.subset) def _get_vault_pwd(self): ''' 获取vault密码,并初始化vault密码 ''' vault_pwd_file = self.options_dict.get('vault_password_file', False) ask_vault_pass = self.options_dict.get('ask_vault_pass', False) if ask_vault_pass: vault_password = ask_vault_pass else: if vault_pwd_file: this_path = os.path.realpath( os.path.expanduser(vault_pwd_file)) if os.path.exists(this_path): mode = self.loader.is_executable(this_path) result = read_file(this_path, mode=mode, sprfmt=b'\r\n', outfmt='bytes') if result[0]: vault_password = result[1] else: vault_password = None else: vault_password = None else: vault_password = None if vault_password: b_vault_password = string2bytes(vault_password) self.loader.set_vault_password(b_vault_password) self.vault_password = vault_password else: self.vault_password = None def _parse_options(self): ''' 获取options字典 ''' keys_list = [] values_list = [] for key, value in self.options_dict.items(): keys_list.append(key) values_list.append(value) Options = namedtuple('Options', keys_list) self.options = Options._make(values_list) def _show_protectfield(self): protectfield_list = [ 'ask_pass', 'ask_su_pass', 'ask_sudo_pass', 'ask_vault_pass', 'become_ask_pass', 'new_vault_password_file', 'vault_password_file', 'private_key_file', ] log_options = {} for field in self.options_dict: if field in protectfield_list: log_options[field] = '***hidden***' else: log_options[field] = self.options_dict[field] return log_options
def main(): variable_manager = VariableManager() loader = DataLoader() passwd = None become_passwd = None display = Display() parser = argparse.ArgumentParser() prepare_parser(parser) args = parser.parse_args() if args.askpass: passwd = getpass.getpass("SSH password:"******"BECOME password " "[defaults to SSH password]:") if become_passwd == "": become_passwd = passwd options = Options( connection=args.connection, module_path=args.module_path, forks=args.forks, become=args.become, become_method=args.become_method, become_user=args.become_user, check=args.check, remote_user=args.remote_user, private_key_file=args.private_key_file, ssh_common_args=None, sftp_extra_args=None, scp_extra_args=None, ssh_extra_args=None, verbosity=args.verbose ) display.verbosity = args.verbose cb = CallbackModule(display) if not os.path.isfile(args.inventory): exit("ERROR! Can't open host list") inventory = Inventory( loader=loader, variable_manager=variable_manager, host_list=args.inventory ) inventory.subset(args.subset) play_source = dict( name="Assign roles %s" % args.roles, hosts='all', gather_facts='no', roles=args.roles) variable_manager.set_inventory(inventory) play = Play().load( play_source, variable_manager=variable_manager, loader=loader ) tqm = None try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords={'conn_pass': passwd, 'become_pass': become_passwd}, stdout_callback=cb ) tqm.run(play) finally: if tqm is not None: tqm.cleanup()
class Runner(object): def __init__(self, inventory_filename, playbook, extra_vars, verbosity=0, subset=constants.DEFAULT_SUBSET): if not os.path.exists(inventory_filename): raise Exception( "Cannot find inventory_filename: {}. Current dir: {}".format( inventory_filename, os.getcwd())) if not os.path.exists(playbook): raise Exception( "Cannot find playbook: {}. Current dir: {}".format( playbook, os.getcwd())) self.options = Options() self.options.verbosity = verbosity self.options.connection = 'ssh' # Need a connection type "smart" or "ssh" self.options.subset = subset # Propagate defaults from ANSIBLE_CONFIG into options self.options.module_path = constants.DEFAULT_MODULE_PATH self.options.forks = constants.DEFAULT_FORKS self.options.ask_vault_pass = constants.DEFAULT_ASK_VAULT_PASS self.options.vault_password_files = [ constants.DEFAULT_VAULT_PASSWORD_FILE ] self.options.sudo = constants.DEFAULT_SUDO self.options.become = constants.DEFAULT_BECOME self.options.become_method = constants.DEFAULT_BECOME_METHOD self.options.become_user = constants.DEFAULT_BECOME_USER self.options.ask_sudo_pass = constants.DEFAULT_ASK_SUDO_PASS self.options.ask_su_pass = constants.DEFAULT_ASK_SU_PASS self.options.ask_pass = constants.DEFAULT_ASK_PASS self.options.private_key_file = constants.DEFAULT_PRIVATE_KEY_FILE self.options.remote_user = constants.DEFAULT_REMOTE_USER self.options.timeout = constants.DEFAULT_TIMEOUT self.options.poll_interval = constants.DEFAULT_POLL_INTERVAL self.options.force_handlers = constants.DEFAULT_FORCE_HANDLERS # Set global verbosity self.display = Display() self.display.verbosity = self.options.verbosity # Executor appears to have it's own # verbosity object/setting as well playbook_executor.verbosity = self.options.verbosity # Become Pass Needed if not logging in as user root passwords = {} # Gets data from YAML/JSON files self.loader = DataLoader() # All the variables from all the various places self.variable_manager = VariableManager() self.variable_manager.extra_vars = extra_vars # WARNING: this is a dirty hack to avoid a situation where creating multiple # instance of this Runner each with it's own Inventory instance was creating # a situation where we ended up with different UUID's for hosts and comparisons # were failing (see http://bit.ly/1qKmV3x) ansible.inventory.HOSTS_PATTERNS_CACHE = {} # Set inventory, using most of above objects self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=inventory_filename) self.inventory.subset(self.options.subset) self.variable_manager.set_inventory(self.inventory) # Setup playbook executor, but don't run until run() called logger.info("Running playbook: {}".format(playbook)) self.pbex = playbook_executor.PlaybookExecutor( playbooks=[playbook], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=passwords) def run(self): # Results of PlaybookExecutor self.pbex.run() stats = self.pbex._tqm._stats return stats
class Runner(object): def __init__( self, playbook, display, hosts='hosts', options={}, passwords={}, vault_pass=None): # Set options self.options = Options() for k, v in options.iteritems(): setattr(self.options, k, v) # Set global verbosity self.display = display self.display.verbosity = self.options.verbosity # Executor has its own verbosity setting playbook_executor.verbosity = self.options.verbosity # Gets data from YAML/JSON files self.loader = DataLoader() # Set vault password if vault_pass is not None: self.loader.set_vault_password(vault_pass) elif 'VAULT_PASS' in os.environ: self.loader.set_vault_password(os.environ['VAULT_PASS']) # All the variables from all the various places self.variable_manager = VariableManager() if self.options.python_interpreter is not None: self.variable_manager.extra_vars = { 'ansible_python_interpreter': self.options.python_interpreter } # Set inventory, using most of above objects self.inventory = Inventory( loader=self.loader, variable_manager=self.variable_manager, host_list=hosts) if len(self.inventory.list_hosts()) == 0: # Empty inventory self.display.error("Provided hosts list is empty.") sys.exit(1) self.inventory.subset(self.options.subset) if len(self.inventory.list_hosts()) == 0: # Invalid limit self.display.error("Specified limit does not match any hosts.") sys.exit(1) self.variable_manager.set_inventory(self.inventory) # import pdb; pdb.set_trace() # Setup playbook executor, but don't run until run() called self.pbex = playbook_executor.PlaybookExecutor( playbooks=[playbook], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=passwords) def run(self): # Run Playbook and get stats self.pbex.run() stats = self.pbex._tqm._stats # Test if success for record_logs run_success = True hosts = sorted(stats.processed.keys()) for h in hosts: t = stats.summarize(h) if t['unreachable'] > 0 or t['failures'] > 0: run_success = False # Dirty hack to send callback to save logs with data we want # Note that function "record_logs" is one I created and put into # the playbook callback file # import pdb; pdb.set_trace() self.pbex._tqm.send_callback('record_logs') # os.remove(self.hosts.name) return stats
def run_playbook(playbook, form_data, runner): # Mark play as started runner.pid = os.getpid() runner.status = 'started' runner.save() # Create ansible default objects variable_manager = VariableManager() loader = DataLoader() inventory = Inventory(loader=loader, variable_manager=variable_manager) variable_manager.set_inventory(inventory) # Set inventory subset if available: if 'subset' in form_data: inventory.subset(form_data['subset']) # Add host list to runner object host_list = inventory.get_hosts(pattern=runner.hosts) # Create password dictionary passwords = {'conn_pass': form_data['remote_pass'], 'become_pass': form_data['become_pass']} # Set sudo user become_user = c.DEFAULT_BECOME_USER if 'sudo_user' in form_data: become_user = form_data['sudo_user'] # Create ansible options tuple options = AnsibleOptions(connection='paramiko', module_path=c.DEFAULT_MODULE_PATH, forks=c.DEFAULT_FORKS, remote_user=form_data['username'], private_key_file=form_data['rsa_key'], ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=form_data['become'], become_method=c.DEFAULT_BECOME_METHOD, become_user=become_user, verbosity=None, check=form_data['check'], tags=form_data['tags'], skip_tags=None) # Create ansible play object play = Play().load(playbook, variable_manager=variable_manager, loader=loader) # Execute play tqm = None if True: # try: tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, passwords=passwords, loader=loader, options=options, # stdout_callback=TestCallback() stdout_callback=AdHocCallback(runner, host_list)) tqm.run(play) # finally: if tqm is not None: tqm.cleanup() runner.status = 'finished' else: runner.status = 'failed' runner.message = 'tqm object in not None' runner.save()
class ConsoleCLI(CLI, cmd.Cmd): modules = [] def __init__(self, args): super(ConsoleCLI, self).__init__(args) self.intro = 'Welcome to the ansible console.\nType help or ? to list commands.\n' self.groups = [] self.hosts = [] self.pattern = None self.variable_manager = None self.loader = None self.passwords = dict() self.modules = None cmd.Cmd.__init__(self) def parse(self): self.parser = CLI.base_parser( usage='%prog <host-pattern> [options]', runas_opts=True, inventory_opts=True, connect_opts=True, check_opts=True, vault_opts=True, fork_opts=True, module_opts=True, ) # options unique to shell self.parser.add_option( '--step', dest='step', action='store_true', help="one-step-at-a-time: confirm each task before running") self.parser.set_defaults(cwd='*') super(AdHocCLI, self).parse() display.verbosity = self.options.verbosity self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True) def get_names(self): return dir(self) def cmdloop(self): try: cmd.Cmd.cmdloop(self) except KeyboardInterrupt: self.do_exit(self) def set_prompt(self): login_user = self.options.remote_user or getpass.getuser() self.selected = self.inventory.list_hosts(self.options.cwd) prompt = "%s@%s (%d)[f:%s]" % (login_user, self.options.cwd, len(self.selected), self.options.forks) if self.options.become and self.options.become_user in [None, 'root']: prompt += "# " color = C.COLOR_ERROR else: prompt += "$ " color = C.COLOR_HIGHLIGHT self.prompt = stringc(prompt, color) def list_modules(self): modules = set() if self.options.module_path is not None: for i in self.options.module_path.split(os.pathsep): module_loader.add_directory(i) module_paths = module_loader._get_paths() for path in module_paths: if path is not None: modules.update(self._find_modules_in_path(path)) return modules def _find_modules_in_path(self, path): if os.path.isdir(path): for module in os.listdir(path): if module.startswith('.'): continue elif os.path.isdir(module): self._find_modules_in_path(module) elif module.startswith('__'): continue elif any(module.endswith(x) for x in C.BLACKLIST_EXTS): continue elif module in C.IGNORE_FILES: continue elif module.startswith('_'): fullpath = '/'.join([path, module]) if os.path.islink(fullpath): # avoids aliases continue module = module.replace('_', '', 1) module = os.path.splitext(module)[0] # removes the extension yield module def default(self, arg, forceshell=False): """ actually runs modules """ if arg.startswith("#"): return False if not self.options.cwd: display.error("No host found") return False if arg.split()[0] in self.modules: module = arg.split()[0] module_args = ' '.join(arg.split()[1:]) else: module = 'shell' module_args = arg if forceshell is True: module = 'shell' module_args = arg self.options.module_name = module result = None try: check_raw = self.options.module_name in ('command', 'shell', 'script', 'raw') play_ds = dict( name="Ansible Shell", hosts=self.options.cwd, gather_facts='no', tasks=[ dict(action=dict(module=module, args=parse_kv(module_args, check_raw=check_raw))) ]) play = Play().load(play_ds, variable_manager=self.variable_manager, loader=self.loader) except Exception as e: display.error(u"Unable to build command: %s" % to_text(e)) return False try: cb = 'minimal' # FIXME: make callbacks configurable # now create a task queue manager to execute the play self._tqm = None try: self._tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=cb, run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS, run_tree=False, ) result = self._tqm.run(play) finally: if self._tqm: self._tqm.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() if result is None: display.error("No hosts found") return False except KeyboardInterrupt: display.error('User interrupted execution') return False except Exception as e: display.error(to_text(e)) # FIXME: add traceback in very very verbose mode return False def emptyline(self): return def do_shell(self, arg): """ You can run shell commands through the shell module. eg.: shell ps uax | grep java | wc -l shell killall python shell halt -n You can use the ! to force the shell module. eg.: !ps aux | grep java | wc -l """ self.default(arg, True) def do_forks(self, arg): """Set the number of forks""" if not arg: display.display('Usage: forks <number>') return self.options.forks = int(arg) self.set_prompt() do_serial = do_forks def do_verbosity(self, arg): """Set verbosity level""" if not arg: display.display('Usage: verbosity <number>') else: display.verbosity = int(arg) display.v('verbosity level set to %s' % arg) def do_cd(self, arg): """ Change active host/group. You can use hosts patterns as well eg.: cd webservers cd webservers:dbservers cd webservers:!phoenix cd webservers:&staging cd webservers:dbservers:&staging:!phoenix """ if not arg: self.options.cwd = '*' elif arg == '..': try: self.options.cwd = self.inventory.groups_for_host( self.options.cwd)[1].name except Exception: self.options.cwd = '' elif arg in '/*': self.options.cwd = 'all' elif self.inventory.get_hosts(arg): self.options.cwd = arg else: display.display("no host matched") self.set_prompt() def do_list(self, arg): """List the hosts in the current group""" if arg == 'groups': for group in self.groups: display.display(group) else: for host in self.selected: display.display(host.name) def do_become(self, arg): """Toggle whether plays run with become""" if arg: self.options.become = C.mk_boolean(arg) display.v("become changed to %s" % self.options.become) self.set_prompt() else: display.display("Please specify become value, e.g. `become yes`") def do_remote_user(self, arg): """Given a username, set the remote user plays are run by""" if arg: self.options.remote_user = arg self.set_prompt() else: display.display( "Please specify a remote user, e.g. `remote_user root`") def do_become_user(self, arg): """Given a username, set the user that plays are run by when using become""" if arg: self.options.become_user = arg else: display.display( "Please specify a user, e.g. `become_user jenkins`") display.v("Current user is %s" % self.options.become_user) self.set_prompt() def do_become_method(self, arg): """Given a become_method, set the privilege escalation method when using become""" if arg: self.options.become_method = arg display.v("become_method changed to %s" % self.options.become_method) else: display.display( "Please specify a become_method, e.g. `become_method su`") def do_check(self, arg): """Toggle whether plays run with check mode""" if arg: self.options.check = C.mk_boolean(arg) display.v("check mode changed to %s" % self.options.check) else: display.display( "Please specify check mode value, e.g. `check yes`") def do_diff(self, arg): """Toggle whether plays run with diff""" if arg: self.options.diff = C.mk_boolean(arg) display.v("diff mode changed to %s" % self.options.diff) else: display.display("Please specify a diff value , e.g. `diff yes`") def do_exit(self, args): """Exits from the console""" sys.stdout.write('\n') return -1 do_EOF = do_exit def helpdefault(self, module_name): if module_name in self.modules: in_path = module_loader.find_plugin(module_name) if in_path: oc, a, _ = module_docs.get_docstring(in_path) if oc: display.display(oc['short_description']) display.display('Parameters:') for opt in oc['options'].keys(): display.display(' ' + stringc(opt, C.COLOR_HIGHLIGHT) + ' ' + oc['options'][opt]['description'][0]) else: display.error('No documentation found for %s.' % module_name) else: display.error( '%s is not a valid command, use ? to list all valid commands.' % module_name) def complete_cd(self, text, line, begidx, endidx): mline = line.partition(' ')[2] offs = len(mline) - len(text) if self.options.cwd in ('all', '*', '\\'): completions = self.hosts + self.groups else: completions = [ x.name for x in self.inventory.list_hosts(self.options.cwd) ] return [ to_native(s)[offs:] for s in completions if to_native(s).startswith(to_native(mline)) ] def completedefault(self, text, line, begidx, endidx): if line.split()[0] in self.modules: mline = line.split(' ')[-1] offs = len(mline) - len(text) completions = self.module_args(line.split()[0]) return [s[offs:] + '=' for s in completions if s.startswith(mline)] def module_args(self, module_name): in_path = module_loader.find_plugin(module_name) oc, a, _ = module_docs.get_docstring(in_path) return oc['options'].keys() def run(self): super(ConsoleCLI, self).run() sshpass = None becomepass = None vault_pass = None # hosts if len(self.args) != 1: self.pattern = 'all' else: self.pattern = self.args[0] self.options.cwd = self.pattern # dynamically add modules as commands self.modules = self.list_modules() for module in self.modules: setattr( self, 'do_' + module, lambda arg, module=module: self.default(module + ' ' + arg)) setattr(self, 'help_' + module, lambda module=module: self.helpdefault(module)) self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() self.passwords = {'conn_pass': sshpass, 'become_pass': becomepass} self.loader = DataLoader() if self.options.vault_password_file: # read vault_pass from a file vault_pass = CLI.read_vault_password_file( self.options.vault_password_file, loader=self.loader) self.loader.set_vault_password(vault_pass) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords()[0] self.loader.set_vault_password(vault_pass) self.variable_manager = VariableManager() self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=self.options.inventory) self.variable_manager.set_inventory(self.inventory) no_hosts = False if len(self.inventory.list_hosts()) == 0: # Empty inventory no_hosts = True display.warning( "provided hosts list is empty, only localhost is available") self.inventory.subset(self.options.subset) hosts = self.inventory.list_hosts(self.pattern) if len(hosts) == 0 and not no_hosts: raise AnsibleError( "Specified hosts and/or --limit does not match any hosts") self.groups = self.inventory.list_groups() self.hosts = [x.name for x in hosts] # This hack is to work around readline issues on a mac: # http://stackoverflow.com/a/7116997/541202 if 'libedit' in readline.__doc__: readline.parse_and_bind("bind ^I rl_complete") else: readline.parse_and_bind("tab: complete") histfile = os.path.join(os.path.expanduser("~"), ".ansible-console_history") try: readline.read_history_file(histfile) except IOError: pass atexit.register(readline.write_history_file, histfile) self.set_prompt() self.cmdloop()
class ConsoleCLI(CLI, cmd.Cmd): modules = [] def __init__(self, args): super(ConsoleCLI, self).__init__(args) self.intro = 'Welcome to the ansible console.\nType help or ? to list commands.\n' self.groups = [] self.hosts = [] self.pattern = None self.variable_manager = None self.loader = None self.passwords = dict() self.modules = None cmd.Cmd.__init__(self) def parse(self): self.parser = CLI.base_parser( usage='%prog <host-pattern> [options]', runas_opts=True, inventory_opts=True, connect_opts=True, check_opts=True, vault_opts=True, fork_opts=True, module_opts=True, ) # options unique to shell self.parser.add_option('--step', dest='step', action='store_true', help="one-step-at-a-time: confirm each task before running") self.parser.set_defaults(cwd='*') self.options, self.args = self.parser.parse_args(self.args[1:]) display.verbosity = self.options.verbosity self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True) return True def get_names(self): return dir(self) def cmdloop(self): try: cmd.Cmd.cmdloop(self) except KeyboardInterrupt: self.do_exit(self) def set_prompt(self): login_user = self.options.remote_user or getpass.getuser() self.selected = self.inventory.list_hosts(self.options.cwd) prompt = "%s@%s (%d)[f:%s]" % (login_user, self.options.cwd, len(self.selected), self.options.forks) if self.options.become and self.options.become_user in [None, 'root']: prompt += "# " color = C.COLOR_ERROR else: prompt += "$ " color = C.COLOR_HIGHLIGHT self.prompt = stringc(prompt, color) def list_modules(self): modules = set() if self.options.module_path is not None: for i in self.options.module_path.split(os.pathsep): module_loader.add_directory(i) module_paths = module_loader._get_paths() for path in module_paths: if path is not None: modules.update(self._find_modules_in_path(path)) return modules def _find_modules_in_path(self, path): if os.path.isdir(path): for module in os.listdir(path): if module.startswith('.'): continue elif os.path.isdir(module): self._find_modules_in_path(module) elif module.startswith('__'): continue elif any(module.endswith(x) for x in C.BLACKLIST_EXTS): continue elif module in C.IGNORE_FILES: continue elif module.startswith('_'): fullpath = '/'.join([path,module]) if os.path.islink(fullpath): # avoids aliases continue module = module.replace('_', '', 1) module = os.path.splitext(module)[0] # removes the extension yield module def default(self, arg, forceshell=False): """ actually runs modules """ if arg.startswith("#"): return False if not self.options.cwd: display.error("No host found") return False if arg.split()[0] in self.modules: module = arg.split()[0] module_args = ' '.join(arg.split()[1:]) else: module = 'shell' module_args = arg if forceshell is True: module = 'shell' module_args = arg self.options.module_name = module result = None try: check_raw = self.options.module_name in ('command', 'shell', 'script', 'raw') play_ds = dict( name = "Ansible Shell", hosts = self.options.cwd, gather_facts = 'no', tasks = [ dict(action=dict(module=module, args=parse_kv(module_args, check_raw=check_raw)))] ) play = Play().load(play_ds, variable_manager=self.variable_manager, loader=self.loader) except Exception as e: display.error(u"Unable to build command: %s" % to_text(e)) return False try: cb = 'minimal' # FIXME: make callbacks configurable # now create a task queue manager to execute the play self._tqm = None try: self._tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=cb, run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS, run_tree=False, ) result = self._tqm.run(play) finally: if self._tqm: self._tqm.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() if result is None: display.error("No hosts found") return False except KeyboardInterrupt: display.error('User interrupted execution') return False except Exception as e: display.error(to_text(e)) # FIXME: add traceback in very very verbose mode return False def emptyline(self): return def do_shell(self, arg): """ You can run shell commands through the shell module. eg.: shell ps uax | grep java | wc -l shell killall python shell halt -n You can use the ! to force the shell module. eg.: !ps aux | grep java | wc -l """ self.default(arg, True) def do_forks(self, arg): """Set the number of forks""" if not arg: display.display('Usage: forks <number>') return self.options.forks = int(arg) self.set_prompt() do_serial = do_forks def do_verbosity(self, arg): """Set verbosity level""" if not arg: display.display('Usage: verbosity <number>') else: display.verbosity = int(arg) display.v('verbosity level set to %s' % arg) def do_cd(self, arg): """ Change active host/group. You can use hosts patterns as well eg.: cd webservers cd webservers:dbservers cd webservers:!phoenix cd webservers:&staging cd webservers:dbservers:&staging:!phoenix """ if not arg: self.options.cwd = '*' elif arg == '..': try: self.options.cwd = self.inventory.groups_for_host(self.options.cwd)[1].name except Exception: self.options.cwd = '' elif arg in '/*': self.options.cwd = 'all' elif self.inventory.get_hosts(arg): self.options.cwd = arg else: display.display("no host matched") self.set_prompt() def do_list(self, arg): """List the hosts in the current group""" if arg == 'groups': for group in self.groups: display.display(group) else: for host in self.selected: display.display(host.name) def do_become(self, arg): """Toggle whether plays run with become""" if arg: self.options.become = C.mk_boolean(arg) display.v("become changed to %s" % self.options.become) self.set_prompt() else: display.display("Please specify become value, e.g. `become yes`") def do_remote_user(self, arg): """Given a username, set the remote user plays are run by""" if arg: self.options.remote_user = arg self.set_prompt() else: display.display("Please specify a remote user, e.g. `remote_user root`") def do_become_user(self, arg): """Given a username, set the user that plays are run by when using become""" if arg: self.options.become_user = arg else: display.display("Please specify a user, e.g. `become_user jenkins`") display.v("Current user is %s" % self.options.become_user) self.set_prompt() def do_become_method(self, arg): """Given a become_method, set the privilege escalation method when using become""" if arg: self.options.become_method = arg display.v("become_method changed to %s" % self.options.become_method) else: display.display("Please specify a become_method, e.g. `become_method su`") def do_check(self, arg): """Toggle whether plays run with check mode""" if arg: self.options.check = C.mk_boolean(arg) display.v("check mode changed to %s" % self.options.check) else: display.display("Please specify check mode value, e.g. `check yes`") def do_diff(self, arg): """Toggle whether plays run with diff""" if arg: self.options.diff = C.mk_boolean(arg) display.v("diff mode changed to %s" % self.options.diff) else: display.display("Please specify a diff value , e.g. `diff yes`") def do_exit(self, args): """Exits from the console""" sys.stdout.write('\n') return -1 do_EOF = do_exit def helpdefault(self, module_name): if module_name in self.modules: in_path = module_loader.find_plugin(module_name) if in_path: oc, a, _ = module_docs.get_docstring(in_path) if oc: display.display(oc['short_description']) display.display('Parameters:') for opt in oc['options'].keys(): display.display(' ' + stringc(opt, C.COLOR_HIGHLIGHT) + ' ' + oc['options'][opt]['description'][0]) else: display.error('No documentation found for %s.' % module_name) else: display.error('%s is not a valid command, use ? to list all valid commands.' % module_name) def complete_cd(self, text, line, begidx, endidx): mline = line.partition(' ')[2] offs = len(mline) - len(text) if self.options.cwd in ('all','*','\\'): completions = self.hosts + self.groups else: completions = [x.name for x in self.inventory.list_hosts(self.options.cwd)] return [to_native(s)[offs:] for s in completions if to_native(s).startswith(to_native(mline))] def completedefault(self, text, line, begidx, endidx): if line.split()[0] in self.modules: mline = line.split(' ')[-1] offs = len(mline) - len(text) completions = self.module_args(line.split()[0]) return [s[offs:] + '=' for s in completions if s.startswith(mline)] def module_args(self, module_name): in_path = module_loader.find_plugin(module_name) oc, a, _ = module_docs.get_docstring(in_path) return oc['options'].keys() def run(self): super(ConsoleCLI, self).run() sshpass = None becomepass = None vault_pass = None # hosts if len(self.args) != 1: self.pattern = 'all' else: self.pattern = self.args[0] self.options.cwd = self.pattern # dynamically add modules as commands self.modules = self.list_modules() for module in self.modules: setattr(self, 'do_' + module, lambda arg, module=module: self.default(module + ' ' + arg)) setattr(self, 'help_' + module, lambda module=module: self.helpdefault(module)) self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() self.passwords = { 'conn_pass': sshpass, 'become_pass': becomepass } self.loader = DataLoader() if self.options.vault_password_file: # read vault_pass from a file vault_pass = CLI.read_vault_password_file(self.options.vault_password_file, loader=self.loader) self.loader.set_vault_password(vault_pass) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords()[0] self.loader.set_vault_password(vault_pass) self.variable_manager = VariableManager() self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=self.options.inventory) self.variable_manager.set_inventory(self.inventory) no_hosts = False if len(self.inventory.list_hosts()) == 0: # Empty inventory no_hosts = True display.warning("provided hosts list is empty, only localhost is available") self.inventory.subset(self.options.subset) hosts = self.inventory.list_hosts(self.pattern) if len(hosts) == 0 and not no_hosts: raise AnsibleError("Specified hosts and/or --limit does not match any hosts") self.groups = self.inventory.list_groups() self.hosts = [x.name for x in hosts] # This hack is to work around readline issues on a mac: # http://stackoverflow.com/a/7116997/541202 if 'libedit' in readline.__doc__: readline.parse_and_bind("bind ^I rl_complete") else: readline.parse_and_bind("tab: complete") histfile = os.path.join(os.path.expanduser("~"), ".ansible-console_history") try: readline.read_history_file(histfile) except IOError: pass atexit.register(readline.write_history_file, histfile) self.set_prompt() self.cmdloop()
def run(self): super(PlaybookCLI, self).run() # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None vault_pass = None passwords = {} # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor for playbook in self.args: if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError( "the playbook: %s does not appear to be a file" % playbook) # don't deal with privilege escalation or passwords when we don't need to if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax: self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() passwords = {'conn_pass': sshpass, 'become_pass': becomepass} loader = DataLoader() if self.options.vault_password_file: # read vault_pass from a file vault_pass = CLI.read_vault_password_file( self.options.vault_password_file, loader=loader) loader.set_vault_password(vault_pass) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords()[0] loader.set_vault_password(vault_pass) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options) variable_manager.options_vars = load_options_vars(self.options) # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory display.warning( "provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # flush fact cache if requested if self.options.flush_cache: for host in inventory.list_hosts(): variable_manager.clear_facts(host) # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor(playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.options, passwords=passwords) results = pbex.run() if isinstance(results, list): for p in results: display.display('\nplaybook: %s' % p['playbook']) for idx, play in enumerate(p['plays']): msg = "\n play #%d (%s): %s" % (idx + 1, ','.join( play.hosts), play.name) mytags = set(play.tags) msg += '\tTAGS: [%s]' % (','.join(mytags)) if self.options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % ( play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host display.display(msg) all_tags = set() if self.options.listtags or self.options.listtasks: taskmsg = '' if self.options.listtasks: taskmsg = ' tasks:\n' def _process_block(b): taskmsg = '' for task in b.block: if isinstance(task, Block): taskmsg += _process_block(task) else: if task.action == 'meta': continue all_tags.update(task.tags) if self.options.listtasks: cur_tags = list( mytags.union(set(task.tags))) cur_tags.sort() if task.name: taskmsg += " %s" % task.get_name( ) else: taskmsg += " %s" % task.action taskmsg += "\tTAGS: [%s]\n" % ', '.join( cur_tags) return taskmsg all_vars = variable_manager.get_vars(loader=loader, play=play) play_context = PlayContext(play=play, options=self.options) for block in play.compile(): block = block.filter_tagged_tasks( play_context, all_vars) if not block.has_tasks(): continue taskmsg += _process_block(block) if self.options.listtags: cur_tags = list(mytags.union(all_tags)) cur_tags.sort() taskmsg += " TASK TAGS: [%s]\n" % ', '.join( cur_tags) display.display(taskmsg) return 0 else: return results
def default(self): verbose = self.app.pargs.verbose init(autoreset=True) if len(self.app.pargs.extra_arguments) == 0: self.app.args.print_help() print(Fore.RED + 'Error! You must specify a playbook file to run') sys.exit(1) if str(self.app.pargs.become_method).upper() not in [ 'SUDO', 'SU', 'PBRUN', 'PFEXEC', 'DOAS', 'DZDO', 'KSU', 'RUNAS' ]: print( Fore.RED + 'Error! Become method must be one of sudo, su, pbrun, pfexec, doas, dzdo, ksu or runas.' ) sys.exit(1) #if len(self.app.pargs.extra_arguments) > 0: playbook_path = self.app.pargs.extra_arguments[0] if len( self.app.pargs.extra_arguments) > 0 else "site.yml" if not os.path.isfile(playbook_path): print(Fore.RED + 'Error! The playbook file does not exist') sys.exit(1) inventory_path = self.app.pargs.inventory if not os.path.isfile(inventory_path): print(Fore.RED + 'Error! The inventory file does not exist.') sys.exit(1) # Most of the code from here down is straight copy & paste from ansible source code, # with a few tweaks/hacks to clean up variables that we don't want to emit in the generated # YAML. loader = DataLoader() pb_cli = PlaybookCLI(sys.argv[1:]) pb_cli.parse() # !!!!! WARNING: THESE WILL BE INCLUDED IN THE GENERATED YAML FILE !!!!! (ssh_pass, become_pass) = pb_cli.ask_passwords() passwords = {'conn_pass': ssh_pass, 'become_pass': become_pass} vault_pass = None if self.app.pargs.ask_vault_pass: vault_pass = pb_cli.ask_vault_passwords() else: vault_pass = pb_cli.read_vault_password_file( self.app.pargs.vault_password_file, loader) if vault_pass is not None: loader.set_vault_password(vault_pass) # create the inventory, and filter it based on the subset specified (if any) host_list = self.app.pargs.inventory if self.app.pargs.inventory else constants.DEFAULT_HOST_LIST # FIXME: This should parse any arguments provided via -e or --extra-vars. Currently it seems # to parse the argument value wrongly and returns # '_raw_params': '<last character in variable>'. This prevents the ability to use # --extra-vars when executing plays. variable_manager = VariableManager() options = Options( verbosity=self.app.pargs.verbose, inventory=self.app.pargs.inventory, subset=self.app.pargs.limit, extra_vars=[self.app.pargs.extra_vars], forks=self.app.pargs.forks, ask_vault_pass=self.app.pargs.ask_vault_pass, vault_password_files=self.app.pargs.vault_password_file, tags=self.app.pargs.tags, skip_tags=self.app.pargs.skip_tags, become=self.app.pargs.become, become_method=self.app.pargs.become_method, become_user=self.app.pargs.become_user, become_ask_pass=self.app.pargs.ask_become_pass, ask_pass=self.app.pargs.ask_pass, private_key_file=self.app.pargs.private_key, remote_user=self.app.pargs.user, connection=self.app.pargs.connection, timeout=self.app.pargs.timeout, ssh_common_args=self.app.pargs.ssh_common_args, sftp_extra_args=self.app.pargs.sftp_extra_args, ssh_extra_args=self.app.pargs.ssh_extra_args, scp_extra_args=self.app.pargs.scp_extra_args, flush_cache=self.app.pargs.flush_cache, module_path=self.app.pargs.module_path) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=host_list) variable_manager.extra_vars = load_extra_vars(loader=loader, options=options) #variable_manager.options_vars = load_options_vars(options) if self.app.pargs.flush_cache: inventory.refresh_inventory() no_hosts = False if len(inventory.list_hosts()) == 0: print( Fore.YELLOW + "Warning! Provided hosts list is empty, only localhost is available." ) no_hosts = True # FIXME: Limit is currently ignored. inventory.subset(self.app.pargs.limit) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit print(Fore.RED + "Error! Specified --limit does not match any hosts.") sys.exit(1) play_data = loader.load_from_file(playbook_path) host_list = inventory.get_hosts( pattern=self.app.pargs.limit ) if self.app.pargs.limit else inventory.get_hosts() playbook = Playbook(loader=loader).load( playbook_path, variable_manager=variable_manager, loader=loader) pbex = PlaybookExecutor(playbooks=playbook.get_plays(), inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords) # Ansible variables matching these strings will be excluded from the generated yaml content. ignored_elements = [ 'ansible_playbook_python', 'ansible_version', 'group_names', 'inventory_hostname', 'inventory_hostname_short', 'omit', 'playbook_dir', 'role_names' ] json_data = {} for host in host_list: host_vars = host.get_vars() host_name = host_vars[ 'ansible_host'] if 'ansible_host' in host_vars.keys( ) else host.get_name() for play in playbook.get_plays(): loader.set_vault_password(vault_pass) all_vars = variable_manager.get_vars(loader=loader, play=play, host=host) json_data[host_name] = all_vars['vars'] json_data[host_name]['ansible_groups'] = all_vars[ 'group_names'] json_data[host_name]['ansible_roles'] = all_vars['role_names'] for elem in ignored_elements: del json_data['{}'.format(host)][elem] json_data[host_name][ 'ansible_become_user'] = self.app.pargs.become_user if passwords['become_pass'] is not None: json_data[host_name]['ansible_become_pass'] = passwords[ 'become_pass'] json_data[host_name]['ansible_become'] = self.app.pargs.become json_data[host_name][ 'ansible_become_method'] = self.app.pargs.become_method if self.app.pargs.ssh_extra_args: json_data[host_name][ 'ansible_ssh_extra_args'] = self.app.pargs.ssh_extra_args if self.app.pargs.scp_extra_args: json_data[host_name][ 'ansible_scp_extra_args'] = self.app.pargs.scp_extra_args if self.app.pargs.sftp_extra_args: json_data[host_name][ 'ansible_sftp_extra_args'] = self.app.pargs.sftp_extra_args if self.app.pargs.ssh_common_args: json_data[host_name][ 'ansible_ssh_common_args'] = self.app.pargs.ssh_common_args json_data[host_name][ 'ansible_connection_timeout'] = self.app.pargs.timeout json_data[host_name][ 'ansible_connection_method'] = self.app.pargs.connection if self.app.pargs.private_key: json_data[host_name][ 'ansible_private_key'] = self.app.pargs.private_key json_data[host_name][ 'ansible_ask_pass'] = self.app.pargs.ask_pass if self.app.pargs.limit: json_data[host_name][ 'ansible_limit'] = self.app.pargs.limit # FIXME: Extra vars needs to be processed by Ansible instead of dumping them # here as a "dumb" string. if self.app.pargs.extra_vars: json_data[host_name][ 'ansible_extra_vars'] = self.app.pargs.extra_vars for key, value in json_data[host_name].iteritems(): if type(value) is AnsibleVaultEncryptedUnicode: json_data[host_name][key] = str(value) # Convert the processed python dictionary to a valid json string json_obj = json.dumps(json_data) # Take the json string, and convert it to a valid yaml string yml = YAML(typ="safe", pure=True) yml.default_flow_style = False yml_obj = yml.load(json_obj) if self.app.pargs.output is None: yml.dump(yml_obj, sys.stdout) else: with open(self.app.pargs.output, 'w') as outfile: yml.dump(yml_obj, outfile) print(Fore.GREEN + "Ansible variable dictionary written to {}".format( self.app.pargs.output)) sys.exit(1)