一、api代碼
# coding: utf-8 import os import sys from collections import namedtuple from ansible.parsing.dataloader import DataLoader from ansible.vars.manager import VariableManager from ansible.inventory.manager import InventoryManager from ansible.executor.playbook_executor import PlaybookExecutor from ansible.playbook.play import Play from ansible.executor.task_queue_manager import TaskQueueManager from ansible.plugins.callback import CallbackBase #存放yml的目錄 YML_DIR = '' class ansible_Runner(object): """ This is a General object for parallel execute modules. """ 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 = {} def __initializeData(self): """ 初始化ansible配置 """ Options = namedtuple('Options', ['listtags', 'listtasks', 'listhosts', 'syntax', 'connection', 'module_path', 'forks', 'remote_user', 'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity', 'check', 'diff']) self.loader = DataLoader() self.options = Options(listtags=False, listtasks=False, listhosts=False, syntax=False, connection='ssh', module_path=None, forks=100, remote_user='root', private_key_file=None, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=True, become_method='sudo', become_user='root', verbosity=None, check=False, diff=False) self.passwords = dict(vault_pass='secret') 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, ): """ run module from andible ad-hoc. module_name: ansible module_name module_args: ansible module args """ play_source = dict( name="Ansible Ad-hoc Command", 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) 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='default', ) tqm._stdout_callback = self.callback result = tqm.run(play) # print self.callback finally: if tqm is not None: tqm.cleanup() def run_playbook(self, playbook_name): try: self.callback = ResultsCollector() playbook_file = [YML_DIR + playbook_name] print(playbook_file) # template_file = BASE_DIR + "roles/"+ role_name + "/templates" if not os.path.exists(playbook_name): print('%s 路徑不存在 ' % playbook_file) sys.exit() executor = PlaybookExecutor( playbooks=playbook_file, 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("Failure in run_playbook:%s"%e) pass def get_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['msg'] return self.results_raw class ResultsCollector(CallbackBase): def __init__(self, *args, **kwargs): super(ResultsCollector, self).__init__(*args, **kwargs) self.host_ok = {} self.host_unreachable = {} self.host_failed = {} def v2_runner_on_unreachable(self, result): self.host_unreachable[result._host.get_name()] = result def v2_runner_on_ok(self, result, *args, **kwargs): self.host_ok[result._host.get_name()] = result def v2_runner_on_failed(self, result, *args, **kwargs): self.host_failed[result._host.get_name()] = result
二、使用演示
1、執行模塊與命令
[root@adminan]#cat test.py from Ansible import * ansible = ansible_Runner('/etc/ansible/hosts') ansible.run('all', 'shell', "ping baidu.com -c 2 >/tmp/ping.txt") print(ansible.get_result()) [root@adminan]#python3 test.py {'success': {'10.0.0.141': {'changed': True, 'end': '2019-08-30 14:28:30.924988', 'stdout': '', 'cmd': 'ping baidu.com -c 2 >/tmp/ping.txt', 'rc': 0, 'start': '2019-08-30 14:28:29.835961', 'stderr': '', 'delta': '0:00:01.089027', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': 'ping baidu.com -c 2 >/tmp/ping.txt', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': [], 'stderr_lines': [], '_ansible_no_log': False}}, 'failed': {}, 'unreachable': {}} [root@adminan]#cat /tmp/ping.txt PING baidu.com (220.181.38.148) 56(84) bytes of data. 64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=1 ttl=128 time=43.9 ms 64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=2 ttl=128 time=44.4 ms --- baidu.com ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 43.914/44.166/44.419/0.328 ms
2、playbook使用
[root@adminan]#cat test.yaml - hosts: all tasks: - name: "test" command: touch /tmp/test.txt [root@adminan]#cat test.py from Ansible import * ansible = ansible_Runner('/etc/ansible/hosts') ansible.run_playbook("/root/an/test.yaml") print(ansible.get_result()) [root@adminan]#python3 test.py ['/root/an/test.yaml'] {'success': {'10.0.0.141': {'changed': True, 'end': '2019-08-30 14:30:46.462422', 'stdout': '', 'cmd': ['touch', '/tmp/test.txt'], 'rc': 0, 'start': '2019-08-30 14:30:46.451079', 'stderr': '', 'delta': '0:00:00.011343', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': False, '_raw_params': 'touch /tmp/test.txt', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, 'warnings': ["Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message."], '_ansible_parsed': True, 'stdout_lines': [], 'stderr_lines': [], '_ansible_no_log': False}}, 'failed': {}, 'unreachable': {}} [root@adminan]#ll /tmp/test.txt -rw-r--r-- 1 root root 0 8月 30 14:30 /tmp/test.txt