def execute_playbook(play_book, host_list=[]): host_list = host_list # since the API is constructed for CLI it expects certain options to always be set in the context object context.CLIARGS = ImmutableDict(connection='smart', module_path=None, forks=None, become=None, become_method=None, become_user=None, check=False, diff=False) sources = ','.join(host_list) if len(host_list) == 1: sources += ',' # initialize needed objects loader = DataLoader( ) # Takes care of finding and reading yaml, json and ini files passwords = dict(vault_pass='******') # Instantiate our ResultsCollectorJSONCallback for handling results as they come in. Ansible expects this to be one of its main display outlets results_callback = ResultsCollectorJSONCallback() inventory = InventoryManager(loader=loader, sources=sources) variable_manager = VariableManager(loader=loader, inventory=inventory) 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 ) pbex = PlaybookExecutor(playbooks=[play_book], inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords) playbook = Playbook.load(pbex._playbooks[0], variable_manager=variable_manager, loader=loader) play = playbook.get_plays()[0] # Actually run it try: 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 tqm.cleanup() if loader: loader.cleanup_all_tmp_files() # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
def main(): host_list = ['localhost', 'www.example.com', 'www.google.com'] # since the API is constructed for CLI it expects certain options to always be set in the context object context.CLIARGS = ImmutableDict(connection='smart', module_path=['/usr/share/ansible'], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False) # required for # https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory/manager.py#L204 sources = ','.join(host_list) if len(host_list) == 1: sources += ',' # initialize needed objects loader = DataLoader() passwords = dict() # create inventory and pass to var manager inventory = InventoryManager(loader=loader, sources=sources) variable_manager = VariableManager(loader=loader, 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, passwords=passwords, stdout_callback=callback, ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() if loader: loader.cleanup_all_tmp_files() print("UP ***********") for host, result in callback.host_ok.items(): print('{0} >>> {1}'.format(host, result._result['msg'])) print("FAILED *******") for host, result in callback.host_failed.items(): print('{0} >>> {1}'.format(host, result._result['msg'])) print("DOWN *********") for host, result in callback.host_unreachable.items(): print('{0} >>> {1}'.format(host, result._result['msg']))
class PlaybookRunner(): def __init__( self, playbook_files=['./site.yml'], inventory_sources=['hosts.sh'], vault_password=None, ): self.playbook_files = playbook_files self.inventory_sources = inventory_sources self.vault_password = vault_password self.loader = DataLoader() self.inventory = InventoryManager(loader=self.loader, sources=self.inventory_sources) self.results_callback = ResultsCallback() self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) def run(self): try: pbex = PlaybookExecutor( inventory=self.inventory, loader=self.loader, passwords={'vault_password': self.vault_password}, playbooks=self.playbook_files, variable_manager=self.variable_manager, ) tqm = pbex._tqm tqm._stdout_callback = self.results_callback pbex.run() # if tqm and hasattr(tqm, 'send_callback'): # tqm.send_callback('playbook_on_exception', exception=e) finally: # if hasattr(self.results_callback, 'results'): # print(json.dumps({ # 'results': self.results_callback.results # }, indent=2)) if tqm is not None: tqm.cleanup() if self.loader is not None: self.loader.cleanup_all_tmp_files() shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
def run_cmd(self): passwords = { 'conn_pass': "******", 'become_pass': "******" } loader = DataLoader() variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.pb_options) variable_manager.options_vars = load_options_vars(self.pb_options) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.pb_options.inventory) variable_manager.set_inventory(inventory) play_ds = self._play_ds(self.pb_options.name, self.pb_options.pattern) play = Play().load(play_ds, variable_manager=variable_manager, loader=loader) self._tqm = None try: self._tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.pb_options, passwords=passwords, # stdout_callback=CallbackWrap(), ) rc = self._tqm.run(play) detail = json.loads(self._tqm._stdout_callback._dump_results) print("json.loads.self._tqm._stdout_callback._dump_results") print(json.loads(self._tqm._stdout_callback._dump_results)) print("self._tqm._stdout_callback dir") print(dir(self._tqm._stdout_callback)) finally: if self._tqm: self._tqm.cleanup() if loader: loader.cleanup_all_tmp_files() return {'rc': rc, 'detail': detail}
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 AdHocRunner: """ ADHoc Runner接口 """ results_callback_class = AdHocResultCallback loader_class = DataLoader variable_manager_class = VariableManager options = get_default_options() default_options = get_default_options() def __init__(self, inventory, options=None): if options: self.options = options self.inventory = inventory self.loader = DataLoader() self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) @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 raise AnsibleError(err) def check_pattern(self, pattern): if not pattern: raise AnsibleError("Pattern `{}` is not valid!".format(pattern)) if not self.inventory.list_hosts("all"): raise AnsibleError("Inventory is empty.") if not self.inventory.list_hosts(pattern): raise AnsibleError("pattern: %s dose not match any hosts." % pattern) def clean_tasks(self, tasks): cleaned_tasks = [] for task in tasks: self.check_module_args(task['action']['module'], task['action'].get('args')) cleaned_tasks.append(task) return cleaned_tasks def set_option(self, k, v): kwargs = {k: v} self.options = self.options._replace(**kwargs) 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()
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 AdHocRunner: """ ADHoc Runner接口 """ results_callback_class = AdHocResultCallback results_callback = None loader_class = DataLoader variable_manager_class = VariableManager default_options = get_default_options() command_modules_choices = ('shell', 'raw', 'command', 'script', 'win_shell') def __init__(self, inventory, options=None): self.options = self.update_options(options) self.inventory = inventory self.loader = DataLoader() self.variable_manager = VariableManager( loader=self.loader, inventory=self.inventory ) def get_result_callback(self, file_obj=None): return self.__class__.results_callback_class() @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 raise AnsibleError(err) def check_pattern(self, pattern): if not pattern: raise AnsibleError("Pattern `{}` is not valid!".format(pattern)) if not self.inventory.list_hosts("all"): raise AnsibleError("Inventory is empty.") if not self.inventory.list_hosts(pattern): raise AnsibleError( "pattern: %s dose not match any hosts." % pattern ) def clean_args(self, module, args): if not args: return '' if module not in self.command_modules_choices: return args if isinstance(args, str): if args.startswith('executable='): _args = args.split(' ') executable, command = _args[0].split('=')[1], ' '.join(_args[1:]) args = {'executable': executable, '_raw_params': command} else: args = {'_raw_params': args} return args else: return args def clean_tasks(self, tasks): cleaned_tasks = [] for task in tasks: module = task['action']['module'] args = task['action'].get('args') cleaned_args = self.clean_args(module, args) task['action']['args'] = cleaned_args self.check_module_args(module, cleaned_args) cleaned_tasks.append(task) return cleaned_tasks def update_options(self, options): if options and isinstance(options, dict): options = self.__class__.default_options._replace(**options) else: options = self.__class__.default_options return options 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) 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=self.results_callback, passwords=self.options.passwords, ) try: tqm.run(play) return self.results_callback except Exception as e: raise AnsibleError(e) finally: tqm.cleanup() self.loader.cleanup_all_tmp_files()
def run(self): """Run the Application""" # Since the API is constructed for CLI it expects certain options to # always be set in the context object context.CLIARGS = ImmutableDict( connection="smart", module_path=[get_path("./modules"), "/usr/share/ansible"], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False, verbosity=3, ) # 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 if self.args.measurement: results_callback = MeasurementsResultCallback( plugins=self._plugins) else: results_callback = ResultCallback(plugins=self._plugins) # Create inventory, use path to host config file as source or hosts in a # comma separated string inventory = InventoryManager(loader=loader, sources=self._sources) # 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) # Instantiate task queue manager, which takes care of forking and setting # up all objects to iterate over host list and tasks # IMPORTANT: This also adds library dirs paths to the module loader # IMPORTANT: and so it must be initialized before calling `Play.load()`. 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 ) # 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="all", gather_facts="yes", tasks=self.playbook_tasks(), ) # Create play object, playbook objects use .load instead of init or new # methods, this will also automatically create the task objects from the # info provided in play_source play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # Actually run it try: tqm.load_callbacks() tqm.run(play) tqm.send_callback( "v2_playbook_on_stats", tqm._stats, # pylint: disable=protected-access ) finally: # We always need to cleanup child procs and the structures we use to # communicate with them tqm.cleanup() if loader: loader.cleanup_all_tmp_files() # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) # pylint: disable=no-member if tqm is not None: tqm.cleanup()
class YoRunner(object): Options = namedtuple("Options", [ 'connection', 'module_path', 'private_key_file', "remote_user", 'timeout', 'forks', 'become', 'become_method', 'become_user', 'check', 'extra_vars', ]) 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.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.extra_vars = extra_vars self.variable_manager.options_vars = load_options_vars(self.options) self.passwords = passwords or {} self.inventory = YoInventory(hosts) self.variable_manager.set_inventory(self.inventory) self.tasks = [] self.play_source = None self.play = None self.runner = None self.timestamp = str(time.time()) self.filename = FILENAME % (self.timestamp, '') self.have_script = 0 def set_callback(self, callback): self.results_callback = callback @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 task_add(self, task_tuple): for task in task_tuple: if not self.check_module_args(task.module, task.args): return if task.module == u'script': self.have_script = 1 script = Script.objects.filter(id=task.args) if os.path.exists(self.filename): os.remove(self.filename) script_name = FILENAME % (self.timestamp, '-' + str(script.get().id)) output = open(script_name, 'w') output.writelines(script.get().formatScript()) output.close() if self.have_script == 1: self.tasks.append( dict(action=dict( module=task.module, args=script_name, ))) else: self.tasks.append( dict(action=dict( module=task.module, args=task.args, ))) def run( self, task_tuple, ): # pattern='all'): """ :param task_tuple: (('shell', 'ls'), ('ping', '')) :param pattern: :param timestamp: :return: """ self.task_add(task_tuple) self.play_source = dict(name=self.timestamp, hosts='all', 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) finally: if self.runner: self.runner.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() if self.have_script: self.cleanup_script() def cleanup_script(self): # if os.path.exists(self.filename): # os.remove(self.filename) # return self.filename for name in glob.glob(self.filename + '*'): if os.path.exists(name): print(name) os.remove(name)
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 ) # Actually run it try: 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 tqm.cleanup() if loader: loader.cleanup_all_tmp_files() # play_source = [] # with open("./mysql.yml") as f: # data = yaml.load(f, yaml.SafeLoader) # if isinstance(data, list): # play_source.extend(data) # else: # play_source.append(data) # for play_book in play_source: # play = Play().load(play_book, variable_manager=variable_manager, loader=loader) # results_callback = ResultCallback() # tqm = None # try: # tqm = TaskQueueManager(
class AnsibleTask: def __init__(self, hosts=None, extra_vars=None): self.hosts = hosts self.__validate() self.hosts_file = None self.__generate_hosts_file() Options = namedtuple('Options', [ 'connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff', 'host_key_checking', 'listhosts', 'listtasks', 'listtags', 'syntax' ]) self.options = Options( connection='ssh', module_path=None, forks=10, become=None, become_method=None, become_user=None, check=False, diff=False, host_key_checking=False, listhosts=None, listtasks=None, listtags=None, syntax=None ) self.loader = DataLoader() self.passwords = dict(vault_pass='******') self.inventory = InventoryManager(loader=self.loader, sources=[self.hosts_file]) self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) self.results_callback = AnsibleTaskResultCallback() # 结果对象 self.results_raw = {'success': {}, 'failed': {}, 'unreachable': {}} if extra_vars: self.variable_manager.extra_vars = extra_vars # 用于读取host 文件的,一般用不到 def __generate_hosts_file(self): self.hosts_file = tempfile.mktemp() with open(self.hosts_file, 'w+', encoding='utf-8') as file: hosts = [] for host in self.hosts: hosts.append(f'{host.host} {str(host)}') file.write('\n'.join(hosts)) def __validate(self): assert self.hosts, 'hosts不能为空' assert isinstance(self.hosts, list), 'hosts 应为 list' for host in self.hosts: assert isinstance(host, AnsibleHost), 'host 类型必须为 AnsibleHost' def exec_run(self, module_name, module_args=None): play_source = dict( name="Ops Ansible Play", hosts='all', gather_facts='no', tasks=[dict(action=dict(module=module_name, args=module_args))] if module_args else [dict(action=dict(module=module_name))] ) play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) self.results_callback = AnsibleTaskResultCallback() 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 ) tqm.run(play) except Exception as e: raise e finally: tqm.cleanup() self.loader.cleanup_all_tmp_files() def exec_playbook(self, playbooks): playbook = PlaybookExecutor( playbooks=playbooks, inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords ) setattr(getattr(playbook, '_tqm'), '_stdout_callback', self.results_callback) playbook.run() playbook._tqm.cleanup() @property def get_result(self): for host, result in self.results_callback.host_ok.items(): self.results_raw['success'][host] = ( result._result, {'code': 0} ) for host, result in self.results_callback.host_failed.items(): self.results_raw['failed'][host] = ( result._result, {'code': 1} ) for host, result in self.results_callback.host_unreachable.items(): self.results_raw['unreachable'][host] = ( result._result, {'code': 1} ) return self.results_raw # __del__ 被称为析构方法,在程序执行完后,python垃圾回收器,会自动执行 def __del__(self): if self.hosts_file: os.remove(self.hosts_file)
class CopyAdHocRunner: """ ADHoc Runner接口 """ results_callback_class = AdHocResultCallback loader_class = DataLoader variable_manager_class = VariableManager options = get_default_options() default_options = get_default_options() def __init__(self, inventory, options=None): if options: self.options = options self.inventory = inventory self.loader = DataLoader() self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) def set_option(self, k, v): kwargs = {k: v} self.options = self.options._replace(**kwargs) 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 :return: """ results_callback = self.results_callback_class() play_source = dict(name=play_name, hosts=pattern, gather_facts=gather_facts, tasks=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, ) logger.debug("Get inventory matched hosts: {}".format( self.inventory.get_matched_hosts(pattern))) try: tqm.run(play) return results_callback except Exception as e: raise AnsibleError(e) finally: tqm.cleanup() self.loader.cleanup_all_tmp_files()
class AdHocRunner: results_callback_class = ResultCallback # results_callback = None # loader_class = DataLoader # variable_manager_class = VariableManager # default_options = get_default_options() def __init__(self, inventory): self.options = get_default_options() self.loader = DataLoader() self.inventory = InventoryManager(loader=self.loader, sources=['/etc/ansible/hosts']) self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) def get_result_callback(self, file_obj=None): return self.__class__.results_callback_class(file_obj=file_obj) def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no', file_obj=None): self.results_callback = self.get_result_callback(file_obj) play_source = dict(name=play_name, hosts=pattern, gather_facts=gather_facts, tasks=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=self.results_callback, passwords=self.options.passwords, ) try: result = tqm.run(play) # return self.results_callback except Exception as e: raise AnsibleError(e) finally: tqm.cleanup() self.loader.cleanup_all_tmp_files() results_raw = {} results_raw['success'] = {} results_raw['failed'] = {} results_raw['unreachable'] = {} for host, result in self.results_callback.host_ok.items(): results_raw['success'][host] = json.dumps(result._result) for host, result in self.results_callback.host_failed.items(): results_raw['failed'][host] = result._result['msg'] for host, result in self.results_callback.host_unreachable.items(): results_raw['unreachable'][host] = result._result['msg'] print(results_raw)
class AnsibleRunner(object): def __init__(self, hosts=C.DEFAULT_HOST_LIST, module_name=C.DEFAULT_MODULE_NAME, module_args=C.DEFAULT_MODULE_ARGS, forks=C.DEFAULT_FORKS, timeout=C.DEFAULT_TIMEOUT, pattern="all", remote_user=C.DEFAULT_REMOTE_USER, module_path=None, connection_type="smart", become=None, become_method=None, become_user=None, check=False, passwords=None, extra_vars=None, private_key_file=None, listtags=False, listtasks=False, listhosts=False, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, verbosity=None, syntax=False, redisKey=None, logId=None): self.Options = namedtuple("Options", [ 'listtags', 'listtasks', 'listhosts', 'syntax', 'connection', 'module_path', 'forks', 'remote_user', 'private_key_file', 'timeout', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity', 'check', 'extra_vars', 'diff' ]) self.results_raw = {} self.pattern = pattern self.module_name = module_name self.module_args = module_args self.gather_facts = 'no' self.options = self.Options(listtags=listtags, listtasks=listtasks, listhosts=listhosts, syntax=syntax, timeout=timeout, connection=connection_type, module_path=module_path, forks=forks, remote_user=remote_user, private_key_file=private_key_file, ssh_common_args=ssh_common_args or "", ssh_extra_args=ssh_extra_args or "", sftp_extra_args=sftp_extra_args, scp_extra_args=scp_extra_args, become=become, become_method=become_method, become_user=become_user, verbosity=verbosity, extra_vars=extra_vars or [], check=check, diff=False) self.redisKey = redisKey self.logId = logId self.loader = DataLoader() self.inventory = CustomInventory(resource=hosts) self.variable_manager = VariableManager(self.loader, self.inventory) self.variable_manager.extra_vars = load_extra_vars( loader=self.loader, options=self.options) self.variable_manager.options_vars = load_options_vars( self.options, "") self.passwords = passwords or {} def run_module(self, host_list, module_name, module_args): """ :param host_list: ßß :param module_name: ansible 模块名称 (-m) :param module_args: ansible 模块参数 (-a) :return: """ self.callback = ModuleResultsCollector() play_source = dict( name="Ansible Ad-hoc", hosts=host_list, gather_facts=self.gather_facts, tasks=[dict(action=dict(module=module_name, args=module_args))]) play = Play().load(play_source, loader=self.loader, variable_manager=self.variable_manager) 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) tqm._stdout_callback = self.callback C.HOST_KEY_CHECKING = False # 关闭第一次使用ansible连接客户端是输入命令 tqm.run(play) except Exception as err: print err finally: if tqm is not None: tqm.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() def run_playbook(self, host_list, playbook_path, extra_vars=dict()): """ run ansible palybook :param host_list: --limit 参数 :param playbook_path: playbook的路径 :param extra_vars: :return: """ try: self.callback = PlayBookResultsCollector() self.variable_manager.extra_vars = extra_vars self.inventory.subset(host_list) executor = PlaybookExecutor( playbooks=[playbook_path], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, ) executor._tqm._stdout_callback = self.callback C.HOST_KEY_CHECKING = False # 关闭第一次使用ansible连接客户端时输入命令 C.DEPRECATION_WARNINGS = False C.RETRY_FILES_ENABLED = False executor.run() except Exception as err: print err return False def get_module_result(self): """ 获取module执行结果 :return: """ self.results_raw = {'success': {}, 'failed': {}, 'unreachable': {}} for host, result in self.callback.host_ok.items(): self.results_raw['success'][host] = result._result['stdout'] for host, result in self.callback.host_failed.items(): self.results_raw['failed'][host] = result._result['stderr'] for host, result in self.callback.host_unreachable.items(): self.results_raw['unreachable'][host] = result._result['msg'] return json.dumps(self.results_raw) def get_playbook_result(self): """ 获取playbook的执行结果 :return: """ self.results_raw = { 'skipped': {}, 'failed': {}, 'ok': {}, "status": {}, 'unreachable': {}, "changed": {}, } for host, results in self.callback.task_ok.items(): for result in results: if not self.results_raw['ok'].get(host): self.results_raw['ok'][host] = dict() task_name = result.task_name _result = result._result if not self.results_raw['ok'][host].get(task_name): self.results_raw['ok'][host][task_name] = list() if task_name != 'Gathering Facts': self.results_raw['ok'][host][task_name] = ( _result['stdout']) for host, results in self.callback.task_failed.items(): for result in results: if not self.results_raw['failed'].get(host): self.results_raw['failed'][host] = dict() task_name = result.task_name _result = result._result if not self.results_raw['failed'][host].get(task_name): self.results_raw['failed'][host][task_name] = list() if task_name != 'Gathering Facts': self.results_raw['failed'][host][task_name] = ( _result['stderr']) for host, results in self.callback.task_unreachable.items(): for result in results: if not self.results_raw['unreachable'].get(host): self.results_raw['unreachable'][host] = dict() task_name = result.task_name _result = result._result if not self.results_raw['unreachable'][host].get(task_name): self.results_raw['unreachable'][host][task_name] = list() self.results_raw['unreachable'][host][task_name] = ( _result['msg']) for host, results in self.callback.task_changed.items(): for result in results: if not self.results_raw['changed'].get(host): self.results_raw['changed'][host] = dict() task_name = result.task_name _result = result._result if not self.results_raw['changed'][host].get(task_name): self.results_raw['changed'][host][task_name] = list() self.results_raw['changed'][host][task_name] = ( _result['task_name']) for host, results in self.callback.task_skipped.items(): for result in results: if not self.results_raw['skipped'].get(host): self.results_raw['skipped'][host] = dict() task_name = result.task_name _result = result._result if not self.results_raw['skipped'][host].get(task_name): self.results_raw['skipped'][host][task_name] = list() self.results_raw['skipped'][host][task_name] = ( _result['task_name']) for host, result in self.callback.task_status.items(): self.results_raw['status'][host] = result self.results_raw['status_no_hosts'] = self.callback.status_no_hosts return json.dumps(self.results_raw)
def main(): host_list = ['172.17.0.10'] # since the API is constructed for CLI it expects certain options to always be set in the context object context.CLIARGS = ImmutableDict(connection='smart', private_key_file="~/.ssh/id_rsa", forks=10, become=None, become_method=None, become_user=None, check=False, diff=False, verbosity=0) # required for # https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory/manager.py#L204 sources = ','.join(host_list) if len(host_list) == 1: sources += ',' # initialize needed objects loader = DataLoader( ) # Takes care of finding and reading yaml, json and ini files passwords = dict(vault_pass='') # Instantiate our ResultsCollectorJSONCallback for handling results as they come in. Ansible expects this to be one of its main display outlets results_callback = ResultsCollectorJSONCallback() # create inventory, use path to host config file as source or hosts in a comma separated string inventory = InventoryManager(loader=loader, sources=sources) # 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) # instantiate task queue manager, which takes care of forking and setting up all objects to iterate over host list and tasks # IMPORTANT: This also adds library dirs paths to the module loader # IMPORTANT: and so it must be initialized before calling `Play.load()`. 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 ) play_sources = [] with open('./mysql.yml') as f: data = yaml.load(f, yaml.SafeLoader) if isinstance(data, list): play_sources.extend(data) else: play_source.append(data) for play_book in play_sources: play_book['hosts'] = host_list play = Play().load(play_book, variable_manager=variable_manager, loader=loader) # Actually run it try: 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 tqm.cleanup() if loader: loader.cleanup_all_tmp_files() # Create play object, playbook objects use .load instead of init or new methods, # this will also automatically create the task objects from the info provided in play_source # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) print("UP ***********") for host, result in results_callback.host_ok.items(): print('{0} >>> {1}'.format(host, result._result['stdout'])) print("FAILED *******") for host, result in results_callback.host_failed.items(): print('{0} >>> {1}'.format(host, result._result['msg'])) print("DOWN *********") for host, result in results_callback.host_unreachable.items(): print('{0} >>> {1}'.format(host, result._result['msg']))
class MyApi(object): def __init__(self, resource=None, sources=None, *args, **kwargs): self.resource = resource self.sources = sources self.inventory = None self.variable_manager = None self.loader = None self.options = None self.passwords = None self.callback = None self.timeout = kwargs.get('timeout', '') if kwargs.get('timeout', '') else 10 self.forks = kwargs.get('forks', '') if kwargs.get('forks', '') else 10 self.connection = kwargs.get('connection', '') if kwargs.get( 'connection', '') else 'smart' self.become_user = kwargs.get('become_user', '') if kwargs.get( 'become_user', '') else 'root' self.__initializeData() self.results_raw = {} def __initializeData(self): """ 初始化 ansible 配置参数 如需其他参数, 可自行添加 """ # 定义选项 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', 'listhosts', 'listtasks', 'listtags', 'diff', 'syntax' ]) # 定义选项 become=u'yes', 开启beome,默认关闭 self.options = Options(connection=self.connection, module_path=None, forks=self.forks, timeout=self.timeout, 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='sudo', become_user=self.become_user, ask_value_pass=False, verbosity=None, check=False, listhosts=False, listtasks=False, listtags=False, diff=False, syntax=False) # 用来加载解析yaml文件或JSON内容, 并且支持vault的解密 self.loader = DataLoader() # 默认密码, 主机未定义密码的时候才生效 #self.passwords = dict(sshpass=None, becomepass=None) self.passwords = dict(vault_pass='******') # 加载 host 列表 self.inventory = MyInventory(self.resource, self.loader, self.sources).inventory # 初始化变量, 包括主机、组、扩展等变量 self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) def run(self, host_list, module_name, module_args=None): """ 从 andible ad-hoc 运行模块. module_name: ansible 模块名称 (-m) module_args: ansible 模块参数 (-a) """ # 创建任务 play_source = dict( name="JK 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) # 实际运行 # TaskQueueManager 是创建进程池, 负责输出结果和多进程间数据结构或者队列的共享协作 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, stdout_callback=self.callback, ) tqm.run(play) finally: if tqm is not None: tqm.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) def run_playbook(self, host_list, playbook_path): """ 执行 ansible palybook """ try: self.callback = ResultsCollector() # playbook的路径 pbfiles = playbook_path.split() for pbfile in pbfiles: if not os.path.exists(pbfile): print('[INFO] The [%s] playbook does not exist' % pbfile) sys.exit() # 额外的参数 sudoers.yml以及模板中的参数,它对应ansible-playbook test.yml --extra-vars "host='aa' name='cc'" extra_vars = {} extra_vars['host_list'] = host_list self.variable_manager.extra_vars = extra_vars # actually run it executor = PlaybookExecutor( playbooks=pbfiles, inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, ) executor._tqm._stdout_callback = self.callback executor.run() except Exception as e: jklog.error(e) def get_result(self): # 获取结束回调 self.result_all = {'success': {}, 'failed': {}, 'unreachable': {}} for host, results in self.callback.status_ok.items(): for result in results: if not self.result_all['success'].get(host): self.result_all['success'][host] = dict() task_name = result.task_name _result = result._result # jklog.debug(_result) if not self.result_all['success'][host].get(task_name): self.result_all['success'][host][task_name] = list() if task_name == 'copy': self.result_all['success'][host][task_name] = ( _result['invocation']) else: self.result_all['success'][host][task_name] = ( _result['stdout']) for host, results in self.callback.status_fail.items(): for result in results: if not self.result_all['failed'].get(host): self.result_all['failed'][host] = dict() task_name = result.task_name _result = result._result # jklog.debug(_result) if not self.result_all['failed'][host].get(task_name): self.result_all['failed'][host][task_name] = list() if task_name == 'copy': self.result_all['failed'][host][task_name] = ( _result['msg']) else: self.result_all['failed'][host][task_name] = ( _result['stdout']) for host, results in self.callback.status_unreachable.items(): for result in results: if not self.result_all['unreachable'].get(host): self.result_all['unreachable'][host] = dict() task_name = result.task_name _result = result._result # jklog.debug(_result) if not self.result_all['unreachable'][host].get(task_name): self.result_all['unreachable'][host][task_name] = list() self.result_all['unreachable'][host][task_name].append( _result['msg']) return self.result_all def get_json(self): d = self.get_result() data = json.dumps(d) return data
class AdHocRunner: """ ADHoc Runner接口 """ results_callback_class = AdHocResultCallback results_callback = None loader_class = DataLoader variable_manager_class = VariableManager default_options = get_default_options() options = None command_modules_choices = ('shell', 'raw', 'command', 'script') def __init__(self, inventory, options=None, stdout=None): self.options = self.get_options(options) self.inventory = inventory self.stdout = stdout self.loader = DataLoader() self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) self.set_result_callback() def get_result_callback(self): display = None if self.stdout: display = LogFileDisplay(self.stdout) return self.results_callback_class(display=display) def set_result_callback(self): self.results_callback = self.get_result_callback() @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 raise AnsibleError(err) def is_command_task(self, tasks): if len(tasks) != 1: return False if tasks[0].get("action", {}).get("module") in self.command_modules_choices: return True return False def check_pattern(self, pattern): if not pattern: raise AnsibleError("Pattern `{}` is not valid!".format(pattern)) if not self.inventory.list_hosts("all"): raise AnsibleError("Inventory is empty.") if not self.inventory.list_hosts(pattern): raise AnsibleError("pattern: %s dose not match any hosts." % pattern) def clean_tasks(self, tasks): cleaned_tasks = [] for task in tasks: module = task['action']['module'] args = task['action'].get('args') self.check_module_args(module, args) cleaned_tasks.append(task) return cleaned_tasks def get_options(self, options): _options = self.default_options if options and isinstance(options, dict): _options = _options._replace(**options) return _options def update_options(self, options): if options and isinstance(options, dict): self.options = self.options._replace(**options) 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) 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=self.results_callback, passwords=self.options.passwords, ) msg = ("Get matched hosts: {}".format( self.inventory.get_matched_hosts(pattern))) try: tqm.send_callback('on_playbook_start', play.name) self.results_callback.display(msg) tqm.run(play) return self.results_callback.results except Exception as e: raise AnsibleError(e) finally: tqm.send_callback('v2_playbook_on_stats', tqm._stats) tqm.send_callback('on_playbook_end', play.name) tqm.cleanup() self.loader.cleanup_all_tmp_files()
class PlaybookRunner(object): """ The plabybook API. """ def __init__( self, hosts=C.DEFAULT_HOST_LIST, # a list or dynamic-hosts, # default is /etc/ansible/hosts playbook_path=None, # * a playbook file forks=C.DEFAULT_FORKS, listtags=False, listtasks=False, listhosts=False, syntax=False, module_path=None, remote_user='******', timeout=C.DEFAULT_TIMEOUT, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=True, become_method=None, become_user="******", verbosity=None, extra_vars=None, connection_type="ssh", passwords=None, private_key_file=C.DEFAULT_PRIVATE_KEY_FILE, remote_pass=C.DEFAULT_REMOTE_PASS, remote_port=None, check=False): C.RETRY_FILES_ENABLED = False self.callbackmodule = CallbackModule() if playbook_path is None or not os.path.exists(playbook_path): raise AnsibleError("Not Found the playbook file: %s." % playbook_path) self.playbook_path = playbook_path self.loader = DataLoader() self.variable_manager = VariableManager() self.passwords = passwords or {} # save host to file if not os.path.exists(os.path.join(base_dir, "tmp_inventory")): os.mkdir(os.path.join(base_dir, "tmp_inventory")) self.file_name = os.path.join(base_dir, "tmp_inventory", "tmp_host_{0}".format(time.time())) with open(self.file_name, 'w') as f: f.write("\n".join(hosts)) self.passwords = passwords or {} self.inventory = InventoryManager(loader=self.loader, sources=self.file_name) self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) self.options = Options(listtags=listtags, listtasks=listtasks, listhosts=listhosts, syntax=syntax, timeout=timeout, connection=connection_type, module_path=module_path, forks=forks, remote_user=remote_user, remote_pass=remote_pass, remote_port=remote_port, private_key_file=private_key_file, ssh_common_args=ssh_common_args or "", ssh_extra_args=ssh_extra_args or "", sftp_extra_args=sftp_extra_args, scp_extra_args=scp_extra_args, become=become, become_method=become_method, become_user=become_user, verbosity=verbosity, extra_vars=extra_vars or [], check=check, diff=False) self.runner = PlaybookExecutor(playbooks=[self.playbook_path], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords) if self.runner._tqm: self.runner._tqm._stdout_callback = self.callbackmodule def run(self): if not self.inventory.list_hosts("all"): raise AnsibleError("Inventory is empty.") try: self.runner.run() return self.callbackmodule.output except Exception as e: raise Exception(e) finally: if self.loader: self.loader.cleanup_all_tmp_files() if os.path.exists(self.file_name): os.remove(self.file_name)
class AdHocRunner: """ ADHoc Runner接口 """ results_callback_class = AdHocResultCallback results_callback = None loader_class = DataLoader variable_manager_class = VariableManager default_options = get_default_options() def __init__(self, inventory, options=None): self.options = self.update_options(options) self.inventory = inventory self.loader = DataLoader() self.variable_manager = VariableManager( loader=self.loader, inventory=self.inventory ) def get_result_callback(self, file_obj=None): return self.__class__.results_callback_class(file_obj=file_obj) @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 raise AnsibleError(err) def check_pattern(self, pattern): if not pattern: raise AnsibleError("Pattern `{}` is not valid!".format(pattern)) if not self.inventory.list_hosts("all"): raise AnsibleError("Inventory is empty.") if not self.inventory.list_hosts(pattern): raise AnsibleError( "pattern: %s dose not match any hosts." % pattern ) def clean_tasks(self, tasks): cleaned_tasks = [] for task in tasks: self.check_module_args(task['action']['module'], task['action'].get('args')) cleaned_tasks.append(task) return cleaned_tasks def update_options(self, options): if options and isinstance(options, dict): options = self.__class__.default_options._replace(**options) else: options = self.__class__.default_options return options def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no', file_obj=None): """ :param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ] :param pattern: all, *, or others :param play_name: The play name :param gather_facts: :param file_obj: logging to file_obj :return: """ self.check_pattern(pattern) self.results_callback = self.get_result_callback(file_obj) 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=self.results_callback, passwords=self.options.passwords, ) print("Get matched hosts: {}".format( self.inventory.get_matched_hosts(pattern) )) try: tqm.run(play) return self.results_callback except Exception as e: raise AnsibleError(e) finally: tqm.cleanup() self.loader.cleanup_all_tmp_files()
class YoRunner(object): Options = namedtuple("Options", [ 'connection', 'module_path', 'private_key_file', "remote_user", 'timeout', 'forks', 'become', 'become_method', 'become_user', 'check', 'extra_vars', ] ) 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.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.extra_vars = extra_vars self.variable_manager.options_vars = load_options_vars(self.options) self.passwords = passwords or {} self.inventory = YoInventory(hosts) self.variable_manager.set_inventory(self.inventory) self.tasks = [] self.play_source = None self.play = None self.runner = None self.timestamp = str(time.time()) self.filename = FILENAME%(self.timestamp,'') self.have_script = 0 def set_callback(self,callback): self.results_callback=callback @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 task_add(self,task_tuple): for task in task_tuple: if not self.check_module_args(task.module,task.args): return if task.module == u'script': self.have_script = 1 script = Script.objects.filter(id=task.args) if os.path.exists(self.filename): os.remove(self.filename) script_name = FILENAME % (self.timestamp, '-' + str(script.get().id)) output = open(script_name, 'w') output.writelines(script.get().formatScript()) output.close() if self.have_script == 1: self.tasks.append( dict(action=dict( module=task.module, args=script_name, )) ) else: self.tasks.append( dict(action=dict( module=task.module, args=task.args, )) ) def run(self, task_tuple,):# pattern='all'): """ :param task_tuple: (('shell', 'ls'), ('ping', '')) :param pattern: :param timestamp: :return: """ self.task_add(task_tuple) self.play_source = dict( name=self.timestamp, hosts='all', 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) finally: if self.runner: self.runner.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() if self.have_script: self.cleanup_script() def cleanup_script(self): # if os.path.exists(self.filename): # os.remove(self.filename) # return self.filename for name in glob.glob(self.filename+'*'): if os.path.exists(name): print(name) os.remove(name) # 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
def main(): host_list = ['localhost', 'www.example.com', 'www.google.com'] # since the API is constructed for CLI it expects certain options to always be set in the context object context.CLIARGS = ImmutableDict( connection='smart', module_path=['/to/mymodules', '/usr/share/ansible'], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False) # required for # https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory/manager.py#L204 sources = ','.join(host_list) if len(host_list) == 1: sources += ',' # initialize needed objects loader = DataLoader( ) # Takes care of finding and reading yaml, json and ini files passwords = dict(vault_pass='******') # Instantiate our ResultsCollectorJSONCallback for handling results as they come in. Ansible expects this to be one of its main display outlets results_callback = ResultsCollectorJSONCallback() # create inventory, use path to host config file as source or hosts in a comma separated string inventory = InventoryManager(loader=loader, sources=sources) # 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) # instantiate task queue manager, which takes care of forking and setting up all objects to iterate over host list and tasks # IMPORTANT: This also adds library dirs paths to the module loader # IMPORTANT: and so it must be initialized before calling `Play.load()`. 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 ) # 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=host_list, gather_facts='no', tasks=[ dict(action=dict(module='shell', args='ls'), register='shell_out'), dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))), dict( action=dict(module='command', args=dict( cmd='/usr/bin/uptime'))), ]) # Create play object, playbook objects use .load instead of init or new methods, # this will also automatically create the task objects from the info provided in play_source play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # Actually run it try: 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 tqm.cleanup() if loader: loader.cleanup_all_tmp_files() # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) print("UP ***********") for host, result in results_callback.host_ok.items(): print('{0} >>> {1}'.format(host, result._result['stdout'])) print("FAILED *******") for host, result in results_callback.host_failed.items(): print('{0} >>> {1}'.format(host, result._result['msg'])) print("DOWN *********") for host, result in results_callback.host_unreachable.items(): print('{0} >>> {1}'.format(host, result._result['msg']))
class Runner(object): """ 仿照ansible1.9 的python API,制作的ansible2.0 API的简化版本。 参数说明: inventory:: 仓库对象,可以是列表,逗号间隔的ip字符串,可执行文件. 默认/etc/ansible/hosts module_name:: 指定要使用的模块 module_args:: 模块参数 forks:: 并发数量, 默认5 timeout:: 连接等待超时时间,默认10秒 pattern:: 模式匹配,指定要连接的主机名, 默认all remote_user:: 指定连接用户, 默认root private_key_files:: 指定私钥文件 """ def __init__( self, hosts=C.DEFAULT_HOST_LIST, module_name=C.DEFAULT_MODULE_NAME, # * command module_args=C.DEFAULT_MODULE_ARGS, # * 'cmd args' forks=C.DEFAULT_FORKS, # 5 timeout=C.DEFAULT_TIMEOUT, # SSH timeout = 10s pattern="all", # all 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 ): # storage & defaults self.pattern = pattern self.loader = DataLoader() self.module_name = module_name self.module_args = module_args self.check_module_args() self.gather_facts = 'no' self.resultcallback = ResultCallback() self.options = 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, diff=False ) self.inventory = MyInventory(host_list=hosts) self.variable_manager = VariableManager(self.loader, self.inventory) self.variable_manager.extra_vars = load_extra_vars(loader=self.loader, options=self.options) self.variable_manager.options_vars = load_options_vars(self.options, "") self.passwords = passwords or {} self.play_source = dict( name="Ansible Ad-hoc", hosts=self.pattern, gather_facts=self.gather_facts, tasks=[dict(action=dict( module=self.module_name, args=self.module_args))] ) 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.resultcallback ) # ** end __init__() ** def run(self): 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) finally: if self.runner: self.runner.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() return self.resultcallback.result_q def check_module_args(self): if self.module_name in C.MODULE_REQUIRE_ARGS and not self.module_args: err = "No argument passed to '%s' module." % self.module_name raise AnsibleError(err)
class Runner(object): """ 仿照ansible1.9 的python API,制作的ansible2.0 API的简化版本。 参数说明: inventory:: 仓库对象,可以是列表,逗号间隔的ip字符串,可执行文件. 默认/etc/ansible/hosts module_name:: 指定要使用的模块 module_args:: 模块参数 forks:: 并发数量, 默认5 timeout:: 连接等待超时时间,默认10秒 pattern:: 模式匹配,指定要连接的主机名, 默认all remote_user:: 指定连接用户, 默认root private_key_files:: 指定私钥文件 """ def __init__( self, hosts=C.DEFAULT_HOST_LIST, module_name=C.DEFAULT_MODULE_NAME, # * command module_args=C.DEFAULT_MODULE_ARGS, # * 'cmd args' forks=C.DEFAULT_FORKS, # 5 timeout=C.DEFAULT_TIMEOUT, # SSH timeout = 10s pattern="all", # all 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=C.DEFAULT_PRIVATE_KEY_FILE, remote_pass=C.DEFAULT_REMOTE_PASS, remote_port=None): # storage & defaults self.pattern = pattern self.loader = DataLoader() self.module_name = module_name self.module_args = module_args self.check_module_args() self.gather_facts = 'no' self.resultcallback = ResultCallback() self.options = Options(connection=connection_type, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, module_path=module_path, forks=forks, become=become, become_method=become_method, become_user=become_user, check=check, remote_user=remote_user, private_key_file=private_key_file, remote_port=remote_port, verbosity=None, diff=False) # save host to file if not os.path.exists(os.path.join(base_dir, "tmp_inventory")): os.mkdir(os.path.join(base_dir, "tmp_inventory")) self.file_name = os.path.join(base_dir, "tmp_inventory", "tmp_host_{0}".format(time.time())) with open(self.file_name, 'w') as f: f.write("[all]\n") f.write("\n".join(hosts)) f.write("\n") if remote_pass: f.write("""[all:vars] ansible_connection=ssh ansible_user={0} ansible_pass={1}""".format(remote_user, remote_pass)) self.passwords = passwords or {} self.inventory = InventoryManager(loader=self.loader, sources=self.file_name) self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) if self.module_name.strip() == "shell": self.module_args = "source ~/.bash_profile;" + self.module_args self.play_source = dict(name="Ansible Ad-hoc", hosts=self.pattern, gather_facts=self.gather_facts, tasks=[ dict(action=dict(module=self.module_name, args=self.module_args), register='shell_out') ]) 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.resultcallback) # ** end __init__() ** def run(self): 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) return self.resultcallback.result_q except Exception as e: raise Exception(e) finally: if self.runner: self.runner.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() if os.path.exists(self.file_name): os.remove(self.file_name) def check_module_args(self): if self.module_name in C.MODULE_REQUIRE_ARGS and not self.module_args: err = "No argument passed to '%s' module." % self.module_name raise AnsibleError(err)
def ansible_install_api(task_id, play_book_path, schema): context.CLIARGS = ImmutableDict( connection='smart', private_key_file=settings.ANSIBLE_PRIVATE_KEY, forks=10, become_method='sudo', become_user='******', check=False, diff=False, verbosity=0) host_list = [schema.host_ip] sources = ','.join(host_list) if len(host_list) == 1: sources += ',' loader = DataLoader() passwords = dict(vault_pass='') results_callback = ResultsCollectorJSONCallback(task_id=task_id) inventory = InventoryManager(loader=loader, sources=sources) variable_manager = VariableManager(loader=loader, inventory=inventory) 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 ) play_sources = [] import os os.chdir(os.path.dirname(play_book_path)) with open(play_book_path) as f: data = yaml.load(f, yaml.SafeLoader) if isinstance(data, list): play_sources.extend(data) else: play_sources.append(data) logger.info("there are %d tasks to run", len(play_sources)) for play_book in play_sources: play_book['hosts'] = host_list play_book['remote_user'] = '******' play_book['vars']['mysql_port'] = schema.port play_book['vars']['mysql_schema'] = schema.schema print("playbook", play_book) play = Play().load(play_book, variable_manager=variable_manager, loader=loader) # Actually run it try: 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 logger.info("tqm has finished") tqm.cleanup() if loader: loader.cleanup_all_tmp_files() # Create play object, playbook objects use .load instead of init or new methods, # this will also automatically create the task objects from the info provided in play_source # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) return not results_callback.is_failed
class PlayRun: Options = namedtuple('Options', [ 'connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check' ]) def __init__(self, connection_type="ssh", forks=100, host_list="/etc/ansible/hosts", passwords=None, callback=None): self.connection_type = connection_type self.forks = forks self.host_list = host_list self.passwords = passwords or None self.variable_manager = VariableManager() self.loader = DataLoader() self.options = self.Options(connection=self.connection_type, module_path=None, forks=forks, become=None, become_method=None, become_user=None, check=False) self.results_callback = callback() self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list="/etc/ansible/hosts") self.variable_manager.set_inventory(self.inventory) self.play_source = None self.play = None self.runner = None def run(self, action_tuple, hosts="all", task_name="Ansible Ad-hoc"): """ :param action_tuple: [('shell', 'ls'), ('ping', '')] """ tasks = [] for item in action_tuple: assert len(item) == 2 module, args = item tasks.append(dict(action=dict(module=module, args=args))) self.play_source = dict(name=task_name, hosts=hosts, gather_facts='no', tasks=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, ) try: self.runner.run(self.play) finally: if self.runner: self.runner.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() return self.results_callback.result_q # run()最终将call_back的结果返回
def execute_playbook(play_book, host_list=[]): host_list = host_list # since the API is constructed for CLI it expects certain options to always be set in the context object context.CLIARGS = ImmutableDict( connection='paramiko', module_path=[ '/home/koshik/Documents/projects/devops/scripts/aenv/lib/python3.6/site-packages/ansible' ], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False) sources = ','.join(host_list) if len(host_list) == 1: sources += ',' # initialize needed objects loader = DataLoader( ) # Takes care of finding and reading yaml, json and ini files passwords = dict(vault_pass='******') # Instantiate our ResultsCollectorJSONCallback for handling results as they come in. Ansible expects this to be one of its main display outlets results_callback = ResultsCollectorJSONCallback() inventory = InventoryManager(loader=loader, sources=sources) variable_manager = VariableManager(loader=loader, inventory=inventory) 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 ) pbex = PlaybookExecutor(playbooks=[play_book], inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords) playbook = Playbook.load(pbex._playbooks[0], variable_manager=variable_manager, loader=loader) play = playbook.get_plays()[0] # Actually run it try: 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 tqm.cleanup() if loader: loader.cleanup_all_tmp_files() # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) if (results_callback.host_ok.items()): print("********* SUCCESS ***********") return results_callback.host_ok.items() if (results_callback.host_failed.items()): print("********* FAILED *******") for host, result in results_callback.host_failed.items(): print('{0} >>> {1}'.format(host, result._result['msg'])) if (results_callback.host_unreachable.items()): print("********* HOST DOWN *********") for host, result in results_callback.host_unreachable.items(): print('{0} >>> {1}'.format(host, result._result['msg']))
def chaosansible_run( host_list: list = ("localhost"), configuration: Configuration = None, facts: bool = False, become: bool = False, run_once: bool = False, ansible: dict = {}, num_target: str = "all", secrets: Secrets = None, ): """ Run a task through ansible and eventually gather facts from host """ # Check for correct inputs if ansible: if ansible.get("module") is None: raise InvalidActivity("No ansible module defined") if ansible.get("args") is None: raise InvalidActivity("No ansible module args defined") configuration = configuration or {} # Ansible configuration elements module_path = configuration.get("ansible_module_path") become_user = configuration.get("ansible_become_user") ssh_key_path = configuration.get("ansible_ssh_private_key") ansible_user = configuration.get("ansible_user") become_ask_pass = configuration.get("become_ask_pass") ssh_extra_args = configuration.get("ansible_ssh_extra_args") context.CLIARGS = ImmutableDict( connection="smart", verbosity=0, module_path=module_path, forks=10, become=become, become_method="sudo", become_user=become_user, check=False, diff=False, private_key_file=ssh_key_path, remote_user=ansible_user, ssh_extra_args=ssh_extra_args, ) # Update host_list regarding the number of desired target. # Need to generate a new host-list because after being update # and will be used later if num_target != "all": new_host_list = random_host(host_list, int(num_target)) else: new_host_list = host_list[:] # Create an inventory sources = ",".join(new_host_list) if len(new_host_list) == 1: sources += "," loader = DataLoader() inventory = InventoryManager(loader=loader, sources=sources) # Instantiate callback for storing results results_callback = ResultsCollectorJSONCallback() variable_manager = VariableManager(loader=loader, inventory=inventory) if become_ask_pass: passwords = dict(become_pass=become_ask_pass) else: passwords = None # Ansible taskmanager tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords, stdout_callback=results_callback, run_additional_callbacks=False, ) # Ansible playbook play_source = dict( name="Ansible Play", hosts=new_host_list, gather_facts=facts, tasks=[ dict( name="facts", action=dict(module="debug", args=dict(var="ansible_facts")), ), ], ) # In cas we only want to gather facts if ansible: module = ansible.get("module") args = ansible.get("args") play_source["tasks"].append( dict( name="task", run_once=run_once, action=dict(module=module, args=args), register="shell_out", ) ) # Create an ansible playbook play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # Run it try: result = tqm.run(play) finally: tqm.cleanup() if loader: loader.cleanup_all_tmp_files() # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) if len(results_callback.host_failed) > 0: print("Ansible error(s): ") for error in results_callback.host_failed: print(results_callback.host_failed[error].__dict__) raise FailedActivity("Failed to run ansible task") elif len(results_callback.host_unreachable) > 0: print("Unreachable host(s): ") for error in results_callback.host_unreachable: print(error) raise FailedActivity("At least one target is down") else: results = {} for host, result in results_callback.host_ok.items(): results[host] = result return json.dumps(results)
class MyApi(object): def __init__(self, resource, *args, **kwargs): self.resource = resource self.inventory = None self.variable_manager = None self.loader = None self.options = None self.passwords = None self.callback = None self.__initializeData() self.results_raw = {} if not os.path.exists(self.resource): print('[INFO] The [%s] inventory does not exist' % resource) sys.exit() def __initializeData(self): # 定义选项 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', 'listhosts', 'listtasks', 'listtags', 'diff', 'syntax' ] ) # 初始化需要的对象(参数) self.variable_manager = VariableManager() # 用来加载解析yaml文件或JSON内容, 并且支持vault的解密 self.loader = DataLoader() # 定义选项 self.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, listhosts=False, listtasks=False, listtags=False, diff=False, syntax=False ) # 默认密码, 主机未定义密码的时候才生效 self.passwords = dict(sshpass=None, becomepass=None) # 加载 host 列表 self.inventory = InventoryManager( loader=self.loader, sources=[self.resource]) # 初始化变量, 包括主机、组、扩展等变量 self.variable_manager = VariableManager( loader=self.loader, inventory=self.inventory) def run(self, host_list, module_name, module_args=None): # 创建任务 play_source = dict( name="Ansible Play", hosts=host_list, gather_facts='no', tasks=[ dict( action=dict( module=module_name, args=module_args ) ), # dict(action=dict(module='shell', args="id"), register='shell_out'), # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')), async=0, poll=15) ] ) play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader) # 实际运行 # TaskQueueManager 是创建进程池, 负责输出结果和多进程间数据结构或者队列的共享协作 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, stdout_callback=self.callback, ) tqm.run(play) finally: if tqm is not None: tqm.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) def run_playbook(self, host_list, playbook_path): """ 执行 ansible palybook """ try: self.callback = ResultsCollector() # playbook的路径 pbfiles = playbook_path.split() for pbfile in pbfiles: if not os.path.exists(pbfile): print('[INFO] The [%s] playbook does not exist' % pbfile) sys.exit() # 额外的参数 sudoers.yml以及模板中的参数,它对应ansible-playbook test.yml --extra-vars "host='aa' name='cc'" extra_vars = {} extra_vars['host_list'] = host_list self.variable_manager.extra_vars = extra_vars # actually run it executor = PlaybookExecutor( playbooks=pbfiles, inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, ) executor._tqm._stdout_callback = self.callback executor.run() except Exception as e: print("error:", e.message) def get_result(self): # 获取结束回调 self.result_all = {'success': {}, 'fail': {}, 'unreachable': {}} # print result_all # print dir(self.callback) for host, results in self.callback.host_ok.items(): for result in results: if not self.result_all['success'].get(host): self.result_all['success'][host] = dict() task_name = result.task_name _result = result._result if not self.result_all['success'][host].get(task_name): self.result_all['success'][host][task_name] = list() self.result_all['success'][host][task_name].append(_result) for host, result in self.callback.host_failed.items(): for result in results: if not self.result_all['failed'].get(host): self.result_all['failed'][host] = dict() task_name = result.task_name _result = result._result if not self.result_all['failed'][host].get(task_name): self.result_all['failed'][host][task_name] = list() self.result_all['failed'][host][task_name].append(_result['msg']) # self.result_all['failed'][host] = _result['msg'] for host, result in self.callback.host_unreachable.items(): for result in results: if not self.result_all['unreachable'].get(host): self.result_all['unreachable'][host] = dict() task_name = result.task_name _result = result._result if not self.result_all['unreachable'][host].get(task_name): self.result_all['unreachable'][host][task_name] = list() self.result_all['unreachable'][host][task_name].append(_result['msg']) for i in self.result_all['success'].keys(): return self.result_all def get_json(self): d = self.get_result() data = json.dumps(d, ensure_ascii=False, indent=4, encoding='utf-8') print(data)
class AnsiBleApi: def __init__( self, connection="smart", module_path=None, remote_user="******", forks=10, become=None, become_method=None, become_user=None, check=False, diff=False, hosts_list=None, verbosity=0, syntax=None, start_at_task=None, results_call_back=None, *args, **kwargs, ): context.CLIARGS = ImmutableDict(connection=connection, module_path=module_path, remote_user=remote_user, forks=forks, become=become, become_method=become_method, become_user=become_user, check=check, diff=diff, syntax=syntax, start_at_task=start_at_task, verbosity=verbosity, *args, **kwargs) self.forks = forks self.sources = hosts_list self.results_callback = results_call_back self.loader = DataLoader() def _(host): if isinstance(host, str): pass elif isinstance(host, list): s = ','.join(host) # if len(host) == 1: s += ',' host = s return host self._host_format = _ self.inventory = InventoryManager(loader=self.loader, sources=self._host_format( self.sources)) self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) self._play_source_template = { "name": "", "hosts": "", "gather_facts": "", "tasks": [], } def _play(self, play_source): var = play_source.pop("vars") return Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader, vars=var) def _tqm(self): return TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, forks=self.forks, passwords=None, stdout_callback=self.results_callback, ) def set_task(self, module="shell", args=None, **kwargs): task = {"action": {"module": module, "args": args}} task.update(kwargs) self._play_source_template["tasks"].append(task) def set_callback(self, callback=None): self.results_callback = callback def ansible(self, hosts, name="task name", gather_facts="no", var=None): if isinstance(hosts, list): hosts = self._host_format(hosts) self._play_source_template["name"] = name self._play_source_template["hosts"] = hosts self._play_source_template["vars"] = var self._play_source_template["gather_facts"] = gather_facts print("AD-HOC DEBUG", self._play_source_template) play = self._play(self._play_source_template) tqm = self._tqm() try: tqm.run(play) finally: if tqm is not None: tqm.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) def ansible_playbook(self, playbooks): pb = playbooks if isinstance(playbooks, list) else [playbooks] playbook = PlaybookExecutor( playbooks=pb, # 注意这里是一个列表 inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, passwords=dict(vault_pass=None)) playbook._tqm = self._tqm() print("Playbook DEBUG", pb) playbook.run() def result(self, to_json=False): result_raw = None if self.results_callback is None: return result_raw else: result_raw = self.results_callback.result() if to_json: return json.dumps(result_raw, indent=4) else: return result_raw
class ANSRunner(object): def __init__(self, hosts=constants.DEFAULT_HOST_LIST, module_name=constants.DEFAULT_MODULE_NAME, module_args=constants.DEFAULT_MODULE_ARGS, forks=constants.DEFAULT_FORKS, timeout=constants.DEFAULT_TIMEOUT, pattern="all", remote_user=constants.DEFAULT_REMOTE_USER, module_path=None, connection_type="smart", become=None, become_method=None, become_user=None, check=False, passwords=None, extra_vars=None, private_key_file=None, listtags=False, listtasks=False, listhosts=False, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, verbosity=None, syntax=False, redisKey=None, logId=None): self.Options = namedtuple("Options", [ 'listtags', 'listtasks', 'listhosts', 'syntax', 'connection', 'module_path', 'forks', 'remote_user', 'private_key_file', 'timeout', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity', 'check', 'extra_vars', 'diff' ]) self.results_raw = {} self.pattern = pattern self.module_name = module_name self.module_args = module_args self.gather_facts = 'no' self.options = self.Options(listtags=listtags, listtasks=listtasks, listhosts=listhosts, syntax=syntax, timeout=timeout, connection=connection_type, module_path=module_path, forks=forks, remote_user=remote_user, private_key_file=private_key_file, ssh_common_args=ssh_common_args or "", ssh_extra_args=ssh_extra_args or "", sftp_extra_args=sftp_extra_args, scp_extra_args=scp_extra_args, become=become, become_method=become_method, become_user=become_user, verbosity=verbosity, extra_vars=extra_vars or [], check=check, diff=False) self.redisKey = redisKey self.logId = logId self.loader = DataLoader() self.inventory = MyInventory(resource=hosts) self.variable_manager = VariableManager(self.loader, self.inventory) self.variable_manager.extra_vars = load_extra_vars( loader=self.loader, options=self.options) self.variable_manager.options_vars = load_options_vars( self.options, "") self.passwords = passwords or {} def run_model(self, host_list, module_name, module_args): if self.redisKey or self.logId: self.callback = ModelResultsCollectorToSave( self.redisKey, self.logId) else: self.callback = ModelResultsCollector() play_source = dict( name="Ansible Ad-hoc", hosts=host_list, gather_facts=self.gather_facts, tasks=[dict(action=dict(module=module_name, args=module_args))]) play = Play().load(play_source, loader=self.loader, variable_manager=self.variable_manager) 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) tqm._stdout_callback = self.callback constants.HOST_KEY_CHECKING = False # 关闭第一次使用ansible连接客户端是输入命令 tqm.run(play) except Exception as err: logger.error(msg=err) finally: if tqm is not None: tqm.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() def run_playbook(self, host_list, playbook_path, extra_vars=dict()): """ run ansible palybook """ try: if self.redisKey or self.logId: self.callback = PlayBookResultsCollectorToSave( self.redisKey, self.logId) else: self.callback = PlayBookResultsCollector() if isinstance(host_list, list): extra_vars['host'] = ','.join(host_list) else: extra_vars['host'] = host_list self.variable_manager.extra_vars = extra_vars executor = PlaybookExecutor( playbooks=[playbook_path], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, ) executor._tqm._stdout_callback = self.callback constants.HOST_KEY_CHECKING = False # 关闭第一次使用ansible连接客户端是输入命令 constants.DEPRECATION_WARNINGS = False constants.RETRY_FILES_ENABLED = False executor.run() except Exception as err: logger.error(msg=err) return False def get_model_result(self): self.results_raw = {'success': {}, 'failed': {}, 'unreachable': {}} for host, result in self.callback.host_ok.items(): self.results_raw['success'][host] = result._result for host, result in self.callback.host_failed.items(): self.results_raw['failed'][host] = result._result for host, result in self.callback.host_unreachable.items(): self.results_raw['unreachable'][host] = result._result return json.dumps(self.results_raw) def get_playbook_result(self): self.results_raw = { 'skipped': {}, 'failed': {}, 'ok': {}, "status": {}, 'unreachable': {}, "changed": {} } for host, result in self.callback.task_ok.items(): self.results_raw['ok'][host] = result for host, result in self.callback.task_failed.items(): self.results_raw['failed'][host] = result for host, result in self.callback.task_status.items(): self.results_raw['status'][host] = result for host, result in self.callback.task_changed.items(): self.results_raw['changed'][host] = result for host, result in self.callback.task_skipped.items(): self.results_raw['skipped'][host] = result for host, result in self.callback.task_unreachable.items(): self.results_raw['unreachable'][host] = result return self.results_raw def handle_cmdb_data(self, data): '''处理setup返回结果方法''' data_list = [] for k, v in json.loads(data).items(): if k == "success": for x, y in v.items(): cmdb_data = {} data = y.get('ansible_facts') disk_size = 0 cpu = data['ansible_processor'][-1] for k, v in data['ansible_devices'].items(): if k[0:2] in ['sd', 'hd', 'ss', 'vd']: disk = int( (int(v.get('sectors')) * int(v.get('sectorsize'))) / 1024 / 1024) disk_size = disk_size + disk cmdb_data['serial'] = data['ansible_product_serial'].split( )[0] cmdb_data['ip'] = x cmdb_data['cpu'] = cpu.replace('@', '') cmdb_data['ram_total'] = int(data['ansible_memtotal_mb']) cmdb_data['disk_total'] = int(disk_size) cmdb_data[ 'system'] = data['ansible_distribution'] + ' ' + data[ 'ansible_distribution_version'] + ' ' + data[ 'ansible_userspace_bits'] cmdb_data['model'] = data['ansible_product_name'].split( ':')[0] cmdb_data['cpu_number'] = data['ansible_processor_count'] cmdb_data['vcpu_number'] = data['ansible_processor_vcpus'] cmdb_data['cpu_core'] = data['ansible_processor_cores'] cmdb_data['hostname'] = data['ansible_hostname'] cmdb_data['kernel'] = str(data['ansible_kernel']) cmdb_data['manufacturer'] = data['ansible_system_vendor'] if data['ansible_selinux']: cmdb_data['selinux'] = data['ansible_selinux'].get( 'status') else: cmdb_data['selinux'] = 'disabled' cmdb_data['swap'] = int(data['ansible_swaptotal_mb']) # 获取网卡资源 nks = [] for nk in data.keys(): if re.match(r"^ansible_(eth|bind|eno|ens|em)\d+?", nk): device = data.get(nk).get('device') try: address = data.get(nk).get('ipv4').get( 'address') except: address = 'unkown' macaddress = data.get(nk).get('macaddress') module = data.get(nk).get('module') mtu = data.get(nk).get('mtu') if data.get(nk).get('active'): active = 1 else: active = 0 nks.append({ "device": device, "address": address, "macaddress": macaddress, "module": module, "mtu": mtu, "active": active }) cmdb_data['status'] = 0 cmdb_data['nks'] = nks data_list.append(cmdb_data) elif k == "unreachable": for x, y in v.items(): cmdb_data = {} cmdb_data['status'] = 1 cmdb_data['ip'] = x data_list.append(cmdb_data) if data_list: return data_list else: return False def handle_cmdb_crawHw_data(self, data): data_list = [] for k, v in json.loads(data).items(): if k == "success": for x, y in v.items(): cmdb_data = {} cmdb_data['ip'] = x data = y.get('ansible_facts') cmdb_data['mem_info'] = data.get( 'ansible_mem_detailed_info') cmdb_data['disk_info'] = data.get( 'ansible_disk_detailed_info') data_list.append(cmdb_data) if data_list: return data_list else: return False def handle_model_data(self, data, module_name, module_args=None): '''处理ANSIBLE 模块输出内容''' module_data = json.loads(data) failed = module_data.get('failed') success = module_data.get('success') unreachable = module_data.get('unreachable') data_list = [] if module_name == "raw": if failed: for x, y in failed.items(): data = {} data['ip'] = x try: data['msg'] = y.get('stdout').replace( '\t\t', '<br>').replace('\r\n', '<br>').replace('\t', '<br>') except: data['msg'] = None if y.get('rc') == 0: data['status'] = 'succeed' else: data['status'] = 'failed' data_list.append(data) elif success: for x, y in success.items(): data = {} data['ip'] = x try: data['msg'] = y.get('stdout').replace( '\t\t', '<br>').replace('\r\n', '<br>').replace('\t', '<br>') except: data['msg'] = None if y.get('rc') == 0: data['status'] = 'succeed' else: data['status'] = 'failed' data_list.append(data) elif module_name == "ping": if success: for x, y in success.items(): data = {} data['ip'] = x if y.get('ping'): data['msg'] = y.get('ping') data['status'] = 'succeed' data_list.append(data) else: if success: for x, y in success.items(): data = {} data['ip'] = x if y.get('invocation'): data['msg'] = "Ansible %s with %s execute success." % ( module_name, module_args) data['status'] = 'succeed' data_list.append(data) elif failed: for x, y in failed.items(): data = {} data['ip'] = x data['msg'] = y.get('msg') data['status'] = 'failed' data_list.append(data) if unreachable: for x, y in unreachable.items(): data = {} data['ip'] = x data['msg'] = y.get('msg') data['status'] = 'failed' data_list.append(data) if data_list: return data_list else: return False
class AnsExecuter(): def __init__(self,inventory): self._loader = DataLoader() self._passwords = None context.CLIARGS = ImmutableDict(connection='smart', module_path=None, forks=1, become=None, verbosity=5, sudo=None,sudo_user=None,ask_sudo_pass=None, become_method=None, become_user=None, check=False, diff=False,syntax=None,start_at_task=None) self._inventory = InventoryManager(loader=self._loader, sources=inventory) self._variable_manager = VariableManager(loader=self._loader, inventory=self._inventory) self.result_callback=ResultsCollectorJSONCallback() def run(self,hosts='localhost',module='ping',args='',timeout=0): tqm = TaskQueueManager( inventory=self._inventory, variable_manager=self._variable_manager, loader=self._loader, passwords=self._passwords, stdout_callback=self.result_callback, ) play_source = dict( name='Ad-hoc', hosts=hosts, gather_facts='no', tasks=[ dict(action=dict(module=module, args=args), register='shell_out'), #{'action':{'module':module,'args':args},'async':timeout,'poll':0}, # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))), # dict(action=dict(module='command', args=dict(cmd='/usr/bin/uptime'))), ] ) play = Play().load(play_source, variable_manager=self._variable_manager, loader=self._loader) try: result = tqm.run(play) finally: tqm.cleanup() if self._loader: self._loader.cleanup_all_tmp_files() # Remove ansible tmpdir shutil.rmtree(C.DEFAULT_LOCAL_TMP, True) def playbook(self,playbooks): """ :param playbooks: list类型 :return: """ playbook=PlaybookExecutor(playbooks=playbooks,inventory=self._inventory,variable_manager=self._variable_manager, loader=self._loader,passwords=self._passwords) playbook._tqm._stdout_callback=self.result_callback result=playbook.run() def get_result(self): # print("UP ***********") # for host, result in self.result_callback.host_ok.items(): # print('{0} >>> {1}'.format(host, result._result['stdout'])) # # print("FAILED *******") # for host, result in self.result_callback.host_failed.items(): # print('{0} >>> {1}'.format(host, result._result['msg'])) # # print("DOWN *********") # for host, result in self.result_callback.host_unreachable.items(): # print('{0} >>> {1}'.format(host, result._result['msg'])) result_raw = {"ok": {}, "failed": {}, "unreachable": {}, "skipped": {}, "status": {}} print("UP", "***********"*8) self.result_callback.host_ok.pop(0) for result in self.result_callback.host_ok: print(result) print("FAILED", "***********" * 8) for result in self.result_callback.host_failed: print(result) print("DOWN", "***********" * 8) for result in self.result_callback.host_unreachable: print(result)