def run_module(self, hosts='localhost', rules=[{'module': 'setup'}]): ''' rules=[ {'module': 'shell', 'args': 'echo "ok"', 'register': 'echo_ok'}, {'module': 'debug', 'args': {'msg': '{{echo_ok.stdout}}'}} ] ''' tasks = [] for rule in rules: if 'register' in rule: register = rule.pop('register') tasks.append(dict(dict(action=rule), register=register)) play_source = dict( name = "Ansible Play", hosts = hosts, gather_facts = 'no', tasks = tasks ) results_callback = ResultCallback() play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) qm = None try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=results_callback, ) tqm.run(play) return results_callback finally: if tqm is not None: tqm.cleanup()
def run(self): # create play with tasks play_source = dict( name = "Ansible Play", hosts = self.host_list, #hosts = 'localhost', gather_facts = 'no', tasks = [ dict(action=dict(module='shell', args='ls')), #dict(action=dict(module='shell', args='ls'), register='shell_out'), #dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) # actually run it tqm = None try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self.results_callback, # Use our custom callback instead of the ``default`` callback plugin ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup()
def run(self, play_data): """ paly_data = dict( name="Ansible Ad-Hoc", hosts=pattern, gather_facts=True, tasks=[dict(action=dict(module='service', args={'name': 'vsftpd', 'state': 'restarted'}), async=async, poll=poll)] ) """ self._prepare_run() play = Play().load(play_data, variable_manager=self.variable_manager, loader=self.loader) tqm = None try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self.cb, run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS, run_tree=False, ) result = tqm.run(play) return result finally: if tqm: tqm.cleanup()
def run_module(self, hosts, module_name, module_args): # create play with tasks play_source = dict( name="Ansible Play", hosts=hosts, gather_facts='no', tasks=[dict(action=dict(module=module_name, args=module_args))]) play = Play().load( play_source, variable_manager=self.variable_manager, loader=self.loader) self.results_callback = ModuleResultCallback() # actually run it tqm = None try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self. results_callback, # Use our custom callback instead of the ``default`` callback plugin ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup()
def run_command(cmd, host): callback_ob = callback_class() play_source = dict( name = "Ansible Play", hosts = host, gather_facts = 'no', tasks = [ dict(action=dict(module='shell', args=cmd), register='shell_out'), dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) task = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, stdout_callback=callback_ob, ) # redirecting stdout to grab the output from the task normal_stdout = sys.stdout sys.stdout = new_stdout = StringIO() result = task.run(play) sys.stdout = normal_stdout # import pdb; pdb.set_trace() return new_stdout.readlines()
def run(self, host_list, module_name, module_args,): """ run module from andible ad-hoc. module_name: ansible module_name module_args: ansible module args """ # create play with tasks play_source = dict( name="Ansible Play", hosts=host_list, gather_facts='no', tasks=[dict(action=dict(module=module_name, args=module_args))] ) play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) # actually run it tqm = None self.callback = ResultsCollector() try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, ) tqm._stdout_callback = self.callback result = tqm.run(play) finally: if tqm is not None: tqm.cleanup()
def my_runner(host_list,module_name,module_args): variable_manager.extra_vars={} # 增加外部变量 # 构建pb, 这里很有意思, 新版本运行ad-hoc或playbook都需要构建这样的pb, 只是最后调用play的类不一样 # :param name: 任务名,类似playbook中tasks中的name # :param hosts: playbook中的hosts # :param tasks: playbook中的tasks, 其实这就是playbook的语法, 因为tasks的值是个列表,因此可以写入多个task play_source = {"name":"Ansible Ad-Hoc","hosts":host_list,"gather_facts":"no","tasks":[{"action":{"module":module_name,"args":module_args}}]} play = Play().load(play_source,variable_manager=variable_manager,loader=loader) tqm = None # results_callback = call_json.CallbackModule() try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=None, stdout_callback='minimal', # stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin ) savedStdout = sys.stdout with open(File_PATH,'w+') as file: sys.stdout = file #标准输出重定向至文件 result = tqm.run(play) sys.stdout = savedStdout return result finally: if tqm is not None: tqm.cleanup()
def ansible_adhoc(ips): logger.info("ansible需要采集%d个IP" % (len(ips))) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=ips) # 根据 inventory 加载对应变量 variable_manager.set_inventory(inventory) # 增加外部变量 variable_manager.extra_vars = {"ansible_ssh_user": ansible_username, "ansible_ssh_pass": ansible_password} play_source = {"name": "Ansible Ad-Hoc", "hosts": ips, "gather_facts": "no", "tasks": [{"action": {"module": "setup", "args": ""}}]} 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=None, stdout_callback=resultcallback, run_tree=False, ) tqm.run(play) return ansible_facts_info finally: if tqm is not None: tqm.cleanup()
def runansible(self,host_list, task_list): play_source = dict( name = "Ansible Play", hosts = host_list, gather_facts = 'no', tasks = task_list ) play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self.callback, ) result = tqm.run(play) result_raw = {'success':{},'failed':{},'unreachable':{}} for host,result in self.callback.host_ok.items(): result_raw['success'][host] = result._result for host,result in self.callback.host_failed.items(): result_raw['failed'][host] = result._result for host,result in self.callback.host_unreachable.items(): result_raw['unreachable'][host] = result._result js = json.dumps(result_raw, sort_keys=False, indent=4) return js
def AnsibleTask(task_list,host_list,user): '''ansible python api 2.0''' loader = DataLoader() variable_manager = VariableManager() inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=host_list) variable_manager.set_inventory(inventory) task_dict = [] for i in task_list: task_dict.append({"action": {"module": i[0], "args": i[1] }}) variable_manager.extra_vars = {"ansible_ssh_user": user, "ansible_ssh_pass": ""} play_source = {"name" : "Ansible PlayBook Run", "hosts": host_list[0], "gather_facts": "no","tasks": task_dict} 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 = None, stdout_callback = 'minimal', run_tree = False, ) result = tqm.run(play) except Exception,e: result = e
def run_adhoc(): variable_manager.extra_vars = { "ansible_ssh_user": "******", "ansible_ssh_pass": "******" } # 增加外部变量 # 构建pb, 这里很有意思, 新版本运行ad-hoc或playbook都需要构建这样的pb, 只是最后调用play的类不一样 # :param name: 任务名,类似playbook中tasks中的name # :param hosts: playbook中的hosts # :param tasks: playbook中的tasks, 其实这就是playbook的语法, 因为tasks的值是个列表,因此可以写入多个task play_source = { "name": "Ansible Ad-Hoc", "hosts": "localhost", "gather_facts": "no", "tasks": [ {"action": {"module": "shell", "args": "w"}} ] } 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=None, stdout_callback='minimal', run_tree=False, ) result = tqm.run(play) print result finally: if tqm is not None: tqm.cleanup()
def main(): host_list = ['localhost', 'www.example.com', 'www.google.com'] Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'remote_user', 'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity', 'check']) # initialize needed objects variable_manager = VariableManager() loader = DataLoader() options = Options(connection='smart', module_path='/usr/share/ansible', forks=100, remote_user=None, private_key_file=None, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=None, become_method=None, become_user=None, verbosity=None, check=False) passwords = dict() # create inventory and pass to var manager inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=host_list) variable_manager.set_inventory(inventory) # create play with tasks play_source = dict( name="Ansible Play", hosts=host_list, gather_facts='no', tasks=[dict(action=dict(module='command', args=dict(cmd='/usr/bin/uptime')))] ) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # actually run it tqm = None callback = ResultsCollector() try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, ) tqm._stdout_callback = callback result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() print("UP ***********") for host, result in callback.host_ok.items(): print('{} >>> {}'.format(host, result._result['stdout'])) print("FAILED *******") for host, result in callback.host_failed.items(): print('{} >>> {}'.format(host, result._result['msg'])) print("DOWN *********") for host, result in callback.host_unreachable.items(): print('{} >>> {}'.format(host, result._result['msg']))
def run(self, host_list, module_name, module_args,): """ run module from andible ad-hoc. module_name: ansible module_name module_args: ansible module args """ self.results_raw = {'success':{}, 'failed':{}, 'unreachable':{}} Options = namedtuple('Options', ['connection','module_path', 'forks', 'timeout', 'remote_user', 'ask_pass', 'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'ask_value_pass', 'verbosity', 'check']) options = Options(connection='smart', module_path='/usr/share/ansible', forks=100, timeout=10, remote_user='******', ask_pass=False, private_key_file=None, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=None, become_method=None, become_user='******',ask_value_pass=False, verbosity=None, check=False) passwords = dict(sshpass=None, becomepass=None) # create play with tasks play_source = dict( name="Ansible Play", hosts=host_list, gather_facts='no', tasks=[dict(action=dict(module=module_name, args=module_args))] ) play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) # actually run it tqm = None callback = ResultsCollector() try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=options, passwords=passwords, ) tqm._stdout_callback = callback result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() for host, result in callback.host_ok.items(): self.results_raw['success'][host] = result._result.get('stdout') + result._result.get('stderr') for host, result in callback.host_failed.items(): self.results_raw['failed'][host] = result._result.get('stdout') + result._result.get('stderr') for host, result in callback.host_unreachable.items(): self.results_raw['unreachable'][host]= result._result['msg'] logger.info(self.results_raw) return self.results_raw
def main(args): # Options definition # Custom tuple to store playbook options Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check']) # Object initialization variable_manager = VariableManager() loader = DataLoader() options = Options(connection='ssh',module_path='library', forks=100, become=None, become_method=None, become_user=None, check=False) passwords = {} # Dinamyc inventory inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=args) # Inventory assignation variable_manager.set_inventory(inventory) # Play creation with tasks play_source = dict( name="Ansible Play", hosts=args, gather_facts='no', tasks=[ dict(action=dict(module='shell', args='hostname -f'), register='shell_out'), dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # Running it tqm = None try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, stdout_callback='default' ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup()
def main(argv=sys.argv[1:]): Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check']) # initialize needed objects variable_manager = VariableManager() loader = DataLoader() options = Options(connection='local', module_path='/path/to/mymodules', forks=100, become=None, become_method=None, become_user=None, check=False) passwords = dict(vault_pass='******') # create inventory and pass to var manager inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list='localhost') variable_manager.set_inventory(inventory) # create play with tasks play_source = dict(name="Ansible Play", hosts='localhost', gather_facts='no', tasks=[ dict(action=dict(module='shell', args='uname -a'), register='shell_out'), dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) 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='default', ) result = tqm.run(play) print result finally: if tqm is not None: tqm.cleanup()
def test_base(self): test_inv_dir = 'test/inventory' for inv in os.listdir(test_inv_dir): print "Processing ", inv res = dynlxc.main(os.path.join(test_inv_dir, inv), '') variable_manager = VariableManager() loader = DataLoader() self.mock_rv.communicate.return_value = [ json.dumps(res), 'mocked_err'] try: inventory = Inventory( loader=loader, variable_manager=variable_manager, host_list='inventory/dynlxc.py' ) except Exception as err: raise Exception("Inventory file {0} processing result '{1}' " "failed with {2}".format(inv, res, err)) variable_manager.set_inventory(inventory) play_source = dict(name="Ansible Play", hosts='localhost', gather_facts='no') playbook = os.path.abspath(os.path.join(test_inv_dir, '../playbooks', inv)) if os.path.isfile(playbook): with open(playbook) as fh: real_playbook = yaml.load(fh)[0] play_source.update(real_playbook) 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=self.options, passwords=None, stdout_callback='default', ) result = tqm.run(play) assert result == 0, ("Ansible playbook exitcode " "different from 0") finally: if tqm is not None: tqm.cleanup()
def test_strategy_base_run_handlers(self, mock_worker): def fake_run(*args): return mock_worker.side_effect = fake_run mock_play_context = MagicMock() mock_handler_task = MagicMock(Handler) mock_handler_task.action = 'foo' mock_handler_task.get_name.return_value = "test handler" mock_handler_task.has_triggered.return_value = False mock_handler = MagicMock() mock_handler.block = [mock_handler_task] mock_handler.flag_for_host.return_value = False mock_play = MagicMock() mock_play.handlers = [mock_handler] mock_host = MagicMock(Host) mock_host.name = "test01" mock_host.has_hostkey = True mock_inventory = MagicMock() mock_inventory.get_hosts.return_value = [mock_host] mock_var_mgr = MagicMock() mock_var_mgr.get_vars.return_value = dict() mock_iterator = MagicMock mock_iterator._play = mock_play fake_loader = DictDataLoader() mock_options = MagicMock() mock_options.module_path = None tqm = TaskQueueManager( inventory=mock_inventory, variable_manager=mock_var_mgr, loader=fake_loader, options=mock_options, passwords=None, ) tqm._initialize_processes(3) tqm._initialize_notified_handlers(mock_play) tqm.hostvars = dict() try: strategy_base = StrategyBase(tqm=tqm) strategy_base._inventory = mock_inventory strategy_base._notified_handlers = {mock_handler_task: [mock_host]} task_result = TaskResult(Host('host01'), Handler(), dict(changed=False)) tqm._final_q.put(('host_task_ok', task_result)) result = strategy_base.run_handlers(iterator=mock_iterator, play_context=mock_play_context) finally: tqm.cleanup()
def run(self): tqm = None try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self.callback, ) for name, play in self.plays.items(): result = tqm.run(play) finally: if tqm is not None: tqm.cleanup()
def run( self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no',): """ :param gather_facts: :param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ] :param pattern: all, *, or others :param play_name: The play name :return: """ self.check_pattern(pattern) results_callback = self.results_callback_class() cleaned_tasks = self.clean_tasks(tasks) play_source = dict( name=play_name, hosts=pattern, gather_facts=gather_facts, tasks=cleaned_tasks ) play = Play().load( play_source, variable_manager=self.variable_manager, loader=self.loader, ) tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, stdout_callback=results_callback, passwords=self.options.passwords, ) try: tqm.run(play) return results_callback except Exception as e: raise AnsibleError(e) finally: tqm.cleanup() self.loader.cleanup_all_tmp_files()
def __init__(self, playbooks, inventory, variable_manager, loader, options): self._playbooks = playbooks self._inventory = inventory self._variable_manager = variable_manager self._loader = loader self._options = options self._tqm = TaskQueueManager(inventory=inventory, callback='default', variable_manager=variable_manager, loader=loader, options=options)
def run(play): tqm = None results = None try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, stdout_callback='default', ) results = tqm.run(play) finally: if tqm is not None: tqm.cleanup() return tqm, results
def run(self, task_tuple, pattern='all', task_name='Ansible Ad-hoc'): """ :param task_tuple: (('shell', 'ls'), ('ping', '')) :param pattern: :param task_name: :return: """ for module, args in task_tuple: if not self.check_module_args(module, args): return self.tasks.append( dict(action=dict( module=module, args=args, )) ) self.play_source = dict( name=task_name, hosts=pattern, gather_facts=self.gather_facts, tasks=self.tasks ) self.play = Play().load( self.play_source, variable_manager=self.variable_manager, loader=self.loader, ) self.runner = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self.results_callback, ) if not self.inventory.list_hosts("all"): raise AnsibleError("Inventory is empty.") if not self.inventory.list_hosts(self.pattern): raise AnsibleError( "pattern: %s dose not match any hosts." % self.pattern) try: self.runner.run(self.play) except Exception as e: logger.warning(e) else: #logger.debug(self.results_callback.result_q) return self.results_callback.result_q finally: if self.runner: self.runner.cleanup() if self.loader: self.loader.cleanup_all_tmp_files()
def execute_tasks(play_name, tasks, hosts, host_list=os.path.join(DIRNAME, 'ansible_hosts.py'), callback="default"): # NOTICE: Here is a trick. The host we acquired must in the host list # everytime. However I can't get the host list in advance. So I add the # hosts into the host list eveytime if it doesn't exist. if hosts not in ansible_hosts.hosts["all"]["hosts"]: ansible_hosts.hosts["all"]["hosts"].append(hosts) # initialize needed objects variable_manager = VariableManager() loader = DataLoader() # create inventory and pass to var manager inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=host_list) variable_manager.set_inventory(inventory) # create play with tasks play_source = dict( name=play_name, hosts=hosts, gather_facts='no', tasks=tasks) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check']) options = Options(connection=None, module_path=None, forks=10, become=None, become_method=None, become_user=None, check=False) passwords = dict() # actually run it tqm = None try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, stdout_callback=callback) return tqm.run(play) finally: if tqm is not None: tqm.cleanup() pass
def run(self): result = {} results_callback = ResultCallback() try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=results_callback ) tqm.run(self.play) finally: result = results_callback.result if tqm is not None: tqm.cleanup() return result
def run(self): self.variable_manager.set_inventory(self.inventory) play = Play().load(self.create_play_tasks(), variable_manager=self.variable_manager, loader=self.loader) tqm = None callback = ResultsCollector() tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords ) tqm._stdout_callback = callback result = tqm.run(play) return result, callback
def run(self, playbook): pb = Playbook.load(playbook, variable_manager=self.variable_manager, loader=self.loader) # only support one playbook.yml play = pb.get_plays()[0] tqm = None try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords={'conn_pass': None, 'become_pass': None}, stdout_callback=self.callback, ) return tqm.run(play), self.callback.result finally: if tqm is not None: tqm.cleanup()
def _run_play(self, play_src): self.options = options = self.Options(**self.options_args) vm = self.variable_manager vm.extra_vars = load_extra_vars(loader=self.loader, options=options) play = Play().load(play_src, loader=self.loader, variable_manager=vm) tqm = None try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=vm, loader=self.loader, options=options, passwords=dict(), stdout_callback='default') tqm.run(play) return vm.get_vars(self.loader) finally: if tqm is not None: tqm.cleanup()
def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no'): """ :param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ] :param pattern: all, *, or others :param play_name: The play name :param gather_facts: :return: """ self.check_pattern(pattern) self.results_callback = self.get_result_callback() cleaned_tasks = self.clean_tasks(tasks) context.CLIARGS = ImmutableDict(self.options) play_source = dict( name=play_name, hosts=pattern, gather_facts=gather_facts, tasks=cleaned_tasks ) play = Play().load( play_source, variable_manager=self.variable_manager, loader=self.loader, ) tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, stdout_callback=self.results_callback, passwords={"conn_pass": self.options.get("password", "")} ) try: tqm.run(play) return self.results_callback except Exception as e: raise AnsibleError(e) finally: if tqm is not None: tqm.cleanup() shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
def ansible_play(self): # run it tqm = None try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self.results_callback, # stdout_callback='default', ) result = tqm.run(self.play) finally: if tqm is not None: tqm.cleanup() #self.inventory.clear_pattern_cache() if result != 0: raise ValueError('SSH Command Failed, resturn: %s' % result) return self.return_results
def run(self, callback=None): self.variable_manager.set_inventory(self.inventory) play = Play().load(self.create_play_tasks(), variable_manager=self.variable_manager, loader=self.loader) tqm = None if not callback: callback = ResultsCollector() try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=callback ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() return result, callback
class PlaybookExecutor: ''' This is the primary class for executing playbooks, and thus the basis for bin/ansible-playbook operation. ''' def __init__(self, playbooks, inventory, variable_manager, loader, display, options, passwords): self._playbooks = playbooks self._inventory = inventory self._variable_manager = variable_manager self._loader = loader self._display = display self._options = options self.passwords = passwords if options.listhosts or options.listtasks or options.listtags: self._tqm = None else: self._tqm = TaskQueueManager(inventory=inventory, callback='default', variable_manager=variable_manager, loader=loader, display=display, options=options, passwords=self.passwords) def run(self): ''' Run the given playbook, based on the settings in the play which may limit the runs to serialized groups, etc. ''' signal.signal(signal.SIGINT, self._cleanup) result = 0 entrylist = [] entry = {} try: for playbook_path in self._playbooks: pb = Playbook.load(playbook_path, variable_manager=self._variable_manager, loader=self._loader) if self._tqm is None: # we are doing a listing entry = {'playbook': playbook_path} entry['plays'] = [] i = 1 plays = pb.get_plays() self._display.vv('%d plays in %s' % (len(plays), playbook_path)) for play in plays: self._inventory.remove_restriction() # Create a temporary copy of the play here, so we can run post_validate # on it without the templating changes affecting the original object. all_vars = self._variable_manager.get_vars(loader=self._loader, play=play) new_play = play.copy() new_play.post_validate(all_vars, fail_on_undefined=False) if self._tqm is None: # we are just doing a listing pname = new_play.get_name().strip() if pname == 'PLAY: <no name specified>': pname = 'PLAY: #%d' % i p = { 'name': pname } if self._options.listhosts: p['pattern']=play.hosts p['hosts']=set(self._inventory.get_hosts(new_play.hosts)) #TODO: play tasks are really blocks, need to figure out how to get task objects from them elif self._options.listtasks: p['tasks'] = [] for task in play.get_tasks(): p['tasks'].append(task) #p['tasks'].append({'name': task.get_name().strip(), 'tags': task.tags}) elif self._options.listtags: p['tags'] = set(new_play.tags) for task in play.get_tasks(): p['tags'].update(task) #p['tags'].update(task.tags) entry['plays'].append(p) else: # we are actually running plays for batch in self._get_serialized_batches(new_play): if len(batch) == 0: self._tqm.send_callback('v2_playbook_on_play_start', new_play) self._tqm.send_callback('v2_playbook_on_no_hosts_matched') result = 0 break # restrict the inventory to the hosts in the serialized batch self._inventory.restrict_to_hosts(batch) # and run it... result = self._tqm.run(play=play) if result != 0: break if result != 0: break i = i + 1 # per play if entry: entrylist.append(entry) # per playbook if entrylist: return entrylist finally: if self._tqm is not None: self._cleanup() # FIXME: this stat summary stuff should be cleaned up and moved # to a new method, if it even belongs here... self._display.banner("PLAY RECAP") hosts = sorted(self._tqm._stats.processed.keys()) for h in hosts: t = self._tqm._stats.summarize(h) self._display.display("%s : %s %s %s %s" % ( hostcolor(h, t), colorize('ok', t['ok'], 'green'), colorize('changed', t['changed'], 'yellow'), colorize('unreachable', t['unreachable'], 'red'), colorize('failed', t['failures'], 'red')), screen_only=True ) self._display.display("%s : %s %s %s %s" % ( hostcolor(h, t, False), colorize('ok', t['ok'], None), colorize('changed', t['changed'], None), colorize('unreachable', t['unreachable'], None), colorize('failed', t['failures'], None)), log_only=True ) self._display.display("", screen_only=True) # END STATS STUFF return result def _cleanup(self, signum=None, framenum=None): return self._tqm.cleanup() def _get_serialized_batches(self, play): ''' Returns a list of hosts, subdivided into batches based on the serial size specified in the play. ''' # make sure we have a unique list of hosts all_hosts = self._inventory.get_hosts(play.hosts) # check to see if the serial number was specified as a percentage, # and convert it to an integer value based on the number of hosts if isinstance(play.serial, basestring) and play.serial.endswith('%'): serial_pct = int(play.serial.replace("%","")) serial = int((serial_pct/100.0) * len(all_hosts)) else: serial = int(play.serial) # if the serial count was not specified or is invalid, default to # a list of all hosts, otherwise split the list of hosts into chunks # which are based on the serial size if serial <= 0: return [all_hosts] else: serialized_batches = [] while len(all_hosts) > 0: play_hosts = [] for x in range(serial): if len(all_hosts) > 0: play_hosts.append(all_hosts.pop(0)) serialized_batches.append(play_hosts) return serialized_batches
def default(self, line, forceshell=False): """ actually runs modules """ if line.startswith("#"): return False if not self.cwd: display.error("No host found") return False # defaults module = 'shell' module_args = line if forceshell is not True: possible_module, *possible_args = line.split() if module_loader.find_plugin(possible_module): # we found module! module = possible_module if possible_args: module_args = ' '.join(possible_args) else: module_args = '' if self.callback: cb = self.callback elif C.DEFAULT_LOAD_CALLBACK_PLUGINS and C.DEFAULT_STDOUT_CALLBACK != 'default': cb = C.DEFAULT_STDOUT_CALLBACK else: cb = 'minimal' result = None try: check_raw = module in C._ACTION_ALLOWS_RAW_ARGS task = dict(action=dict(module=module, args=parse_kv(module_args, check_raw=check_raw)), timeout=self.task_timeout) play_ds = dict( name="Ansible Shell", hosts=self.cwd, gather_facts='no', tasks=[task], remote_user=self.remote_user, become=self.become, become_user=self.become_user, become_method=self.become_method, check_mode=self.check_mode, diff=self.diff, collections=self.collections, ) 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: # 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, passwords=self.passwords, stdout_callback=cb, run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS, run_tree=False, forks=self.forks, ) result = self._tqm.run(play) display.debug(result) 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: if self.verbosity >= 3: import traceback display.v(traceback.format_exc()) display.error(to_text(e)) return False
'gather_facts' : 'False', 'tasks' : [ { 'name' : 'shell', 'shell' : 'ls /', 'register' : 'result', }, { 'debug' : { 'msg' : ' {{ result.stdout }}', } } ] } play = Play().load(source, variable_manager=variable_manager, loader=loader) tqm = None tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, stdout_callback=callback ) result = tqm.run(play) if tqm: tqm.cleanup()
class AdHocCLI(CLI): ''' code behind ansible ad-hoc cli''' def parse(self): ''' create an options parser for bin/ansible ''' self.parser = CLI.base_parser( usage='%prog <host-pattern> [options]', runas_opts=True, async_opts=True, output_opts=True, connect_opts=True, check_opts=True, runtask_opts=True, vault_opts=True, fork_opts=True, ) # options unique to ansible ad-hoc self.parser.add_option('-a', '--args', dest='module_args', help="module arguments", default=C.DEFAULT_MODULE_ARGS) self.parser.add_option('-m', '--module-name', dest='module_name', help="module name to execute (default=%s)" % C.DEFAULT_MODULE_NAME, default=C.DEFAULT_MODULE_NAME) self.options, self.args = self.parser.parse_args() if len(self.args) != 1: raise AnsibleOptionsError("Missing target hosts") self.display.verbosity = self.options.verbosity self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True) return True def _play_ds(self, pattern): return dict( name="Ansible Ad-Hoc", hosts=pattern, gather_facts='no', tasks=[ dict(action=dict(module=self.options.module_name, args=parse_kv(self.options.module_args))), ]) def run(self): ''' use Runner lib to do SSH things ''' super(AdHocCLI, self).run() # only thing left should be host pattern pattern = self.args[0] # ignore connection password cause we are local if self.options.connection == "local": self.options.ask_pass = False sshpass = None becomepass = None vault_pass = None 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) variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) hosts = inventory.list_hosts(pattern) if len(hosts) == 0: self.display.warning( "provided hosts list is empty, only localhost is available") if self.options.listhosts: self.display.display(' hosts (%d):' % len(hosts)) for host in hosts: self.display.display(' %s' % host) return 0 if self.options.module_name in C.MODULE_REQUIRE_ARGS and not self.options.module_args: err = "No argument passed to %s module" % self.options.module_name if pattern.endswith(".yml"): err = err + ' (did you mean to run ansible-playbook?)' raise AnsibleOptionsError(err) #TODO: implement async support #if self.options.seconds: # callbacks.display("background launch...\n\n", color='cyan') # results, poller = runner.run_async(self.options.seconds) # results = self.poll_while_needed(poller) #else: # results = runner.run() # create a pseudo-play to execute the specified module via a single task play_ds = self._play_ds(pattern) play = Play().load(play_ds, variable_manager=variable_manager, loader=loader) if self.options.one_line: cb = 'oneline' else: cb = 'minimal' if self.options.tree: C.DEFAULT_CALLBACK_WHITELIST.append('tree') C.TREE_DIR = self.options.tree # now create a task queue manager to execute the play self._tqm = None try: self._tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, display=self.display, options=self.options, passwords=passwords, stdout_callback=cb, ) result = self._tqm.run(play) finally: if self._tqm: self._tqm.cleanup() return result # ---------------------------------------------- def poll_while_needed(self, poller): ''' summarize results from Runner ''' # BACKGROUND POLL LOGIC when -B and -P are specified if self.options.seconds and self.options.poll_interval > 0: poller.wait(self.options.seconds, self.options.poll_interval) return poller.results
class AdHocRunner(object): """ ADHoc接口 """ Options = namedtuple("Options", [ 'connection', 'module_path', 'private_key_file', "remote_user", 'timeout', 'forks', 'become', 'become_method', 'become_user', 'check', 'extra_vars', ]) results_callback_class = AdHocResultCallback def __init__( self, hosts=C.DEFAULT_HOST_LIST, forks=C.DEFAULT_FORKS, # 5 timeout=C.DEFAULT_TIMEOUT, # SSH timeout = 10s remote_user=C.DEFAULT_REMOTE_USER, # root module_path=None, # dirs of custome modules connection_type="smart", become=None, become_method=None, become_user=None, check=False, passwords=None, extra_vars=None, private_key_file=None, gather_facts='no'): self.pattern = '' self.variable_manager = VariableManager() self.loader = DataLoader() self.gather_facts = gather_facts self.results_callback = AdHocRunner.results_callback_class() self.options = self.Options( connection=connection_type, timeout=timeout, module_path=module_path, forks=forks, become=become, become_method=become_method, become_user=become_user, check=check, remote_user=remote_user, extra_vars=extra_vars or [], private_key_file=private_key_file, ) self.variable_manager.extra_vars = load_extra_vars( self.loader, options=self.options) self.variable_manager.options_vars = load_options_vars(self.options) self.passwords = passwords or {} self.inventory = JMSInventory(hosts) self.variable_manager.set_inventory(self.inventory) self.tasks = [] self.play_source = None self.play = None self.runner = None @staticmethod def check_module_args(module_name, module_args=''): if module_name in C.MODULE_REQUIRE_ARGS and not module_args: err = "No argument passed to '%s' module." % module_name print(err) return False return True def run(self, task_tuple, pattern='all', task_name='Ansible Ad-hoc'): """ :param task_tuple: (('shell', 'ls'), ('ping', '')) :param pattern: :param task_name: :return: """ for module, args in task_tuple: if not self.check_module_args(module, args): return self.tasks.append(dict(action=dict( module=module, args=args, ))) self.play_source = dict(name=task_name, hosts=pattern, gather_facts=self.gather_facts, tasks=self.tasks) self.play = Play().load( self.play_source, variable_manager=self.variable_manager, loader=self.loader, ) self.runner = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self.results_callback, ) if not self.inventory.list_hosts("all"): raise AnsibleError("Inventory is empty.") if not self.inventory.list_hosts(self.pattern): raise AnsibleError("pattern: %s dose not match any hosts." % self.pattern) try: self.runner.run(self.play) except Exception as e: logger.warning(e) else: #logger.debug(self.results_callback.result_q) return self.results_callback.result_q finally: if self.runner: self.runner.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() def clean_result(self): """ :return: { "success": ['hostname',], "failed": [('hostname', 'msg'), {}], } """ result = {'success': [], 'failed': []} for host in self.results_callback.result_q['contacted']: result['success'].append(host) for host, msgs in self.results_callback.result_q['dark'].items(): msg = '\n'.join([ '{} {}: {}'.format( msg.get('module_stdout', ''), msg.get('invocation', {}).get('module_name'), msg.get('msg', '')) for msg in msgs ]) result['failed'].append((host, msg)) return result
class PlaybookExecutor: ''' This is the primary class for executing playbooks, and thus the basis for bin/ansible-playbook operation. ''' def __init__(self, playbooks, inventory, variable_manager, loader, options, passwords, callback=None): self._playbooks = playbooks self._inventory = inventory self._variable_manager = variable_manager self._loader = loader self._options = options self.passwords = passwords self.callback = callback self._unreachable_hosts = dict() if options.listhosts or options.listtasks or options.listtags or options.syntax: self._tqm = None else: self._tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=self.passwords,stdout_callback=callback) def run(self): ''' Run the given playbook, based on the settings in the play which may limit the runs to serialized groups, etc. ''' result = 0 entrylist = [] entry = {} try: for playbook_path in self._playbooks: pb = Playbook.load(playbook_path, variable_manager=self._variable_manager, loader=self._loader) self._inventory.set_playbook_basedir(os.path.dirname(playbook_path)) if self._tqm is None: # we are doing a listing entry = {'playbook': playbook_path} entry['plays'] = [] else: # make sure the tqm has callbacks loaded self._tqm.load_callbacks() self._tqm.send_callback('v2_playbook_on_start', pb) i = 1 plays = pb.get_plays() display.vv(u'%d plays in %s' % (len(plays), to_unicode(playbook_path))) for play in plays: if play._included_path is not None: self._loader.set_basedir(play._included_path) else: self._loader.set_basedir(pb._basedir) # clear any filters which may have been applied to the inventory self._inventory.remove_restriction() if play.vars_prompt: for var in play.vars_prompt: vname = var['name'] prompt = var.get("prompt", vname) default = var.get("default", None) private = var.get("private", True) confirm = var.get("confirm", False) encrypt = var.get("encrypt", None) salt_size = var.get("salt_size", None) salt = var.get("salt", None) if vname not in self._variable_manager.extra_vars: if self._tqm: self._tqm.send_callback('v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt, default) play.vars[vname] = display.do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default) else: # we are either in --list-<option> or syntax check play.vars[vname] = default # Create a temporary copy of the play here, so we can run post_validate # on it without the templating changes affecting the original object. all_vars = self._variable_manager.get_vars(loader=self._loader, play=play) templar = Templar(loader=self._loader, variables=all_vars) new_play = play.copy() new_play.post_validate(templar) if self._options.syntax: continue if self._tqm is None: # we are just doing a listing entry['plays'].append(new_play) else: self._tqm._unreachable_hosts.update(self._unreachable_hosts) previously_failed = len(self._tqm._failed_hosts) previously_unreachable = len(self._tqm._unreachable_hosts) break_play = False # we are actually running plays for batch in self._get_serialized_batches(new_play): if len(batch) == 0: self._tqm.send_callback('v2_playbook_on_play_start', new_play) self._tqm.send_callback('v2_playbook_on_no_hosts_matched') break # restrict the inventory to the hosts in the serialized batch self._inventory.restrict_to_hosts(batch) # and run it... result = self._tqm.run(play=play) # break the play if the result equals the special return code if result == self._tqm.RUN_FAILED_BREAK_PLAY: result = self._tqm.RUN_FAILED_HOSTS break_play = True # check the number of failures here, to see if they're above the maximum # failure percentage allowed, or if any errors are fatal. If either of those # conditions are met, we break out, otherwise we only break out if the entire # batch failed failed_hosts_count = len(self._tqm._failed_hosts) + len(self._tqm._unreachable_hosts) - \ (previously_failed + previously_unreachable) if new_play.max_fail_percentage is not None and \ int((new_play.max_fail_percentage)/100.0 * len(batch)) > int((len(batch) - failed_hosts_count) / len(batch) * 100.0): break_play = True break elif len(batch) == failed_hosts_count: break_play = True break # save the unreachable hosts from this batch self._unreachable_hosts.update(self._tqm._unreachable_hosts) # if the last result wasn't zero or 3 (some hosts were unreachable), # break out of the serial batch loop if result not in (self._tqm.RUN_OK, self._tqm.RUN_UNREACHABLE_HOSTS): break if break_play: break i = i + 1 # per play if entry: entrylist.append(entry) # per playbook # send the stats callback for this playbook if self._tqm is not None: if C.RETRY_FILES_ENABLED: retries = set(self._tqm._failed_hosts.keys()) retries.update(self._tqm._unreachable_hosts.keys()) retries = sorted(retries) if len(retries) > 0: if C.RETRY_FILES_SAVE_PATH: basedir = C.shell_expand(C.RETRY_FILES_SAVE_PATH) elif playbook_path: basedir = os.path.dirname(playbook_path) else: basedir = '~/' (retry_name, _) = os.path.splitext(os.path.basename(playbook_path)) filename = os.path.join(basedir, "%s.retry" % retry_name) if self._generate_retry_inventory(filename, retries): display.display("\tto retry, use: --limit @%s\n" % filename) self._tqm.send_callback('v2_playbook_on_stats', self._tqm._stats) # if the last result wasn't zero, break out of the playbook file name loop if result != 0: break if entrylist: return entrylist finally: if self._tqm is not None: self._tqm.cleanup() if self._loader: self._loader.cleanup_all_tmp_files() if self._options.syntax: display.display("No issues encountered") return result return result def _get_serialized_batches(self, play): ''' Returns a list of hosts, subdivided into batches based on the serial size specified in the play. ''' # make sure we have a unique list of hosts all_hosts = self._inventory.get_hosts(play.hosts) # check to see if the serial number was specified as a percentage, # and convert it to an integer value based on the number of hosts if isinstance(play.serial, string_types) and play.serial.endswith('%'): serial_pct = int(play.serial.replace("%","")) serial = int((serial_pct/100.0) * len(all_hosts)) or 1 else: if play.serial is None: serial = -1 else: serial = int(play.serial) # if the serial count was not specified or is invalid, default to # a list of all hosts, otherwise split the list of hosts into chunks # which are based on the serial size if serial <= 0: return [all_hosts] else: serialized_batches = [] while len(all_hosts) > 0: play_hosts = [] for x in range(serial): if len(all_hosts) > 0: play_hosts.append(all_hosts.pop(0)) serialized_batches.append(play_hosts) return serialized_batches def _generate_retry_inventory(self, retry_path, replay_hosts): ''' Called when a playbook run fails. It generates an inventory which allows re-running on ONLY the failed hosts. This may duplicate some variable information in group_vars/host_vars but that is ok, and expected. ''' try: makedirs_safe(os.path.dirname(retry_path)) with open(retry_path, 'w') as fd: for x in replay_hosts: fd.write("%s\n" % x) except Exception as e: display.warning("Could not create retry file '%s'.\n\t%s" % (retry_path, to_str(e))) return False return True
def _run(self, ips, key_file, play_file, expected_results=[0], play_vars={}): """ Common code used for each run. :param ips: IP address(es) to check. :type ips: str or list :param key_file: Full path the the file holding the private SSH key. :type key_file: string :param play_file: Path to the ansible play file. :type play_file: str :param expected_results: List of expected return codes. Default: [0] :type expected_results: list :returns: Ansible exit code :type: int """ if type(ips) != list: ips = [ips] ssh_args = ('-o StrictHostKeyChecking=no -o ' 'ControlMaster=auto -o ControlPersist=60s') options = self.Options(connection='ssh', module_path=None, forks=1, remote_user='******', private_key_file=key_file, ssh_common_args=ssh_args, ssh_extra_args=ssh_args, sftp_extra_args=None, scp_extra_args=None, become=None, become_method=None, become_user=None, verbosity=None, check=False) # create inventory and pass to var manager inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=ips) self.logger.debug('Options: {0}'.format(options)) group = Group('commissaire_targets') for ip in ips: host = Host(ip, 22) group.add_host(host) inventory.groups.update({'commissaire_targets': group}) self.logger.debug('Inventory: {0}'.format(inventory)) self.variable_manager.set_inventory(inventory) play_source = self.loader.load_from_file(play_file)[0] play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) # Add any variables provided into the play play.vars.update(play_vars) self.logger.debug( 'Running play for hosts {0}: play={1}, vars={2}'.format( ips, play_source, play.vars)) # actually run it for cnt in range(0, 3): tqm = None try: tqm = TaskQueueManager( inventory=inventory, variable_manager=self.variable_manager, loader=self.loader, options=options, passwords=self.passwords, stdout_callback=LogForward(), ) result = tqm.run(play) # Deal with unreachable hosts (result == 3) by retrying # up to 3 times, sleeping 5 seconds after each attempt. if result == 3 and cnt < 2: self.logger.warn( 'One or more hosts in {0} is unreachable, ' 'retrying in 5 seconds...'.format(ips)) sleep(5) else: break finally: if tqm is not None: self.logger.debug( 'Cleaning up after the TaskQueueManager.') tqm.cleanup() if result in expected_results: self.logger.debug('{0}: Good result {1}'.format(ip, result)) fact_cache = self.variable_manager._fact_cache.get(ip, {}) return (result, fact_cache) self.logger.debug('{0}: Bad result {1}'.format(ip, result)) raise Exception('Can not run for {0}'.format(ip))
class MyRunner: def __init__(self, resource): # Gets data from YAML/JSON files self.loader = DataLoader() # All the variables from all the various places self.variable_manager = VariableManager() # Set inventory, using most of above objects self.inventory = MyInventory(resource=resource, loader=self.loader, variable_manager=self.variable_manager) self.variable_manager.set_inventory(self.inventory) def init_options(self, connection='ssh', become=True): self.options = Options() self.options.connection = 'ssh' # Need a connection type 'smart' or 'ssh' self.options.become = become self.options.become_method = 'sudo' self.options.become_user = '******' def init_task_queue_manager(self): # Become Pass Needed if not logging in as user root (do not support now) passwords = {'become_pass': ''} # set callback object self.results_callback = CallbackModule() # playbook self.tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=passwords, stdout_callback=self.results_callback, ) def run(self, module_name='shell', module_args='', gather_facts=False, pattern='*', become=True): self.init_options(become=True) self.init_task_queue_manager() play_source = dict( name='Ansible Play', hosts=pattern, gather_facts=gather_facts, tasks=[ dict(action=dict(module=module_name, args=module_args)), ] ) self.play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) self.tqm.run(self.play) self.result_raw = self.results_callback.results return self.result_raw def close(self): self.tqm.cleanup() @property def results(self): """ {'failed': {'localhost': ''}, 'ok': {'jumpserver': ''}} """ result = {'failed': {}, 'ok': {}} results = self.result_raw[-1] tasks = results.get('tasks', {}) hosts = tasks[0].get('hosts', {}) for host, info in hosts.items(): if info.get('unreachable') or info.get('failed'): result['failed'][host] = info.get('msg') else: if info.get('invocation').get('module_name') in ['raw', 'shell', 'command', 'script']: if info.get('rc') == 0: result['ok'][host] = info.get('stdout') + info.get('stderr') else: result['failed'][host] = info.get('stdout') + info.get('stderr') elif info.get('invocation').get('module_name') in ['setup']: result['ok'][host] = info.get('ansible_facts') else: if info.get('failed'): result['failed'][host] = info.get('msg') else: result['ok'][host] = info.get('changed') return result
def exec_ansible_api(self, playbooks_file): variable_manager = VariableManager() loader = DataLoader() ds = loader.load_from_file(playbooks_file) Options = namedtuple('Options', [ 'connection', 'module_path', 'forks', 'remote_user', 'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity', 'check' ]) options = Options(connection='ssh', module_path=None, forks=100, remote_user='******', private_key_file='id_rsa', ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=None, become_method=None, become_user=None, verbosity=None, check=False) # create inventory and pass to var manager inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=Global.inventory) variable_manager.set_inventory(inventory) # Currently we are limiting to one playbook play_source = ds[0] 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=None, stdout_callback=Global.display) result = tqm.run(play) # Exit gdeploy in case of errors and user has explicitly set # not to ignore errors if result != 0 and Global.ignore_errors != 'yes': msg = "Error while executing playbook %s, exiting"\ %playbooks_file print msg Global.logger.error(msg) self.cleanup_and_quit(1) elif result != 0 and Global.ignore_errors == 'yes': msg = "Error while executing playbook %s, ignoring errors..."\ %playbooks_file Global.logger.error(msg) print msg except AnsibleError, e: print "%s" % e
def execute(self, *args, **kwargs): """ Puts args and kwargs in a way ansible can understand. Calls ansible and interprets the result. """ assert self.is_hooked_up, "the module should be hooked up to the api" self.module_args = module_args = self.get_module_args(args, kwargs) loader = DataLoader() inventory_manager = SourcelessInventoryManager(loader=loader) for server, port in self.api.servers: inventory_manager._inventory.add_host(server, group='all', port=port) for key, value in self.api.options.extra_vars.items(): inventory_manager._inventory.set_variable('all', key, value) variable_manager = VariableManager(loader=loader, inventory=inventory_manager) play_source = { 'name': "Suitable Play", 'hosts': self.api.servers.hosts, 'gather_facts': 'no', 'tasks': [{ 'action': { 'module': self.module_name, 'args': module_args, }, 'environment': self.api.environment }] } play = Play.load(play_source, variable_manager=variable_manager, loader=loader) log.info(u'running {}'.format(u'- {module_name}: {module_args}'.format( module_name=self.module_name, module_args=module_args))) start = datetime.utcnow() task_queue_manager = None callback = SilentCallbackModule() try: task_queue_manager = TaskQueueManager( inventory=inventory_manager, variable_manager=variable_manager, loader=loader, options=self.api.options, passwords=getattr(self.api.options, 'passwords', {}), stdout_callback=callback) task_queue_manager.run(play) finally: if task_queue_manager is not None: task_queue_manager.cleanup() log.info(u'took {} to complete'.format(datetime.utcnow() - start)) return self.evaluate_results(callback)
def CallbackBaseAdHoc(hosts, actions, name="Ansible Play", source=settings.ANSIBLE_SOURCE): ''' :param hosts: 主机列表 :param actions: 相关ad-hoc的指令,以字典形式 [dict(action=dict(module="shell", args="touch /tmp/bbb.txt", warn=False)),] :param name: 任务名称 :param source ansible配置hosts文件 :return: ''' logger = logging.getLogger("django") dataLoader = DataLoader() inventory = InventoryManager(loader=dataLoader, sources=source) #主机信息管理 variableManager = VariableManager(loader=dataLoader, inventory=inventory) #变量管理 Options = namedtuple("Options", [ "connection", "remote_user", "ask_sudo_pass", "verbosity", "ack_pass", "module_path", "forks", "become", "become_method", "become_user", "check", "listhosts", "listtasks", "listtags", "syntax", "sudo_user", "sudo", "diff" ]) options = Options(connection='ssh', remote_user=None, ack_pass=None, sudo_user=None, forks=settings.ANSIBLE_FORKS, sudo=None, ask_sudo_pass=False, verbosity=5, module_path=None, become=None, become_method=None, become_user=None, check=False, diff=False, listhosts=None, listtasks=None, listtags=None, syntax=None) play_source = dict( name=name, # 任务名称 hosts=hosts, # 目标主机,可以填写具体主机也可以是主机组名称 gather_facts="no", # 是否收集主机配置信息 tasks=actions # tasks是具体执行的任务,列表形式,每个具体任务都是一个字典 ) play = Play().load(play_source, variable_manager=variableManager, loader=dataLoader) passwords = dict() # 这个可以为空,因为在hosts文件中有配置或者密钥登陆 callback = AdHocCallbackBase() tqm = TaskQueueManager(inventory=inventory, variable_manager=variableManager, loader=dataLoader, options=options, passwords=passwords, stdout_callback=callback) logger_info = {"hosts": hosts, "actions": actions, "passwords": passwords} logger.info(str(logger_info)) tqm.run(play) status_list = ['ok', 'failed', 'unreachable', 'skipped'] result_raw = {"failed": {}, "unreachable": {}, "ok": {}, "skipped": {}} for status in status_list: for host, result in getattr(callback, 'host_' + status).items(): result_raw[status][host] = result._result result_raw[status][host]["task"] = name logger.info(str(result_raw)) result_raw = get_result(result_raw) return result_raw
host = result._host print(json.dumps({host.name: result._result}, indent=4)) context.CLIARGS = ImmutableDict(connection='local', module_path=['/to/mymodules'], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False) loader = DataLoader() passwords = dict(vault_pass='******') results_callback = ResultCallback() inventory = InventoryManager(loader=loader, sources='localhost,') variable_manager = VariableManager(loader=loader, inventory=inventory) play = Play().load(playbook_path, variable_manager=variable_manager, loader=loader) tqm = None try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords, stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin, which prints to stdout ) result = tqm.run(play) # most interesting data for a play is actually sent to the callback's methods finally: # we always need to cleanup child procs and the structures we use to communicate with them if tqm is not None: tqm.cleanup() # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
def run_ansible(module_name, module_args, host_list, ansible_user="******"): """ansible api""" # 负责查找和读取yaml、json和ini文件 loader = DataLoader() # 初始化需要的对象 Options = namedtuple('Options', [ 'connection', 'module_path', 'forks', 'become', 'become_method', 'private_key_file', 'become_user', 'remote_user', 'check', 'diff' ]) options = Options(connection='ssh', module_path=None, forks=5, become=True, become_method='sudo', private_key_file="/root/.ssh/id_rsa", become_user='******', remote_user=ansible_user, check=False, diff=False) passwords = dict(vault_pass='******') # 实例化ResultCallback来处理结果 callback = ResultsCollector() # 创建库存(inventory)并传递给VariableManager inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts']) # 管理变量的类,包括主机,组,扩展等变量 variable_manager = VariableManager(loader=loader, inventory=inventory) # 创建任务 host = ",".join(host_list) play_source = dict(name="Ansible Play", hosts=host, gather_facts='no', tasks=[ dict(action=dict(module=module_name, args=module_args), register='shell_out'), ]) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # 开始执行 tqm = None tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, stdout_callback=callback, ) result = tqm.run(play) result_raw = {'success': {}, 'failed': {}, 'unreachable': {}} for host, result in callback.host_ok.items(): result_raw['success'][host] = result._result for host, result in callback.host_failed.items(): result_raw['failed'][host] = result._result for host, result in callback.host_unreachable.items(): result_raw['unreachable'][host] = result._result for host, result in callback.host_skipped.items(): result_raw['skipped'][host] = result._result return json.dumps(result_raw, indent=4, ensure_ascii=False)
def test_strategy_base_run_handlers(self, mock_worker): def fake_run(*args): return mock_worker.side_effect = fake_run mock_play_context = MagicMock() mock_handler_task = MagicMock(Handler) mock_handler_task.action = 'foo' mock_handler_task.get_name.return_value = "test handler" mock_handler_task.has_triggered.return_value = False mock_handler_task.listen = None mock_handler_task._role = None mock_handler_task._parent = None mock_handler_task._uuid = 'xxxxxxxxxxxxxxxx' mock_handler_task.copy.return_value = mock_handler_task mock_handler = MagicMock() mock_handler.block = [mock_handler_task] mock_handler.flag_for_host.return_value = False mock_play = MagicMock() mock_play.handlers = [mock_handler] mock_host = MagicMock(Host) mock_host.name = "test01" mock_host.has_hostkey = True mock_inventory = MagicMock() mock_inventory.get_hosts.return_value = [mock_host] mock_inventory.get.return_value = mock_host mock_inventory.get_host.return_value = mock_host mock_var_mgr = MagicMock() mock_var_mgr.get_vars.return_value = dict() mock_iterator = MagicMock() mock_iterator._play = mock_play fake_loader = DictDataLoader() mock_options = MagicMock() mock_options.module_path = None tqm = TaskQueueManager( inventory=mock_inventory, variable_manager=mock_var_mgr, loader=fake_loader, options=mock_options, passwords=None, ) tqm._initialize_processes(3) tqm._initialize_notified_handlers(mock_play) tqm.hostvars = dict() try: strategy_base = StrategyBase(tqm=tqm) strategy_base._inventory = mock_inventory strategy_base._notified_handlers = { mock_handler_task._uuid: [mock_host] } task_result = TaskResult(mock_host.name, mock_handler_task._uuid, dict(changed=False)) strategy_base._queued_task_cache = dict() strategy_base._queued_task_cache[(mock_host.name, mock_handler_task._uuid)] = { 'task': mock_handler_task, 'host': mock_host, 'task_vars': {}, 'play_context': mock_play_context } tqm._final_q.put(task_result) result = strategy_base.run_handlers(iterator=mock_iterator, play_context=mock_play_context) finally: strategy_base.cleanup() tqm.cleanup()
play_source = dict( name='Ansible Play', hosts='pool', gather_facts='no', tasks=[ dict(action=dict(module='shell', args='systemctl status indy-node'), register='shell_out'), dict(action=dict(module='debug', args=dict( msg='{{shell_out.stdout}}'))) ]) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) if __name__ == '__main__': tqm = None try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords, ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
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()
def execude(self): # since API is constructed for CLI it expects certain options to always be set, named tuple 'fakes' the args parsing options object Options = namedtuple('Options', [ 'connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff', 'private_key_file', ]) options = Options( connection='smart', module_path=['/to/mymodules'], forks=10, become=None, become_method=None, become_user='******', check=False, diff=False, private_key_file='~/.ssh/id_rsa', ) # initialize needed objects loader = DataLoader( ) # Takes care of finding and reading yaml, json and ini files passwords = dict(vault_pass='******') # Instantiate our ResultCallback for handling results as they come in. Ansible expects this to be one of its main display outlets results_callback = ResultCallback() # create inventory, use path to host config file as source or hosts in a comma separated string inventory = InventoryManager(loader=loader, sources='/etc/ansible/hosts') # inventory.add_host(host='172.20.51.22',port=22,group='test') # variable manager takes care of merging all the different sources to give you a unified view of variables available in each context variable_manager = VariableManager(loader=loader, inventory=inventory) # create data structure that represents our play, including tasks, this is basically what our YAML loader does internally. play_source = dict( name="Ansible Play", hosts=self.hosts, gather_facts='no', tasks=[ dict( action=dict(module='shell', args='ps -ef | grep VSM'), register='shell_out', ), # dict(action=dict(module='setup', ), register='shell_out'), # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ]) 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=None, stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin, which prints to stdout ) # atest = tqm # atest.run(play) rs = tqm.run( play, ) # most interesting data for a play is actually sent to the callback's methods print('---') print() # if tqm._stdout_callback.consquence: # for key in tqm._stdout_callback.consquence['172.20.51.22']['stderr']: # print(key,) except BaseException: print(str(BaseException)) finally: # we always need to cleanup child procs and the structures we use to communicate with them if tqm is not None: tqm.cleanup() # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
args='bash /opt/remote_shift/kafka/param_run_container.sh '), register='shell_out'), dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ]) playFifteen = Play().load(play_source_fiftteen, variable_manager=variable_manager, loader=loader) #queue'em, and run dem playbooks final = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, stdout_callback='default', ) ###### # this approach of running playbooks takes too long: # # + resultz = [ playOne, playTwo,...] # + for result in resultz # + run_playbooks = final.run(result) # ######### #the tedious approach, # yet benevolent when troubleshooting any future changes
def run(self): ''' use Runner lib to do SSH things ''' super(AdHocCLI, self).run() # only thing left should be host pattern pattern = self.args[0] # ignore connection password cause we are local if self.options.connection == "local": self.options.ask_pass = False sshpass = None becomepass = None vault_pass = None 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) variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) hosts = inventory.list_hosts(pattern) if len(hosts) == 0: self.display.warning( "provided hosts list is empty, only localhost is available") if self.options.listhosts: self.display.display(' hosts (%d):' % len(hosts)) for host in hosts: self.display.display(' %s' % host) return 0 if self.options.module_name in C.MODULE_REQUIRE_ARGS and not self.options.module_args: err = "No argument passed to %s module" % self.options.module_name if pattern.endswith(".yml"): err = err + ' (did you mean to run ansible-playbook?)' raise AnsibleOptionsError(err) #TODO: implement async support #if self.options.seconds: # callbacks.display("background launch...\n\n", color='cyan') # results, poller = runner.run_async(self.options.seconds) # results = self.poll_while_needed(poller) #else: # results = runner.run() # create a pseudo-play to execute the specified module via a single task play_ds = self._play_ds(pattern) play = Play().load(play_ds, variable_manager=variable_manager, loader=loader) if self.options.one_line: cb = 'oneline' else: cb = 'minimal' if self.options.tree: C.DEFAULT_CALLBACK_WHITELIST.append('tree') C.TREE_DIR = self.options.tree # now create a task queue manager to execute the play self._tqm = None try: self._tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, display=self.display, options=self.options, passwords=passwords, stdout_callback=cb, ) result = self._tqm.run(play) finally: if self._tqm: self._tqm.cleanup() return result
def main(): host_list = ['localhost', 'www.example.com', 'www.google.com'] Options = namedtuple( 'Options', [ 'connection', 'module_path', 'forks', 'remote_user', 'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity', 'check', ], ) # initialize needed objects variable_manager = VariableManager() loader = DataLoader() options = Options( connection='smart', module_path='/usr/share/ansible', forks=100, remote_user=None, private_key_file=None, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=None, become_method=None, become_user=None, verbosity=None, check=False, ) passwords = dict() # create inventory and pass to var manager inventory = Inventory( loader=loader, variable_manager=variable_manager, host_list=host_list, ) variable_manager.set_inventory(inventory) # create play with tasks play_source = dict( name='Ansible Play', hosts=host_list, gather_facts='no', tasks=[dict(action=dict( module='command', args=dict(cmd='/usr/bin/uptime'), ))], ) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # actually run it tqm = None callback = ResultsCollector() try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, ) tqm._stdout_callback = callback result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() print('UP ***********') for host, result in callback.host_ok.items(): print('{} >>> {}'.format(host, result._result['stdout'])) print('FAILED *******') for host, result in callback.host_failed.items(): print('{} >>> {}'.format(host, result._result['msg'])) print('DOWN *********') for host, result in callback.host_unreachable.items(): print('{} >>> {}'.format(host, result._result['msg']))
class ConsoleCLI(CLI, cmd.Cmd): ''' A REPL that allows for running ad-hoc tasks against a chosen inventory from a nice shell with built-in tab completion (based on dominis' ansible-shell). It supports several commands, and you can modify its configuration at runtime: - `cd [pattern]`: change host/group (you can use host patterns eg.: app*.dc*:!app01*) - `list`: list available hosts in the current path - `list groups`: list groups included in the current path - `become`: toggle the become flag - `!`: forces shell module instead of the ansible module (!yum update -y) - `verbosity [num]`: set the verbosity level - `forks [num]`: set the number of forks - `become_user [user]`: set the become_user - `remote_user [user]`: set the remote_user - `become_method [method]`: set the privilege escalation method - `check [bool]`: toggle check mode - `diff [bool]`: toggle diff mode - `timeout [integer]`: set the timeout of tasks in seconds (0 to disable) - `help [command/module]`: display documentation for the command or module - `exit`: exit ansible-console ''' name = 'ansible-console' modules = [] # type: list[str] | None ARGUMENTS = { 'host-pattern': 'A name of a group in the inventory, a shell-like glob ' 'selecting hosts in inventory or any combination of the two separated by commas.' } # use specific to console, but fallback to highlight for backwards compatibility NORMAL_PROMPT = C.COLOR_CONSOLE_PROMPT or C.COLOR_HIGHLIGHT def __init__(self, args): super(ConsoleCLI, self).__init__(args) self.intro = 'Welcome to the ansible console. Type help or ? to list commands.\n' self.groups = [] self.hosts = [] self.pattern = None self.variable_manager = None self.loader = None self.passwords = dict() self.cwd = '*' # Defaults for these are set from the CLI in run() self.remote_user = None self.become = None self.become_user = None self.become_method = None self.check_mode = None self.diff = None self.forks = None self.task_timeout = None self.collections = None cmd.Cmd.__init__(self) def init_parser(self): super(ConsoleCLI, self).init_parser( desc="REPL console for executing Ansible tasks.", epilog= "This is not a live session/connection: each task is executed in the background and returns its results." ) opt_help.add_runas_options(self.parser) opt_help.add_inventory_options(self.parser) opt_help.add_connect_options(self.parser) opt_help.add_check_options(self.parser) opt_help.add_vault_options(self.parser) opt_help.add_fork_options(self.parser) opt_help.add_module_options(self.parser) opt_help.add_basedir_options(self.parser) opt_help.add_runtask_options(self.parser) opt_help.add_tasknoplay_options(self.parser) # options unique to shell self.parser.add_argument('pattern', help='host pattern', metavar='pattern', default='all', nargs='?') self.parser.add_argument( '--step', dest='step', action='store_true', help="one-step-at-a-time: confirm each task before running") def post_process_args(self, options): options = super(ConsoleCLI, self).post_process_args(options) display.verbosity = options.verbosity self.validate_conflicts(options, runas_opts=True, fork_opts=True) return options def get_names(self): return dir(self) def cmdloop(self): try: cmd.Cmd.cmdloop(self) except KeyboardInterrupt: self.cmdloop() except EOFError: self.display("[Ansible-console was exited]") self.do_exit(self) def set_prompt(self): login_user = self.remote_user or getpass.getuser() self.selected = self.inventory.list_hosts(self.cwd) prompt = "%s@%s (%d)[f:%s]" % (login_user, self.cwd, len( self.selected), self.forks) if self.become and self.become_user in [None, 'root']: prompt += "# " color = C.COLOR_ERROR else: prompt += "$ " color = self.NORMAL_PROMPT self.prompt = stringc(prompt, color, wrap_nonvisible_chars=True) def list_modules(self): return list_plugins('module', self.collections) def default(self, line, forceshell=False): """ actually runs modules """ if line.startswith("#"): return False if not self.cwd: display.error("No host found") return False # defaults module = 'shell' module_args = line if forceshell is not True: possible_module, *possible_args = line.split() if module_loader.find_plugin(possible_module): # we found module! module = possible_module if possible_args: module_args = ' '.join(possible_args) else: module_args = '' if self.callback: cb = self.callback elif C.DEFAULT_LOAD_CALLBACK_PLUGINS and C.DEFAULT_STDOUT_CALLBACK != 'default': cb = C.DEFAULT_STDOUT_CALLBACK else: cb = 'minimal' result = None try: check_raw = module in C._ACTION_ALLOWS_RAW_ARGS task = dict(action=dict(module=module, args=parse_kv(module_args, check_raw=check_raw)), timeout=self.task_timeout) play_ds = dict( name="Ansible Shell", hosts=self.cwd, gather_facts='no', tasks=[task], remote_user=self.remote_user, become=self.become, become_user=self.become_user, become_method=self.become_method, check_mode=self.check_mode, diff=self.diff, collections=self.collections, ) 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: # 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, passwords=self.passwords, stdout_callback=cb, run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS, run_tree=False, forks=self.forks, ) result = self._tqm.run(play) display.debug(result) 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: if self.verbosity >= 3: import traceback display.v(traceback.format_exc()) display.error(to_text(e)) 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 help_shell(self): display.display("You can run shell commands through the shell module.") def do_forks(self, arg): """Set the number of forks""" if arg: try: forks = int(arg) except TypeError: display.error('Invalid argument for "forks"') self.usage_forks() if forks > 0: self.forks = forks self.set_prompt() else: display.display('forks must be greater than or equal to 1') else: self.usage_forks() def help_forks(self): display.display("Set the number of forks to use per task") self.usage_forks() def usage_forks(self): display.display('Usage: forks <number>') do_serial = do_forks help_serial = help_forks def do_collections(self, arg): """Set list of collections for 'short name' usage""" if arg in ('', 'none'): self.collections = None elif not arg: self.usage_collections() else: collections = arg.split(',') for collection in collections: if self.collections is None: self.collections = [] self.collections.append(collection.strip()) if self.collections: display.v('Collections name search is set to: %s' % ', '.join(self.collections)) else: display.v('Collections name search is using defaults') def help_collections(self): display.display( "Set the collection name search path when using short names for plugins" ) self.usage_collections() def usage_collections(self): display.display( 'Usage: collections <collection1>[, <collection2> ...]\n Use empty quotes or "none" to reset to default.\n' ) def do_verbosity(self, arg): """Set verbosity level""" if not arg: display.display('Usage: verbosity <number>') else: try: display.verbosity = int(arg) display.v('verbosity level set to %s' % arg) except (TypeError, ValueError) as e: display.error('The verbosity must be a valid integer: %s' % to_text(e)) def help_verbosity(self): display.display( "Set the verbosity level, equivalent to -v for 1 and -vvvv for 4.") 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.cwd = '*' elif arg in '/*': self.cwd = 'all' elif self.inventory.get_hosts(arg): self.cwd = arg else: display.display("no host matched") self.set_prompt() def help_cd(self): display.display("Change active host/group. ") self.usage_cd() def usage_cd(self): display.display("Usage: cd <group>|<host>|<host pattern>") def do_list(self, arg): """List the hosts in the current group""" if not arg: for host in self.selected: display.display(host.name) elif arg == 'groups': for group in self.groups: display.display(group) else: display.error('Invalid option passed to "list"') self.help_list() def help_list(self): display.display( "List the hosts in the current group or a list of groups if you add 'groups'." ) def do_become(self, arg): """Toggle whether plays run with become""" if arg: self.become = boolean(arg, strict=False) display.v("become changed to %s" % self.become) self.set_prompt() else: display.display("Please specify become value, e.g. `become yes`") def help_become(self): display.display("Toggle whether the tasks are run with become") def do_remote_user(self, arg): """Given a username, set the remote user plays are run by""" if arg: self.remote_user = arg self.set_prompt() else: display.display( "Please specify a remote user, e.g. `remote_user root`") def help_remote_user(self): display.display("Set the user for use as login to the remote target") def do_become_user(self, arg): """Given a username, set the user that plays are run by when using become""" if arg: self.become_user = arg else: display.display( "Please specify a user, e.g. `become_user jenkins`") display.v("Current user is %s" % self.become_user) self.set_prompt() def help_become_user(self): display.display( "Set the user for use with privilege escalation (which remote user attempts to 'become' when become is enabled)" ) def do_become_method(self, arg): """Given a become_method, set the privilege escalation method when using become""" if arg: self.become_method = arg display.v("become_method changed to %s" % self.become_method) else: display.display( "Please specify a become_method, e.g. `become_method su`") display.v("Current become_method is %s" % self.become_method) def help_become_method(self): display.display( "Set the privilege escalation plugin to use when become is enabled" ) def do_check(self, arg): """Toggle whether plays run with check mode""" if arg: self.check_mode = boolean(arg, strict=False) display.display("check mode changed to %s" % self.check_mode) else: display.display( "Please specify check mode value, e.g. `check yes`") display.v("check mode is currently %s." % self.check_mode) def help_check(self): display.display("Toggle check_mode for the tasks") def do_diff(self, arg): """Toggle whether plays run with diff""" if arg: self.diff = boolean(arg, strict=False) display.display("diff mode changed to %s" % self.diff) else: display.display("Please specify a diff value , e.g. `diff yes`") display.v("diff mode is currently %s" % self.diff) def help_diff(self): display.display("Toggle diff output for the tasks") def do_timeout(self, arg): """Set the timeout""" if arg: try: timeout = int(arg) if timeout < 0: display.error( 'The timeout must be greater than or equal to 1, use 0 to disable' ) else: self.task_timeout = timeout except (TypeError, ValueError) as e: display.error( 'The timeout must be a valid positive integer, or 0 to disable: %s' % to_text(e)) else: self.usage_timeout() def help_timeout(self): display.display("Set task timeout in seconds") self.usage_timeout() def usage_timeout(self): display.display('Usage: timeout <seconds>') def do_exit(self, args): """Exits from the console""" sys.stdout.write('\nAnsible-console was exited.\n') return -1 def help_exit(self): display.display("LEAVE!") do_EOF = do_exit help_EOF = help_exit def helpdefault(self, module_name): if module_name: in_path = module_loader.find_plugin(module_name) if in_path: oc, a, _dummy1, _dummy2 = plugin_docs.get_docstring( in_path, fragment_loader) if oc: display.display(oc['short_description']) display.display('Parameters:') for opt in oc['options'].keys(): display.display(' ' + stringc(opt, self.NORMAL_PROMPT) + ' ' + 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 help_help(self): display.warning("Don't be redundant!") def complete_cd(self, text, line, begidx, endidx): mline = line.partition(' ')[2] offs = len(mline) - len(text) if self.cwd in ('all', '*', '\\'): completions = self.hosts + self.groups else: completions = [x.name for x in self.inventory.list_hosts(self.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.list_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, _dummy1, _dummy2 = plugin_docs.get_docstring(in_path, fragment_loader, is_module=True) return list(oc['options'].keys()) def run(self): super(ConsoleCLI, self).run() sshpass = None becomepass = None # hosts self.pattern = context.CLIARGS['pattern'] self.cwd = self.pattern # Defaults from the command line self.remote_user = context.CLIARGS['remote_user'] self.become = context.CLIARGS['become'] self.become_user = context.CLIARGS['become_user'] self.become_method = context.CLIARGS['become_method'] self.check_mode = context.CLIARGS['check'] self.diff = context.CLIARGS['diff'] self.forks = context.CLIARGS['forks'] self.task_timeout = context.CLIARGS['task_timeout'] # set module path if needed if context.CLIARGS['module_path']: for path in context.CLIARGS['module_path']: if path: module_loader.add_directory(path) # dynamically add 'cannonical' modules as commands, aliases coudld be used and dynamically loaded 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)) (sshpass, becomepass) = self.ask_passwords() self.passwords = {'conn_pass': sshpass, 'become_pass': becomepass} self.loader, self.inventory, self.variable_manager = self._play_prereqs( ) hosts = self.get_host_list(self.inventory, context.CLIARGS['subset'], self.pattern) 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 __getattr__(self, name): ''' handle not found to populate dynamically a module function if module matching name exists ''' attr = None if name.startswith('do_'): module = name.replace('do_', '') if module_loader.find_plugin(module): setattr(self, name, lambda arg, module=module: self.default(module + ' ' + arg)) attr = object.__getattr__(self, name) elif name.startswith('help_'): module = name.replace('help_', '') if module_loader.find_plugin(module): setattr(self, name, lambda module=module: self.helpdefault(module)) attr = object.__getattr__(self, name) if attr is None: raise AttributeError( f"{self.__class__} does not have a {name} attribute") return attr
def execute(self, *args, **kwargs): """ Puts args and kwargs in a way ansible can understand. Calls ansible and interprets the result. """ assert self.is_hooked_up, "the module should be hooked up to the api" if set_global_context: set_global_context(self.api.options) # legacy key=value pairs shorthand approach if args: self.module_args = module_args = self.get_module_args(args, kwargs) else: self.module_args = module_args = kwargs loader = DataLoader() inventory_manager = SourcelessInventoryManager(loader=loader) for host, host_variables in self.api.inventory.items(): inventory_manager._inventory.add_host(host, group='all') for key, value in host_variables.items(): inventory_manager._inventory.set_variable(host, key, value) for key, value in self.api.options.extra_vars.items(): inventory_manager._inventory.set_variable('all', key, value) variable_manager = VariableManager(loader=loader, inventory=inventory_manager) play_source = { 'name': "Suitable Play", 'hosts': 'all', 'gather_facts': 'no', 'tasks': [{ 'action': { 'module': self.module_name, 'args': module_args, }, 'environment': self.api.environment, }] } try: play = Play.load( play_source, variable_manager=variable_manager, loader=loader, ) if self.api.strategy: play.strategy = self.api.strategy log.info(u'running {}'.format( u'- {module_name}: {module_args}'.format( module_name=self.module_name, module_args=module_args))) start = datetime.utcnow() task_queue_manager = None callback = SilentCallbackModule() # ansible uses various levels of verbosity (from -v to -vvvvvv) # offering various amounts of debug information # # we keep it a bit simpler by activating all of it during debug, # and falling back to the default of 0 otherwise verbosity = self.api.options.verbosity == logging.DEBUG and 6 or 0 with ansible_verbosity(verbosity): # host_key_checking is special, since not each connection # plugin handles it the same way, we need to apply both # environment variable and Ansible constant when running a # command in the runner to be successful with host_key_checking(self.api.host_key_checking): kwargs = dict(inventory=inventory_manager, variable_manager=variable_manager, loader=loader, options=self.api.options, passwords=getattr(self.api.options, 'passwords', {}), stdout_callback=callback) if set_global_context: del kwargs['options'] task_queue_manager = TaskQueueManager(**kwargs) try: task_queue_manager.run(play) except SystemExit: # Mitogen forks our process and exits it in one # instance before returning # # This is fine, but it does lead to a very messy exit # by py.test which will essentially return with a test # that is first successful and then failed as each # forked process dies. # # To avoid this we commit suicide if we are run inside # a pytest session. Normally this would just result # in a exit code of zero, which is good. if 'pytest' in sys.modules: try: atexit._run_exitfuncs() except Exception: pass os.kill(os.getpid(), signal.SIGKILL) raise finally: if task_queue_manager is not None: task_queue_manager.cleanup() if set_global_context: # Ansible 2.8 introduces a global context which persists # during the lifetime of the process - for Suitable this # singleton/cache needs to be cleared after each call # to make sure that API calls do not carry over state. # # The docs hint at a future inclusion of local contexts, which # would of course be preferable. from ansible.utils.context_objects import GlobalCLIArgs GlobalCLIArgs._Singleton__instance = None log.debug(u'took {} to complete'.format(datetime.utcnow() - start)) return self.evaluate_results(callback)
dict(action=dict(module='debug', args=dict( msg='{{shell_out.stdout}}'))) ]) # 创建play object,playbook objects使用。 # 加载而不是初始化或新方法,这也将从play_source中提供的信息自动创建任务对象。 play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # 运行它-实例化任务队列管理器,它负责分叉和设置所有对象,以便在主机列表和任务上迭代。 tqm = None try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords, stdout_callback=results_callback, # 使用我们的自定义回调,而不是打印到stdout的"默认"回调插件 ) result = tqm.run(play) # 一出戏最有趣的数据实际上是发送到回调的方法 finally: # 我们总是需要清理子程序和我们用来与他们沟通的结构. if tqm is not None: tqm.cleanup() # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) if __name__ == "__main__": sys.stdout.write('\033[31;47;1msys.argv is %s\n\033[0m' % sys.argv) returnObj = ResultCallback() print(type(returnObj), '\n---------------\n')
def ansible_adhoc(host_list, module_name, module_args, pattern, play_name=None, passwords=None, forks=5): loader = DataLoader() variable_manager = VariableManager() inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=host_list) variable_manager.set_inventory(inventory) Options = namedtuple('Options', [ 'remote_user', 'forks', 'become_method', 'become_user', 'listhosts', 'listtasks', 'listtags', 'syntax', 'module_path', 'become', 'check', 'verbosity', 'connection', 'private_key_file', 'host_key_checking' ]) options = Options(remote_user='******', forks=10, become_method='sudo', become_user='******', listhosts=False, listtasks=False, listtags=False, syntax=False, module_path=None, become=True, check=False, verbosity=True, connection='smart', private_key_file=None, host_key_checking=False) # variable_manager.extra_vars={"ansible_ssh_user":"******" , "ansible_ssh_pass":"******"} passwords = passwords play_source = { "name": play_name, "hosts": pattern, "gather_facts": "no", "tasks": [{ "action": { "module": module_name, "args": module_args } }] } 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=passwords, stdout_callback='json', ) result_code = tqm.run(play) except Exception as e: raise Exception(e) finally: if tqm is not None: tqm.cleanup() return dict(retcode=result_code, results=tqm._stdout_callback.results)
class Runner(object): def __init__(self, pb_file, sources=['inventory/hosts'], **kwargs): self.pb_file = pb_file self.sources = sources Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff']) # initialize needed objects self.Options = Options(connection='smart', module_path=None, forks=100, become=True, become_method='sudo', become_user='******', check=False, diff=False) self.loader = DataLoader() passwords = dict(vault_pass='******') # Instantiate our ResultCallback for handling results as they come in self.results_callback = ResultCallback() # create inventory and pass to var manager #self.inventory = InventoryManager(loader=loader, sources=['/home/alvin/git/ansible/ansible-playbook/inventory/hosts']) self.inventory = self._gen_inventory() self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) self.variable_manager.extra_vars = kwargs self.tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.Options, passwords=passwords, stdout_callback=self.results_callback, ) def _gen_inventory(self): if isinstance(self.sources, str): assert os.path.isfile(self.sources), "Inventory file ['{}'] not exist".format(self.sources) return InventoryManager(loader=self.loader, sources=self.sources) elif isinstance(self.sources, list): for source in self.sources: assert os.path.isfile(source), "One or more inventory file not exist in {}".format(self.sources) return InventoryManager(loader=self.loader, sources=self.sources) def _load_play_source(self): for source in self.loader.load_from_file(self.pb_file): self.play_source.update(source) def run(self): self.play_source = {} self._load_play_source() self.play = Play().load(self.play_source, variable_manager=self.variable_manager, loader=self.loader) try: ret = self.tqm.run(self.play) return ret finally: if self.tqm is not None: self.tqm.cleanup()
# create play with tasks play_source = dict( name="Ansible Play", hosts='localhost', gather_facts='no', tasks=[ dict( action=dict(module='get_version', args=dict( program='libreoffice'))), ]) 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, # Use our custom callback instead of the ``default`` callback plugin ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup()
inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=["127.0.0.1"]) variable_manager.set_inventory(inventory) play_src = dict(name='ansible api test', hosts='all', gather_facts='no', tasks=[ dict(action=dict(module='shell', args='ifconfig eth5'), register='shell_out') ]) play = Play().load(play_src, variable_manager=variable_manager, loader=loader) tmq = None try: tmq = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, #stdout_callback=results_callback stdout_callback=None) result = tmq.run(play) #print result finally: if tmq is not None: tmq.cleanup()
class PlaybookExecutor: ''' This is the primary class for executing playbooks, and thus the basis for bin/ansible-playbook operation. ''' def __init__(self, playbooks, inventory, variable_manager, loader, options, passwords): self._playbooks = playbooks self._inventory = inventory self._variable_manager = variable_manager self._loader = loader self._options = options self.passwords = passwords self._unreachable_hosts = dict() if options.listhosts or options.listtasks or options.listtags or options.syntax: self._tqm = None else: self._tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=self.passwords) def run(self): ''' Run the given playbook, based on the settings in the play which may limit the runs to serialized groups, etc. ''' signal.signal(signal.SIGINT, self._cleanup) result = 0 entrylist = [] entry = {} try: for playbook_path in self._playbooks: pb = Playbook.load(playbook_path, variable_manager=self._variable_manager, loader=self._loader) self._inventory.set_playbook_basedir( os.path.dirname(playbook_path)) if self._tqm is None: # we are doing a listing entry = {'playbook': playbook_path} entry['plays'] = [] i = 1 plays = pb.get_plays() display.vv('%d plays in %s' % (len(plays), playbook_path)) for play in plays: if play._included_path is not None: self._loader.set_basedir(play._included_path) else: self._loader.set_basedir(pb._basedir) # clear any filters which may have been applied to the inventory self._inventory.remove_restriction() if play.vars_prompt: for var in play.vars_prompt: vname = var['name'] prompt = var.get("prompt", vname) default = var.get("default", None) private = var.get("private", True) confirm = var.get("confirm", False) encrypt = var.get("encrypt", None) salt_size = var.get("salt_size", None) salt = var.get("salt", None) if vname not in play.vars: if self._tqm: self._tqm.send_callback( 'v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt, default) play.vars[vname] = self._do_var_prompt( vname, private, prompt, encrypt, confirm, salt_size, salt, default) # Create a temporary copy of the play here, so we can run post_validate # on it without the templating changes affecting the original object. all_vars = self._variable_manager.get_vars( loader=self._loader, play=play) templar = Templar(loader=self._loader, variables=all_vars) new_play = play.copy() new_play.post_validate(templar) if self._options.syntax: continue if self._tqm is None: # we are just doing a listing entry['plays'].append(new_play) else: # make sure the tqm has callbacks loaded self._tqm.load_callbacks() self._tqm._unreachable_hosts.update( self._unreachable_hosts) # we are actually running plays for batch in self._get_serialized_batches(new_play): if len(batch) == 0: self._tqm.send_callback( 'v2_playbook_on_play_start', new_play) self._tqm.send_callback( 'v2_playbook_on_no_hosts_matched') break # restrict the inventory to the hosts in the serialized batch self._inventory.restrict_to_hosts(batch) # and run it... result = self._tqm.run(play=play) # check the number of failures here, to see if they're above the maximum # failure percentage allowed, or if any errors are fatal. If either of those # conditions are met, we break out, otherwise we only break out if the entire # batch failed failed_hosts_count = len( self._tqm._failed_hosts) + len( self._tqm._unreachable_hosts) if new_play.any_errors_fatal and failed_hosts_count > 0: break elif new_play.max_fail_percentage is not None and \ int((new_play.max_fail_percentage)/100.0 * len(batch)) > int((len(batch) - failed_hosts_count) / len(batch) * 100.0): break elif len(batch) == failed_hosts_count: break # clear the failed hosts dictionaires in the TQM for the next batch self._unreachable_hosts.update( self._tqm._unreachable_hosts) self._tqm.clear_failed_hosts() # if the last result wasn't zero or 3 (some hosts were unreachable), # break out of the serial batch loop if result not in (0, 3): break i = i + 1 # per play if entry: entrylist.append(entry) # per playbook # if the last result wasn't zero, break out of the playbook file name loop if result != 0: break if entrylist: return entrylist finally: if self._tqm is not None: self._cleanup() if self._options.syntax: display.display("No issues encountered") return result # TODO: this stat summary stuff should be cleaned up and moved # to a new method, if it even belongs here... display.banner("PLAY RECAP") hosts = sorted(self._tqm._stats.processed.keys()) for h in hosts: t = self._tqm._stats.summarize(h) display.display( u"%s : %s %s %s %s" % (hostcolor(h, t), colorize(u'ok', t['ok'], 'green'), colorize(u'changed', t['changed'], 'yellow'), colorize(u'unreachable', t['unreachable'], 'red'), colorize(u'failed', t['failures'], 'red')), screen_only=True) display.display( u"%s : %s %s %s %s" % (hostcolor(h, t, False), colorize(u'ok', t['ok'], None), colorize(u'changed', t['changed'], None), colorize(u'unreachable', t['unreachable'], None), colorize(u'failed', t['failures'], None)), log_only=True) display.display("", screen_only=True) # END STATS STUFF return result def _cleanup(self, signum=None, framenum=None): return self._tqm.cleanup() def _get_serialized_batches(self, play): ''' Returns a list of hosts, subdivided into batches based on the serial size specified in the play. ''' # make sure we have a unique list of hosts all_hosts = self._inventory.get_hosts(play.hosts) # check to see if the serial number was specified as a percentage, # and convert it to an integer value based on the number of hosts if isinstance(play.serial, string_types) and play.serial.endswith('%'): serial_pct = int(play.serial.replace("%", "")) serial = int((serial_pct / 100.0) * len(all_hosts)) else: if play.serial is None: serial = -1 else: serial = int(play.serial) # if the serial count was not specified or is invalid, default to # a list of all hosts, otherwise split the list of hosts into chunks # which are based on the serial size if serial <= 0: return [all_hosts] else: serialized_batches = [] while len(all_hosts) > 0: play_hosts = [] for x in range(serial): if len(all_hosts) > 0: play_hosts.append(all_hosts.pop(0)) serialized_batches.append(play_hosts) return serialized_batches def _do_var_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None): if sys.__stdin__.isatty(): if prompt and default is not None: msg = "%s [%s]: " % (prompt, default) elif prompt: msg = "%s: " % prompt else: msg = 'input for %s: ' % varname def do_prompt(prompt, private): if sys.stdout.encoding: msg = prompt.encode(sys.stdout.encoding) else: # when piping the output, or at other times when stdout # may not be the standard file descriptor, the stdout # encoding may not be set, so default to something sane msg = prompt.encode(locale.getpreferredencoding()) if private: return getpass.getpass(msg) return raw_input(msg) if confirm: while True: result = do_prompt(msg, private) second = do_prompt("confirm " + msg, private) if result == second: break display.display("***** VALUES ENTERED DO NOT MATCH ****") else: result = do_prompt(msg, private) else: result = None display.warning("Not prompting as we are not in interactive mode") # if result is false and default is not None if not result and default is not None: result = default if encrypt: result = do_encrypt(result, encrypt, salt_size, salt) # handle utf-8 chars result = to_unicode(result, errors='strict') return result
def _run_playbook(self, yamlfile, is_checksyntax=False): if not is_checksyntax : if self.options.flush_cache: self._flush_cache() self._loading_callback(yamlfile) # self._unreachable_hosts = dict() tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self.callback, ) check_for_controlpersist(C.ANSIBLE_SSH_EXECUTABLE) else : tqm = None try : pb = Playbook.load( yamlfile, variable_manager=self.variable_manager, loader=self.loader ) self.inventory.set_playbook_basedir(yamlfile) if tqm is not None : tqm.load_callbacks() tqm.send_callback('v2_playbook_on_start', pb) self.logger.debug(self.log_prefix + '任务开始执行') plays = pb.get_plays() for play in plays: if play._included_path is not None: self.loader.set_basedir(play._included_path) else: self.loader.set_basedir(pb._basedir) self.inventory.remove_restriction() all_vars = self.variable_manager.get_vars(loader=self.loader, play=play) templar = Templar(loader=self.loader, variables=all_vars) new_play = play.copy() new_play.post_validate(templar) if is_checksyntax or tqm is None: return True # tqm._unreachable_hosts.update(self._unreachable_hosts) batches = self._get_serialized_batches(new_play) if len(batches) == 0: tqm.send_callback('v2_playbook_on_play_start', new_play) tqm.send_callback('v2_playbook_on_no_hosts_matched') self.logger.debug(self.log_prefix + '任务开始执行,但没有匹配主机') # 需要写日志,需要写该模块 continue for batch in batches: self.inventory.restrict_to_hosts(batch) try : tqm.run(play) except Exception as e: print(e) pass # self._unreachable_hosts.update(tqm._unreachable_hosts) tqm.send_callback('v2_playbook_on_stats', tqm._stats) self.logger.debug(self.log_prefix + '任务执行完比') # self.host_list = self.inventory.get_hosts(play.hosts) tqm.cleanup() self.loader.cleanup_all_tmp_files() return True except Exception as e: print(e) if is_checksyntax : return False else : return False
class TestTaskQueueManagerCallbacks(unittest.TestCase): def setUp(self): inventory = MagicMock() variable_manager = MagicMock() loader = MagicMock() passwords = [] # Reset the stored command line args co.GlobalCLIArgs._Singleton__instance = None self._tqm = TaskQueueManager(inventory, variable_manager, loader, passwords) self._playbook = Playbook(loader) # we use a MagicMock to register the result of the call we # expect to `v2_playbook_on_call`. We don't mock out the # method since we're testing code that uses `inspect` to # look at that method's argspec and we want to ensure this # test is easy to reason about. self._register = MagicMock() def tearDown(self): # Reset the stored command line args co.GlobalCLIArgs._Singleton__instance = None def test_task_queue_manager_callbacks_v2_playbook_on_start(self): """ Assert that no exceptions are raised when sending a Playbook start callback to a current callback module plugin. """ register = self._register class CallbackModule(CallbackBase): """ This is a callback module with the current method signature for `v2_playbook_on_start`. """ CALLBACK_VERSION = 2.0 CALLBACK_TYPE = 'notification' CALLBACK_NAME = 'current_module' def v2_playbook_on_start(self, playbook): register(self, playbook) callback_module = CallbackModule() self._tqm._callback_plugins.append(callback_module) self._tqm.send_callback('v2_playbook_on_start', self._playbook) register.assert_called_once_with(callback_module, self._playbook) def test_task_queue_manager_callbacks_v2_playbook_on_start_wrapped(self): """ Assert that no exceptions are raised when sending a Playbook start callback to a wrapped current callback module plugin. """ register = self._register def wrap_callback(func): """ This wrapper changes the exposed argument names for a method from the original names to (*args, **kwargs). This is used in order to validate that wrappers which change par- ameter names do not break the TQM callback system. :param func: function to decorate :return: decorated function """ def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper class WrappedCallbackModule(CallbackBase): """ This is a callback module with the current method signature for `v2_playbook_on_start` wrapped in order to change the signature. """ CALLBACK_VERSION = 2.0 CALLBACK_TYPE = 'notification' CALLBACK_NAME = 'current_module' @wrap_callback def v2_playbook_on_start(self, playbook): register(self, playbook) callback_module = WrappedCallbackModule() self._tqm._callback_plugins.append(callback_module) self._tqm.send_callback('v2_playbook_on_start', self._playbook) register.assert_called_once_with(callback_module, self._playbook)