自动化运维 Ansible 2.2.1 playbook api

最近把Ansible升级到2.2.1,感觉变化比较大,花些时间对playbook api 的调用做下总结

重大更新:
  • ansible.conf中添加了strategy:free属性, 配置该属性可以实现任务的异步执行,再也不用的等待所有机器执行完,才进入下个任务了。
  • ansible api 和 ansible-playbook api 的调用方式


发现的问题:
  • 2.2.1 的执行速度比1.9略慢


Ansible Playbook api的调用

核心类
ansible.executor.task_queue_manager
  • 将各类参数放到"ansible.executor.task_queue_manager"类中
  • 将playbook 拆分成多个task 放入ansible.executor.task_queue_manager中


直接上源码
class TaskQueueManager:

    '''
    This class handles the multiprocessing requirements of Ansible by
    creating a pool of worker forks, a result handler fork, and a
    manager object with shared datastructures/queues for coordinating
    work between all processes.

    The queue manager is responsible for loading the play strategy plugin,
    which dispatches the Play's tasks to hosts.
    '''

    def __init__(self, inventory, variable_manager, loader, options, passwords, stdout_callback=None, run_additional_callbacks=True, run_tree=False):

        self._inventory        = inventory
        self._variable_manager = variable_manager
        self._loader           = loader
        self._options          = options
        self._stats            = AggregateStats()
        self.passwords         = passwords
        self._stdout_callback  = stdout_callback
        self._run_additional_callbacks = run_additional_callbacks
        self._run_tree         = run_tree

        self._callbacks_loaded = False
        self._callback_plugins = []
        self._start_at_done    = False

        # make sure the module path (if specified) is parsed and
        # added to the module_loader object
        
        ...



参数:
  • inventory --> 由ansible.inventory模块创建,用于导入inventory文件 (也可以直接使用实例)
  • variable_manager --> 由ansible.vars模块创建,用于存储各类变量信息
  • loader --> 由ansible.parsing.dataloader模块创建,用于数据解析
  • options --> 存放各类配置信息的数据字典
  • passwords --> 登录密码,可设置加密信息
  • stdout_callback --> 回调函数(可以自定义返回结果)



完整的例子:
class MyInventory(object):
    """
    this is my ansible inventory object
    """

    def __init__(self, loader, variable_manager, host_list, groupname='default_group'):
        """
        :param loader:
        :param variable_manager:
        :param host_list: ex.:[{'hostname':'','ip':'','port':,'username':,'password':,'become_root_passwd':,'become':,}]
        :param groupname:
        """

        self.inventory = Inventory(loader, variable_manager, host_list=[])
        # self.inventory.refresh_inventory()
        self.set_inventory(host_list, groupname)

    def get_inventory(self):
        return self.inventory

    def set_inventory(self, hosts, groupname, groupvars=None):
        """
        add hosts to a group
        """
        my_group = Group(name=groupname)

        # if group variables exists, add them to group
        if groupvars:
            for key, value in groupvars.iteritems():
                my_group.set_variable(key, value)

        # add hosts to group
        for host in hosts:
            # set connection variables
            hostname = host.get("hostname")
            hostip = host.get('ip', hostname)
            hostport = host.get("port")
            username = host.get("username")
            password = host.get("password")
            become_root_passwd = host.get("become_root_passwd")
            become = host.get("become", True)

            my_host = Host(name=hostname, port=hostport)
            my_host.set_variable('ansible_host', hostip)
            my_host.set_variable('ansible_port', hostport)
            my_host.set_variable('ansible_user', username)
            my_host.set_variable('ansible_ssh_pass', password)
            my_host.set_variable('ansible_become', become)
            my_host.set_variable('ansible_become_method', 'su')
            my_host.set_variable('ansible_become_user', 'root')
            my_host.set_variable('ansible_become_pass', become_root_passwd)

            for key, value in host.iteritems():
                if key not in ["hostname", "port", "username", "password"]:
                    my_host.set_variable(key, value)
            # add to group
            my_group.add_host(my_host)
        self.inventory.add_group(my_group)



class ResultsCallBack(CallbackBase):
    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()] = 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


class AnsiblePlaybookTask(object):
    def __init__(self, host_list, **kwargs):
        """

        :param host_list: [{'hostname':'','ip':'','port':,'username':,'password':,'become_root_passwd':,'become':,}]
        """
        Options = namedtuple('Options',
                             ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check',
                              'listtags', 'listtasks', 'listhosts', 'syntax', 'stdout_callback'])
        # initialize needed objects
        self.loader = DataLoader()
        self.variable_manager = VariableManager()
        self.resultCallBack = ResultsCallBack()
        self.options = Options(
            listtags=None,
            listtasks=None,
            listhosts=None,
            syntax=None,
            connection='smart',
            module_path=None,
            forks=100 if not kwargs else kwargs.get('forks', 100),
            become=True, become_method=None,
            stdout_callback=self.resultCallBack,
            become_user=None, check=False)
        myInventory = MyInventory(self.loader, self.variable_manager, host_list)
        self.inventory = myInventory.get_inventory()

    def run_yaml(self, yml_path, extra_vars):
        self.variable_manager.extra_vars = extra_vars
        playbook = Playbook.load(yml_path, variable_manager=self.variable_manager, loader=self.loader)
        p = playbook.get_plays()[0]
        tqm = None
        try:
            tqm = TaskQueueManager(
                inventory=self.inventory,
                variable_manager=self.variable_manager,
                loader=self.loader,
                options=self.options,
                passwords=None,
                stdout_callback=self.options.stdout_callback,
            )
            result = tqm.run(playbook.get_plays()[0])
        finally:
            if tqm is not None:
                tqm.cleanup()
        return result

    def get_result(self):
        self.results_raw = {'ok': {}, 'failed': {}, 'unreachable': {}}
        for host, result in self.resultCallBack.host_ok.items():
            self.results_raw['ok'][host] = result._result

        for host, result in self.resultCallBack.host_failed.items():
            self.results_raw['failed'][host] = result._result

        for host, result in self.resultCallBack.host_unreachable.items():
            self.results_raw['unreachable'][host] = result._result

        return self.results_raw


调用:
playbook = AnsiblePlaybookTask(        [dict(hostname='XXX', ip='XXX', port=XXX, username="XXX",
              password='XXX', become_root_passwd='XXX', become=XXX,
              platform='XXX')         ])
playbook.run_yaml(yml_path='XXX', extra_vars={})

playbook.get_result()



优化点:
  • 可以在MyInventory中设置每个Host的自身属性,并在yml里调用
  • 自定义callback,将结果按需要输出

猜你喜欢

转载自endless2009.iteye.com/blog/2362103