ansible2.4+ python api封装

ansible2.4的结构跟2.3相比有修改的地方,所以封装的方式也需要调整一下。

ansible_utils.py

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os

from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.inventory.host import Host
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
from tempfile import NamedTemporaryFile
# from ansible.MyInventory import MyInventory
from ansible.plugins.callback import CallbackBase


class AnsibleAPI(object):
    """ 
    This is a General object for parallel execute modules. 
    """

    def __init__(self, resource, resource_list=[], *args, **kwargs):
        self.resource = resource
        self.resource_list = resource_list
        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',
                     ['connection',
                      'remote_user',
                      'ask_sudo_pass',
                      'verbosity',
                      'ack_pass',
                      'module_path',
                      'forks',
                      'become',
                      'become_method',
                      'become_user',
                      'check',
                      'listhosts',
                      'listtasks',
                      'listtags',
                      'syntax',
                      'sudo_user',
                      'sudo',
                      'diff'])
        self.options = Options(connection='smart',
                       remote_user=None,
                       ack_pass=None,
                       sudo_user=None,
                       forks=5,
                       sudo=None,
                       ask_sudo_pass=False,
                       verbosity=5,
                       module_path=None,
                       become='yes',
                       become_method='sudo',
                       become_user='root',
                       check=False,
                       diff=False,
                       listhosts=None,
                       listtasks=None,
                       listtags=None,
                       syntax=None)

        '''
        Options = namedtuple('Options',
                             ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check',
                              'diff'])
        self.options = Options(connection='ssh', module_path='/path/to/mymodules', forks=100, become=None,
                               become_method=None, become_user=None, check=False,
                               diff=False)
        '''

        self.loader = DataLoader()

        self.passwords = dict(vault_pass='secret')

        self.inventory = InventoryManager(
            loader=self.loader, sources=self.resource)

        # 添加host的登录信息
        self.convert_hosts()

        self.variable_manager = VariableManager(
            loader=self.loader, inventory=self.inventory)

    def convert_hosts(self):
        for host in self.resource_list:
            if host['hostname'] in self.inventory.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")
                ssh_key = host.get("ssh_key")
                my_host = Host(name=hostname, port=hostport)
                my_host.set_variable('ansible_ssh_host', hostip)
                my_host.set_variable('ansible_ssh_port', hostport)
                my_host.set_variable('ansible_ssh_user', username)
                my_host.set_variable('ansible_ssh_pass', password)
                my_host.set_variable('ansible_ssh_private_key_file', ssh_key)

                # set other variables
                for key, value in host.iteritems():
                    if key not in ["hostname", "port", "username", "password"]:
                        my_host.set_variable(key, value)
                self.inventory.hosts[hostname]=my_host

    def run(self, host_list, module_name, module_args):
        """ 
        run module from andible ad-hoc. 
        module_name: ansible module_name 
        module_args: ansible module args 
        """
        # create play with tasks
        play_source = dict(
            name="Ansible Play",
            hosts=host_list,
            gather_facts='no',
            tasks=[dict(action=dict(module=module_name, args=module_args))]
        )
        play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)

        # actually run it
        tqm = None
        self.callback = ResultsCollector()
        try:
            tqm = TaskQueueManager(
                inventory=self.inventory,
                variable_manager=self.variable_manager,
                loader=self.loader,
                options=self.options,
                passwords=self.passwords,
                stdout_callback='default',
            )
            tqm._stdout_callback = self.callback
            result = tqm.run(play)
        # print result
        # print self.callback
        finally:
            if tqm is not None:
                tqm.cleanup()

    def run_playbook(self, host_list, filenames='/home/work/test.yml'):
        """ 
        run ansible palybook 
        """
        try:
            self.callback = ResultsCollector()
            # playbook的路径
            '''
            filenames = [BASE_DIR + '/handlers/ansible/v1_0/sudoers.yml']
            logger.info('ymal file path:%s' % filenames)
            template_file = TEMPLATE_DIR  # 模板文件的路径
            if not os.path.exists(template_file):
                logger.error('%s 路径不存在 ' % template_file)
                sys.exit()
            '''

            extra_vars = {}  # 额外的参数 sudoers.yml以及模板中的参数,它对应ansible-playbook test.yml --extra-vars "host='aa' name='cc' "
            host_list_str = ','.join([item for item in host_list])
            '''
            extra_vars['host_list'] = host_list_str
            extra_vars['username'] = role_name
            extra_vars['template_dir'] = template_file
            extra_vars['command_list'] = temp_param.get('cmdList')
            extra_vars['role_uuid'] = 'role-%s' % role_uuid
            '''
            self.variable_manager.extra_vars = {'customer': 'test', 'disabled': 'yes'}
            ##logger.info('playbook 额外参数:%s'%self.variable_manager.extra_vars)
            # actually run it
            executor = PlaybookExecutor(
                playbooks=filenames, 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:
            # logger.error("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']

        # print "Ansible执行结果集:%s"%self.results_raw
        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

ansible_interface.py

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from ansible_utils import AnsibleAPI


class AnsiInterface(AnsibleAPI):
    def __init__(self, resource, resource_list=[], *args, **kwargs):
        super(AnsiInterface, self).__init__(resource, resource_list, *args, **kwargs)

    @staticmethod
    def deal_result(info):
        host_ips = info.get('success').keys()
        info['success'] = host_ips

        error_ips = info.get('failed')
        error_msg = {}
        for key, value in error_ips.items():
            temp = {}
            temp[key] = value.get('msg')
            error_msg.update(temp)
        info['failed'] = error_msg
        return info

    def copy_file(self, host_list, src=None, dest=None):
        """
        copy file
        """
        module_args = "src=%s  dest=%s"%(src, dest)
        self.run(host_list, 'copy', module_args)
        result = self.get_result()
        return self.deal_result(result)

    def exec_command(self, host_list, cmds):
        """
        commands
        """
        self.run(host_list, 'command', cmds)
        result = self.get_result()
        return self.deal_result(result)

    def exec_script(self, host_list, path):
        """
        在远程主机执行shell命令或者.sh脚本
        """
        self.run(host_list, 'shell', path)
        result = self.get_result()
        return self.deal_result(result)

    def user(self, host_list, params):
        """
        在远程主机添加用户
        """
        module_args = ''
        for i in params:
            module_args += i+'='+params[i]+' '
        self.run(host_list, 'user', module_args)
        result = self.get_result()
        return self.deal_result(result)

    def authorized_key(self, host_list, params):
        """
        在远程主机添加用户
        """
        module_args = ''
        for i in params:
            if i == 'key':
                module_args += i+'="'+params[i]+'" '
            else:
                module_args += i+'='+params[i]+' '
        self.run(host_list, 'authorized_key', module_args)
        result = self.get_result()
        return self.deal_result(result)

    def run_playbook(self, host_list, path):
        """
        在远程主机执行ansible playbook
        """
        self.run_playbook(host_list, path)
        result = self.get_result()
        return self.deal_result(result)

    def ping(self, host_list, args):
        """
        commands
        """
        self.run(host_list, 'ping', args)
        result = self.get_result()
        return self.deal_result(result)


if __name__ == "__main__":
    """
      参数格式1:
        resource和resource_list一一对应, 如果配置了免密钥登陆, 可以不传resource_list
        resource_list = [{"hostname":"192.168.175.3","port":"22","username":"root","password":"123456","ip":'192.168.175.3'}]
        resource = '192.168.175.3,' // 逗号不能少,即使只有一个

      参数格式2:
        resource = '/home/work/hosts'
    """
    resource_list = [{"hostname":"192.168.175.3","port":"22","username":"root","password":"123456","ip":'192.168.175.3', 'ssh_key': ''}]
    resource = '192.168.175.3,'
    #resource = '/home/work/hosts'
    interface = AnsiInterface(resource,resource_list)
    '''
    print "copy: ", interface.copy_file(['172.20.3.18', '172.20.3.31'], src='/Users/majing/test1.py', dest='/opt')
    print "commands: ", interface.exec_command(['172.20.3.18', '172.20.3.31'], 'hostname')
    print "shell: ", interface.exec_script(['172.20.3.18', '172.20.3.31'], 'chdir=/home ls')
    print "shell: ", interface.exec_script(['172.20.3.18', '172.20.3.31'], 'sh /opt/test.sh')
    '''
    #print "create user: ", interface.user(['172.20.3.18'], 'test')
    print "commands: ", interface.ping(['192.168.175.3'], '')
    # print "playbook: ", interface.run_playbook(['192.168.99.101'], '/home/work/test.yml')

支持直接传resource登录信息,而不是必须使用文件形式。

 

你可能感兴趣的:(杂项)