为以后用的方便,记录一下(主要是怕忘,又得折腾半天)

直接贴代码,没太多注释,看不懂的看下源码。Pycharm+b

Ansible 2.0 之后的 API 比 2.0 之前要复杂,但使用起来的自由度更好,可根据自己需求修改 Ansible API 的使用方法;还有功能也更强大。

我主要是使用这个 API 配合 Djcelery 实现监控系统的数据采集功能,好处是不再需要每中服务器再开发一个agent。这样使用的问题可能主要是程序的负载性能及程序并发性能,我还没测试。

# -*- coding:utf8 -*-import osimport sysimport logginglogger = logging.getLogger('django')# from collections import namedtuplefrom ansible.inventory import Inventoryfrom ansible.vars import VariableManagerfrom ansible.parsing.dataloader import DataLoaderfrom ansible.inventory.group import Groupfrom ansible.inventory.host import Hostfrom ansible.playbook.play import Playfrom ansible.executor.playbook_executor import PlaybookExecutorfrom ansible.executor.task_queue_manager import TaskQueueManagerfrom ansible.plugins.callback import CallbackBase# 初始化选项参数#host_list=C.DEFAULT_HOST_LIST, # ex: /etc/ansible/hosts, legacy usage #执行host清单,如果不指定文件,会读取ansible.cfg文件的inventory = xx字段。#module_path=None, # ex: /usr/share/ansible#模块路径,比如:/usr/share/ansible ex==example。#module_name=C.DEFAULT_MODULE_NAME, # ex: copy#模块的名字。#module_args=C.DEFAULT_MODULE_ARGS, # ex: "src=/tmp/a dest=/tmp/b"#模块的参数。#forks=C.DEFAULT_FORKS, # parallelism level并发进程数。#timeout=C.DEFAULT_TIMEOUT, # SSH timeout#ssh 连接超时。#pattern=C.DEFAULT_PATTERN, # which hosts? ex: 'all', 'acme.example.org'#host清单里,匹配的组 host清单。#remote_user=C.DEFAULT_REMOTE_USER, # ex: 'username'#远程登录用户和执行用户。#remote_pass=C.DEFAULT_REMOTE_PASS, # ex: 'password123' or None if using key#远程登录用户密码。#remote_port=None, # if SSH on different ports#ssh连接端口。#private_key_file=C.DEFAULT_PRIVATE_KEY_FILE, # if not using keys/passwords#私钥位置,如果不是ssh 连接话。#background=0, # async poll every X seconds, else 0 for non-async#异步参数。#basedir=None, # directory of playbook, if applicable#playbook 路径。#setup_cache=None, # used to share fact data w/ other tasks#搜集远程节点的信息。#vars_cache=None, # used to store variables about hosts#host清单变量。#transport=C.DEFAULT_TRANSPORT, # 'ssh', 'paramiko', 'local'#连接远程主机的方式,是ssh还是paramiko....#conditional='True', # run only if this fact expression evals to true #未知#callbacks=None, # used for output#用于结果输出。#module_vars=None, # a playbooks internals thing##模块变量。#play_vars=None, ##play_file_vars=None, ##role_vars=None, ##role_params=None, ##default_vars=None, ##extra_vars=None, # extra vars specified with he playbook(s)#其他额外一些参数。#is_playbook=False, # running from playbook or not?#inventory=None, # reference to Inventory object#subset=None, # subset pattern#check=False, # don't make any changes, just try to probe for potential changes#测试play,看看对hostlist产生哪些变化。#diff=False, # whether to show diffs for template files that change#environment=None, # environment variables (as dict) to use inside the command#complex_args=None, # structured data in addition to module_args, must be a dict#error_on_undefined_vars=C.DEFAULT_UNDEFINED_VAR_BEHAVIOR, # ex. False#accelerate=False, # use accelerated connection#accelerate_ipv6=False, # accelerated connection w/ IPv6#accelerate_port=None, # port to use with accelerated connection#vault_pass=None,#run_hosts=None, # an optional list of pre-calculated hosts to run on#no_log=False, # option to enable/disable logging for a given task#run_once=False, # option to enable/disable host bypass loop for a given task#become=False, # whether to run privelege escalation or not#become_method=C.DEFAULT_BECOME_METHOD,#become_user=C.DEFAULT_BECOME_USER, # ex: 'root'#become_pass=C.DEFAULT_BECOME_PASS, # ex: 'password123' or None#become_exe=C.DEFAULT_BECOME_EXE, # ex: /usr/local/bin/sudo# OPTIONS = namedtuple('OPTIONS',# ['module_path', 'extra_vars', 'forks', 'become', 'become_method', 'become_user',# 'become_ask_pass', 'connection', 'timeout', 'poll_interval', 'check', 'diff']# )# options = OPTIONS(module_path=None, extra_vars=None, forks=5, become=None, become_method=None, become_user=None,# become_ask_pass=None, connection='smart', timeout=10, poll_interval=15, check=False, diff=3)class Options(object):'''Initialize options class to replace Ansible OptParser'''def __init__(self, module_path=None, extra_vars=None, forks=10, become=None, become_method=None, become_user=None, become_ask_pass=None, connection='smart', timeout=2, poll_interval=15, check=False, diff=3, listtasks=None, listhosts=None, listtags=None, syntax=None): self.module_path = module_path self.extra_vars = extra_vars self.forks = forks self.become = become self.become_method = become_method self.become_user = become_user self.become_ask_pass = become_ask_pass self.connection = connection self.timeout = timeout self.poll_interval = poll_interval self.check = check self.diff = diff self.listhosts = listhosts self.listtasks = listtasks self.listtags = listtags self.syntax = syntaxclass ResultsCallback(CallbackBase):'''Callback the result of execute AdHoc and playbook'''def __init__(self, *args, **kwargs): super(ResultsCallback, 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()] = resultdef v2_runner_on_ok(self, result, *args, **kwargs): self.host_ok[result._host.get_name()] = resultdef v2_runner_on_failed(self, result, *args, **kwargs): self.host_failed[result._host.get_name()] = resultdef v2_runner_on_async_poll(self, result): self.host_ok.setdefault('async_poll', result)def v2_runner_on_async_ok(self, result): self.host_ok.setdefault('async_ok', result)def v2_runner_on_async_failed(self, result): self.host_failed.setdefault('async_failed', result)def v2_playbook_on_no_hosts_matched(self): self.host_unreachable.setdefault(self)class DynamicInventory(Inventory):def __init__(self, resource, loader, variable_manager): ''' @resource: { "group1": { "hosts": [{"hostname": "10.0.0.0", "port": "22", "username": "test", "password": "pass"}, ...], "vars": {"var1": value1, "var2": value2, ...} } } ''' self.resource = resource self.inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=[]) self.gen_inventory()def Dynamic_add_group(self, hosts, groupname, groupvars=None): ''' Dynamic generate group list of ansible inventory :param hosts: :param groupname: :param groupvars: :return: ''' NewGroup = Group(name=groupname) if groupvars: for key, value in groupvars.iteritems(): NewGroup.set_variable(key, value) for host in hosts: hostname = host.get("hostname") hostport = host.get("port") username = host.get("username") password = host.get("password") # ssh_key = host.get("ssh_key") GeneralHost = Host(name=hostname, port=hostport) GeneralHost.set_variable('ansible_ssh_host', hostname) GeneralHost.set_variable('ansible_ssh_port', hostport) GeneralHost.set_variable('ansible_ssh_user', username) GeneralHost.set_variable('ansible_ssh_pass', password) # GeneralHost.set_variable('ansible_ssh_private_key_file', ssh_key) for key, value in host.iteritems(): if key not in ["hostname", "port", "username", "password"]: GeneralHost.set_variable(key, value) NewGroup.add_host(GeneralHost) return self.inventory.add_group(NewGroup)def gen_inventory(self): ''' Dynamic generate host inventory of ansible :return: ''' if isinstance(self.resource, list): self.Dynamic_add_group(self.resource, 'default_group') elif isinstance(self.resource, dict): for groupname, hosts_and_vars in self.resource.iteritems(): self.Dynamic_add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars"))class AnsibleAPI(object):def __init__(self, resource): ''' @resource type: dict { "group1": { "hosts": [{"hostname": "10.0.0.0", "port": "22", "username": "test", "password": "pass"}, ...], "vars": {"var1": value1, "var2": value2, ...} } } @resource: list { "hosts": [{"hostname": "10.0.0.0", "port": "22", "username": "test", "password": "pass"} } ''' self.variable_manager = VariableManager() self.loader = DataLoader() self.options = Options() self.passwords = dict() self.results_raw = {'success': {}, 'failed': {}, 'unreachable': {}} self.resource = resource self.callback = ResultsCallback() self.inventory = DynamicInventory(self.resource, self.loader, self.variable_manager).inventory self.variable_manager.set_inventory(self.inventory) if isinstance(self.resource, list): self.host_list = map(str, self.inventory.get_hosts(pattern='default_group')) if isinstance(self.resource, dict): self.host_list = [] for groupname in self.resource.keys(): self.host_list.extend(self.inventory.get_group(groupname).get_hosts()) self.host_list = map(str, self.host_list)def PrivateAdHoc(self, module_name, module_args=''): ''' Use ansible ad-hoc to run ansible mudule :param module_name: Executable ansible mudule :param module_args: Executable mudule extends arguments :return: Execution status number ''' play_source = dict( name="Ansible Play", hosts=self.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 try: tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords, stdout_callback=self.callback ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() return resultdef PrivatePlaybook(self, playbooks): ''' Run ansible palybook and get ran result :param playbooks: Absolute path of entry file of ansible playbook :return: Execution status number ''' try: if not os.path.exists(playbooks): logger.error('No such file: %s' % playbooks) sys.exit() self.executor = PlaybookExecutor(playbooks=[playbooks, ], inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=self.passwords ) self.executor._tqm._stdout_callback = self.callback result = self.executor.run() except Exception as e: sys.exit(127) else: return resultdef playbook_result(self): for host, result_object in self.executor._tqm._stdout_callback.host_ok.iteritems(): self.results_raw['success'][host] = result_object._result for host, result_object in self.executor._tqm._stdout_callback.host_failed.iteritems(): try: self.results_raw['failed'][host] = result_object._result['stderr'] except KeyError: self.results_raw['failed'][host] = result_object._result['msg'] for host, result_object in self.executor._tqm._stdout_callback.host_unreachable.iteritems(): self.results_raw['unreachable'][host] = result_object._result['msg'] return self.results_rawdef adhoc_result(self): ''' Takes ansible ad-hoc execution result :return: Dict ''' 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(): try: self.results_raw['failed'][host] = result._result['stderr'] except KeyError: self.results_raw['failed'][host] = result._result['msg'] for host, result in self.callback.host_unreachable.items(): self.results_raw['unreachable'][host] = result._result['msg'] return self.results_rawif __name__ == '__main__':#Ad-Hoc testing# ad_hoc_example = AnsibleAPI([# dict(hostname='10.10.181.132', port=20003, username='root', password=123456),# ])# print ad_hoc_example.PrivateAdHoc('service', module_args='name=crond state=reloaded')# print ad_hoc_example.get_result()# Playbook testingplaybook_example = AnsibleAPI(dict(memory=dict(hosts=[dict(hostname='10.10.181.132', port=20003, username='root', password=123456), dict(hostname='10.10.181.131', port=20004, username='root', password=123456)], vars=dict())))print playbook_example.PrivatePlaybook('/Users/fanolee/PycharmProjects/AutoOPPlatform/monitor/ansible/playbooks/entry_files/memory/memory.yml')print playbook_example.playbook_result()