Beispiel #1
0
 def run_module(self, hosts='localhost', rules=[{'module': 'setup'}]):
     '''
     rules=[
           {'module': 'shell', 'args': 'echo "ok"', 'register': 'echo_ok'},
           {'module': 'debug', 'args': {'msg': '{{echo_ok.stdout}}'}}
     ]
     '''
     tasks = []
     for rule in rules:
         if 'register' in rule:
             register = rule.pop('register')
         tasks.append(dict(dict(action=rule), register=register))
     play_source =  dict(
         name = "Ansible Play",
         hosts = hosts,
         gather_facts = 'no',
         tasks = tasks
     )
     results_callback = ResultCallback()
     play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)
     qm = None
     try:
         tqm = TaskQueueManager(
               inventory=self.inventory,
               variable_manager=self.variable_manager,
               loader=self.loader,
               options=self.options,
               passwords=self.passwords,
               stdout_callback=results_callback,
          )
         tqm.run(play)
         return results_callback
     finally:
         if tqm is not None:
             tqm.cleanup()
Beispiel #2
0
    def run(self):

        # create play with tasks
        play_source =  dict(
                name = "Ansible Play",
                hosts = self.host_list,
                #hosts = 'localhost',
                gather_facts = 'no',
                tasks = [
                    dict(action=dict(module='shell', args='ls')),
                    #dict(action=dict(module='shell', args='ls'), register='shell_out'),
                    #dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
                 ]
            )
        play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)

        # actually run it
        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,  # Use our custom callback instead of the ``default`` callback plugin
                  )
            result = tqm.run(play)
        finally:
            if tqm is not None:
                tqm.cleanup()
Beispiel #3
0
    def run(self, play_data):
        """
        paly_data = dict(
            name="Ansible Ad-Hoc",
            hosts=pattern,
            gather_facts=True,
            tasks=[dict(action=dict(module='service', args={'name': 'vsftpd', 'state': 'restarted'}), async=async, poll=poll)]
        )
        """
        self._prepare_run()

        play = Play().load(play_data, 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.cb,
                run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS,
                run_tree=False,
            )

            result = tqm.run(play)
            return result
        finally:
            if tqm:
                tqm.cleanup()
Beispiel #4
0
    def run_module(self, hosts, module_name, module_args):
        # create play with tasks
        play_source = dict(
            name="Ansible Play",
            hosts=hosts,
            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)

        self.results_callback = ModuleResultCallback()
        # actually run it
        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,  # Use our custom callback instead of the ``default`` callback plugin
            )
            result = tqm.run(play)
        finally:
            if tqm is not None:
                tqm.cleanup()
def run_command(cmd, host):
    callback_ob = callback_class()
    play_source =  dict(
        name = "Ansible Play",
        hosts = host,
        gather_facts = 'no',
        tasks = [
	    dict(action=dict(module='shell', args=cmd), register='shell_out'),
            dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
         ]
    )
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

    task = TaskQueueManager(
              inventory=inventory,
              variable_manager=variable_manager,
              loader=loader,
              options=options,
              passwords=passwords,
              stdout_callback=callback_ob,
          )
    # redirecting stdout to grab the output from the task
    normal_stdout = sys.stdout
    sys.stdout = new_stdout = StringIO()
    result = task.run(play)
    sys.stdout = normal_stdout
#    import pdb; pdb.set_trace()
    return new_stdout.readlines()
    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,
            )
            tqm._stdout_callback = self.callback
            result = tqm.run(play)
        finally:
            if tqm is not None:
                tqm.cleanup()
Beispiel #7
0
def my_runner(host_list,module_name,module_args):
 variable_manager.extra_vars={} # 增加外部变量
 # 构建pb, 这里很有意思, 新版本运行ad-hoc或playbook都需要构建这样的pb, 只是最后调用play的类不一样
 # :param name: 任务名,类似playbook中tasks中的name
 # :param hosts: playbook中的hosts
 # :param tasks: playbook中的tasks, 其实这就是playbook的语法, 因为tasks的值是个列表,因此可以写入多个task
 play_source = {"name":"Ansible Ad-Hoc","hosts":host_list,"gather_facts":"no","tasks":[{"action":{"module":module_name,"args":module_args}}]}
 play = Play().load(play_source,variable_manager=variable_manager,loader=loader)
 tqm = None
# results_callback = call_json.CallbackModule()
 try:
   tqm = TaskQueueManager(
	inventory=inventory,
 	variable_manager=variable_manager,
 	loader=loader,
 	options=options,
 	passwords=None,
 	stdout_callback='minimal',
#	stdout_callback=results_callback,  # Use our custom callback instead of the ``default`` callback plugin
   )
   savedStdout = sys.stdout
   with open(File_PATH,'w+') as file:
     sys.stdout = file #标准输出重定向至文件
     result = tqm.run(play)
   sys.stdout = savedStdout  
   return result
 
 finally:
   if tqm is not None:
     tqm.cleanup()
Beispiel #8
0
def ansible_adhoc(ips):
    logger.info("ansible需要采集%d个IP" % (len(ips)))
    inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=ips)
    # 根据 inventory 加载对应变量
    variable_manager.set_inventory(inventory)
    # 增加外部变量
    variable_manager.extra_vars = {"ansible_ssh_user": ansible_username, "ansible_ssh_pass": ansible_password}
    play_source = {"name": "Ansible Ad-Hoc", "hosts": ips, "gather_facts": "no",
                   "tasks": [{"action": {"module": "setup", "args": ""}}]}
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
    tqm = None
    try:
        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            options=options,
            passwords=None,
            stdout_callback=resultcallback,
            run_tree=False,
        )
        tqm.run(play)
        return ansible_facts_info
    finally:
        if tqm is not None:
            tqm.cleanup()
Beispiel #9
0
    def runansible(self,host_list, task_list):

        play_source =  dict(
            name = "Ansible Play",
            hosts = host_list,
            gather_facts = 'no',
            tasks = task_list
        )
    
        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,
           passwords=self.passwords,
           stdout_callback=self.callback,
           )

        result = tqm.run(play)
        result_raw = {'success':{},'failed':{},'unreachable':{}}
        for host,result in self.callback.host_ok.items():
            result_raw['success'][host] = result._result
        for host,result in self.callback.host_failed.items():
            result_raw['failed'][host] = result._result
        for host,result in self.callback.host_unreachable.items():
            result_raw['unreachable'][host] = result._result

        js = json.dumps(result_raw, sort_keys=False, indent=4)
        
        return js
def AnsibleTask(task_list,host_list,user):
    '''ansible python api 2.0'''
    loader = DataLoader()
    variable_manager = VariableManager()
    inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=host_list)
    variable_manager.set_inventory(inventory)
    task_dict = []
    for i in task_list:
        task_dict.append({"action": {"module": i[0], "args": i[1] }})
    variable_manager.extra_vars = {"ansible_ssh_user": user, "ansible_ssh_pass": ""}
    play_source = {"name" : "Ansible PlayBook Run", "hosts": host_list[0], "gather_facts": "no","tasks": task_dict}
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
    tqm = None
    try:
        tqm = TaskQueueManager(
            inventory = inventory,
            variable_manager = variable_manager,
            loader = loader,
            options = options,
            passwords = None,
            stdout_callback = 'minimal',
            run_tree = False,
        )
        result = tqm.run(play)
    except Exception,e:
        result = e
Beispiel #11
0
def run_adhoc():
    variable_manager.extra_vars = {
        "ansible_ssh_user": "******", "ansible_ssh_pass": "******"
    }  # 增加外部变量
    # 构建pb, 这里很有意思, 新版本运行ad-hoc或playbook都需要构建这样的pb, 只是最后调用play的类不一样
    # :param name: 任务名,类似playbook中tasks中的name
    # :param hosts: playbook中的hosts
    # :param tasks: playbook中的tasks, 其实这就是playbook的语法, 因为tasks的值是个列表,因此可以写入多个task
    play_source = {
        "name": "Ansible Ad-Hoc",
        "hosts": "localhost",
        "gather_facts": "no",
        "tasks": [
            {"action": {"module": "shell", "args": "w"}}
        ]
    }
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
    tqm = None
    try:
        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            options=options,
            passwords=None,
            stdout_callback='minimal',
            run_tree=False,
        )
        result = tqm.run(play)
        print result
    finally:
        if tqm is not None:
            tqm.cleanup()
Beispiel #12
0
def main():
    host_list = ['localhost', 'www.example.com', 'www.google.com']
    Options = namedtuple('Options', ['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'])

    # initialize needed objects
    variable_manager = VariableManager()
    loader = DataLoader()
    options = Options(connection='smart', module_path='/usr/share/ansible', forks=100,
                      remote_user=None, 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=None, verbosity=None, check=False)

    passwords = dict()

    # create inventory and pass to var manager
    inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=host_list)
    variable_manager.set_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,
            options=options,
            passwords=passwords,
        )
        tqm._stdout_callback = callback
        result = tqm.run(play)
    finally:
        if tqm is not None:
            tqm.cleanup()

    print("UP ***********")
    for host, result in callback.host_ok.items():
        print('{} >>> {}'.format(host, result._result['stdout']))

    print("FAILED *******")
    for host, result in callback.host_failed.items():
        print('{} >>> {}'.format(host, result._result['msg']))

    print("DOWN *********")
    for host, result in callback.host_unreachable.items():
        print('{} >>> {}'.format(host, result._result['msg']))
    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
        """
        self.results_raw = {'success':{}, 'failed':{}, 'unreachable':{}}
        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'])


        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)

        passwords = dict(sshpass=None, becomepass=None)

        # 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
        callback = ResultsCollector()
        try:
            tqm = TaskQueueManager(
                    inventory=self.inventory,
                    variable_manager=self.variable_manager,
                    loader=self.loader,
                    options=options,
                    passwords=passwords,
            )
            tqm._stdout_callback = callback
            result = tqm.run(play)
        finally:
            if tqm is not None:
                tqm.cleanup()

        for host, result in callback.host_ok.items():
            self.results_raw['success'][host] = result._result.get('stdout') + result._result.get('stderr')

        for host, result in callback.host_failed.items():
            self.results_raw['failed'][host] = result._result.get('stdout') + result._result.get('stderr')

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

        logger.info(self.results_raw)
        return self.results_raw
def main(args):
    # Options definition
    # Custom tuple to store playbook options
    Options = namedtuple('Options', ['connection', 'module_path', 'forks',
                                     'become', 'become_method', 'become_user',
                                     'check'])

    # Object initialization
    variable_manager = VariableManager()
    loader = DataLoader()
    options = Options(connection='ssh',module_path='library',
                      forks=100, become=None, become_method=None,
                      become_user=None, check=False)
    passwords = {}

    # Dinamyc inventory
    inventory = Inventory(loader=loader, variable_manager=variable_manager,
                          host_list=args)

    # Inventory assignation
    variable_manager.set_inventory(inventory)

    # Play creation with tasks
    play_source = dict(
         name="Ansible Play",
         hosts=args,
         gather_facts='no',
         tasks=[
             dict(action=dict(module='shell', args='hostname -f'),
                  register='shell_out'),
             dict(action=dict(module='debug',
                              args=dict(msg='{{shell_out.stdout}}')))
         ]
    )

    play = Play().load(play_source, variable_manager=variable_manager,
                       loader=loader)

    # Running it
    tqm = None
    try:
        tqm = TaskQueueManager(
                      inventory=inventory,
                      variable_manager=variable_manager,
                      loader=loader,
                      options=options,
                      passwords=passwords,
                      stdout_callback='default'
        )
        result = tqm.run(play)
    finally:
        if tqm is not None:
                    tqm.cleanup()
Beispiel #15
0
def main(argv=sys.argv[1:]):
    Options = namedtuple('Options', ['connection', 'module_path', 'forks',
                                     'become', 'become_method', 'become_user',
                                     'check'])
    # initialize needed objects
    variable_manager = VariableManager()
    loader = DataLoader()
    options = Options(connection='local', module_path='/path/to/mymodules',
                      forks=100, become=None, become_method=None,
                      become_user=None,
                      check=False)

    passwords = dict(vault_pass='******')

    # create inventory and pass to var manager
    inventory = Inventory(loader=loader, variable_manager=variable_manager,
                          host_list='localhost')

    variable_manager.set_inventory(inventory)

    # create play with tasks
    play_source = dict(name="Ansible Play",
                       hosts='localhost',
                       gather_facts='no',
                       tasks=[
                           dict(action=dict(module='shell',
                                args='uname -a'), register='shell_out'),
                           dict(action=dict(module='debug',
                                args=dict(msg='{{shell_out.stdout}}')))
                       ]
                       )

    play = Play().load(play_source, variable_manager=variable_manager,
                       loader=loader)

    # actually run it
    tqm = None
    try:
        tqm = TaskQueueManager(inventory=inventory,
                               variable_manager=variable_manager,
                               loader=loader,
                               options=options,
                               passwords=passwords,
                               stdout_callback='default',
                               )

        result = tqm.run(play)
        print result
    finally:
        if tqm is not None:
            tqm.cleanup()
    def test_base(self):
        test_inv_dir = 'test/inventory'
        for inv in os.listdir(test_inv_dir):
            print "Processing ", inv
            res = dynlxc.main(os.path.join(test_inv_dir, inv), '')

            variable_manager = VariableManager()
            loader = DataLoader()
            self.mock_rv.communicate.return_value = [
                json.dumps(res), 'mocked_err']
            try:
                inventory = Inventory(
                    loader=loader,
                    variable_manager=variable_manager,
                    host_list='inventory/dynlxc.py'
                )
            except Exception as err:
                raise Exception("Inventory file {0} processing result '{1}' "
                                "failed with {2}".format(inv, res, err))
            variable_manager.set_inventory(inventory)

            play_source = dict(name="Ansible Play", hosts='localhost',
                               gather_facts='no')

            playbook = os.path.abspath(os.path.join(test_inv_dir,
                                       '../playbooks', inv))
            if os.path.isfile(playbook):
                with open(playbook) as fh:
                    real_playbook = yaml.load(fh)[0]
                    play_source.update(real_playbook)

            play = Play().load(play_source, variable_manager=variable_manager,
                               loader=loader)
            tqm = None
            try:
                tqm = TaskQueueManager(
                    inventory=inventory,
                    variable_manager=variable_manager,
                    loader=loader,
                    options=self.options,
                    passwords=None,
                    stdout_callback='default',
                )
                result = tqm.run(play)
                assert result == 0, ("Ansible playbook exitcode "
                                     "different from 0")
            finally:
                if tqm is not None:
                    tqm.cleanup()
    def test_strategy_base_run_handlers(self, mock_worker):
        def fake_run(*args):
            return
        mock_worker.side_effect = fake_run
        mock_play_context = MagicMock()

        mock_handler_task = MagicMock(Handler)
        mock_handler_task.action = 'foo'
        mock_handler_task.get_name.return_value = "test handler"
        mock_handler_task.has_triggered.return_value = False

        mock_handler = MagicMock()
        mock_handler.block = [mock_handler_task]
        mock_handler.flag_for_host.return_value = False

        mock_play = MagicMock()
        mock_play.handlers = [mock_handler]

        mock_host = MagicMock(Host)
        mock_host.name = "test01"
        mock_host.has_hostkey = True

        mock_inventory = MagicMock()
        mock_inventory.get_hosts.return_value = [mock_host]

        mock_var_mgr = MagicMock()
        mock_var_mgr.get_vars.return_value = dict()

        mock_iterator = MagicMock
        mock_iterator._play = mock_play

        fake_loader = DictDataLoader()
        mock_options = MagicMock()
        mock_options.module_path = None

        tqm = TaskQueueManager(
            inventory=mock_inventory,
            variable_manager=mock_var_mgr,
            loader=fake_loader,
            options=mock_options,
            passwords=None,
        )
        tqm._initialize_processes(3)
        tqm._initialize_notified_handlers(mock_play)
        tqm.hostvars = dict()

        try:
            strategy_base = StrategyBase(tqm=tqm)

            strategy_base._inventory = mock_inventory
            strategy_base._notified_handlers = {mock_handler_task: [mock_host]}

            task_result = TaskResult(Host('host01'), Handler(), dict(changed=False))
            tqm._final_q.put(('host_task_ok', task_result))

            result = strategy_base.run_handlers(iterator=mock_iterator, play_context=mock_play_context)
        finally:
            tqm.cleanup()
Beispiel #18
0
 def run(self):
     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,
         )
         for name, play in self.plays.items():
             result = tqm.run(play)
     finally:
         if tqm is not None:
             tqm.cleanup()
Beispiel #19
0
    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()
Beispiel #20
0
    def __init__(self, playbooks, inventory, variable_manager, loader, options):
        self._playbooks        = playbooks
        self._inventory        = inventory
        self._variable_manager = variable_manager
        self._loader           = loader
        self._options          = options

        self._tqm = TaskQueueManager(inventory=inventory, callback='default', variable_manager=variable_manager, loader=loader, options=options)
def run(play):
    tqm = None
    results = None
    try:
        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            options=options,
            passwords=passwords,
            stdout_callback='default',
        )
        results = tqm.run(play)
    finally:
        if tqm is not None:
            tqm.cleanup()
    return tqm, results
Beispiel #22
0
    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()
Beispiel #23
0
def execute_tasks(play_name, tasks, hosts, host_list=os.path.join(DIRNAME, 'ansible_hosts.py'), callback="default"):
    # NOTICE: Here is a trick. The host we acquired must in the host list
    # everytime. However I can't get the host list in advance. So I add the
    # hosts into the host list eveytime if it doesn't exist.
    if hosts not in ansible_hosts.hosts["all"]["hosts"]:
        ansible_hosts.hosts["all"]["hosts"].append(hosts)

    # initialize needed objects
    variable_manager = VariableManager()
    loader = DataLoader()

    # create inventory and pass to var manager
    inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=host_list)
    variable_manager.set_inventory(inventory)

    # create play with tasks
    play_source = dict(
        name=play_name,
        hosts=hosts,
        gather_facts='no',
        tasks=tasks)

    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

    Options = namedtuple('Options', ['connection', 'module_path', 'forks',
        'become', 'become_method', 'become_user', 'check'])
    options = Options(connection=None, module_path=None, forks=10, become=None,
        become_method=None, become_user=None, check=False)
    passwords = dict()

    # actually run it
    tqm = None
    try:
        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            options=options,
            passwords=passwords,
            stdout_callback=callback)
        return tqm.run(play)
    finally:
        if tqm is not None:
            tqm.cleanup()
        pass
 def run(self):
     result = {}
     results_callback = ResultCallback()
     try:
         tqm = TaskQueueManager(
             inventory=self.inventory,
             variable_manager=self.variable_manager,
             loader=self.loader,
             options=self.options,
             passwords=self.passwords,
             stdout_callback=results_callback
         )
         tqm.run(self.play)
     finally:
         result = results_callback.result
         if tqm is not None:
             tqm.cleanup()
     return result
Beispiel #25
0
    def run(self):
        self.variable_manager.set_inventory(self.inventory)
        play = Play().load(self.create_play_tasks(),
                           variable_manager=self.variable_manager, loader=self.loader)
        tqm = None
        callback = ResultsCollector()

        tqm = TaskQueueManager(
            inventory=self.inventory,
            variable_manager=self.variable_manager,
            loader=self.loader,
            options=self.options,
            passwords=self.passwords
        )
        tqm._stdout_callback = callback
        result = tqm.run(play)

        return result, callback
Beispiel #26
0
    def run(self, playbook):
        pb = Playbook.load(playbook, variable_manager=self.variable_manager, loader=self.loader)
        # only support one playbook.yml
        play = pb.get_plays()[0]

        tqm = None
        try:
            tqm = TaskQueueManager(
                inventory=self.inventory,
                variable_manager=self.variable_manager,
                loader=self.loader,
                options=self.options,
                passwords={'conn_pass': None, 'become_pass': None},
                stdout_callback=self.callback,
            )
            return tqm.run(play), self.callback.result
        finally:
            if tqm is not None:
                tqm.cleanup()
Beispiel #27
0
 def _run_play(self, play_src):
     self.options = options = self.Options(**self.options_args)
     vm = self.variable_manager
     vm.extra_vars = load_extra_vars(loader=self.loader, options=options)
     play = Play().load(play_src, loader=self.loader, variable_manager=vm)
     tqm = None
     try:
         tqm = TaskQueueManager(
             inventory=self.inventory,
             variable_manager=vm,
             loader=self.loader,
             options=options,
             passwords=dict(),
             stdout_callback='default')
         tqm.run(play)
         return vm.get_vars(self.loader)
     finally:
         if tqm is not None:
             tqm.cleanup()
Beispiel #28
0
    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)
        context.CLIARGS = ImmutableDict(self.options)

        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,
            stdout_callback=self.results_callback,
            passwords={"conn_pass": self.options.get("password", "")}
        )
        try:
            tqm.run(play)
            return self.results_callback
        except Exception as e:
            raise AnsibleError(e)
        finally:
            if tqm is not None:
                tqm.cleanup()
            shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
Beispiel #29
0
 def ansible_play(self):
     # run it
     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,
             # stdout_callback='default',
         )
         result = tqm.run(self.play)
     finally:
         if tqm is not None:
             tqm.cleanup()
             #self.inventory.clear_pattern_cache()
         if result != 0:
             raise ValueError('SSH Command Failed, resturn: %s' % result)
         return self.return_results
 def run(self, callback=None):
     self.variable_manager.set_inventory(self.inventory)
     play = Play().load(self.create_play_tasks(),
                        variable_manager=self.variable_manager, loader=self.loader)
     tqm = None
     if not callback:
         callback = ResultsCollector()
     try:
         tqm = TaskQueueManager(
             inventory=self.inventory,
             variable_manager=self.variable_manager,
             loader=self.loader,
             options=self.options,
             passwords=self.passwords,
             stdout_callback=callback
         )
         result = tqm.run(play)
     finally:
         if tqm is not None:
             tqm.cleanup()
     return result, callback
Beispiel #31
0
class PlaybookExecutor:

    '''
    This is the primary class for executing playbooks, and thus the
    basis for bin/ansible-playbook operation.
    '''

    def __init__(self, playbooks, inventory, variable_manager, loader, display, options, passwords):
        self._playbooks        = playbooks
        self._inventory        = inventory
        self._variable_manager = variable_manager
        self._loader           = loader
        self._display          = display
        self._options          = options
        self.passwords         = passwords

        if options.listhosts or options.listtasks or options.listtags:
            self._tqm = None
        else:
            self._tqm = TaskQueueManager(inventory=inventory, callback='default', variable_manager=variable_manager, loader=loader, display=display, options=options, passwords=self.passwords)

    def run(self):

        '''
        Run the given playbook, based on the settings in the play which
        may limit the runs to serialized groups, etc.
        '''

        signal.signal(signal.SIGINT, self._cleanup)

        result = 0
        entrylist = []
        entry = {}
        try:
            for playbook_path in self._playbooks:
                pb = Playbook.load(playbook_path, variable_manager=self._variable_manager, loader=self._loader)

                if self._tqm is None: # we are doing a listing
                    entry = {'playbook': playbook_path}
                    entry['plays'] = []

                i = 1
                plays = pb.get_plays()
                self._display.vv('%d plays in %s' % (len(plays), playbook_path))

                for play in plays:
                    self._inventory.remove_restriction()

                    # Create a temporary copy of the play here, so we can run post_validate
                    # on it without the templating changes affecting the original object.
                    all_vars = self._variable_manager.get_vars(loader=self._loader, play=play)
                    new_play = play.copy()
                    new_play.post_validate(all_vars, fail_on_undefined=False)

                    if self._tqm is None:
                        # we are just doing a listing

                        pname =  new_play.get_name().strip()
                        if pname == 'PLAY: <no name specified>':
                            pname = 'PLAY: #%d' % i
                        p = { 'name': pname }

                        if self._options.listhosts:
                            p['pattern']=play.hosts
                            p['hosts']=set(self._inventory.get_hosts(new_play.hosts))

                        #TODO: play tasks are really blocks, need to figure out how to get task objects from them
                        elif self._options.listtasks:
                            p['tasks'] = []
                            for task in play.get_tasks():
                               p['tasks'].append(task)
                               #p['tasks'].append({'name': task.get_name().strip(), 'tags': task.tags})

                        elif self._options.listtags:
                            p['tags'] = set(new_play.tags)
                            for task in play.get_tasks():
                                p['tags'].update(task)
                                #p['tags'].update(task.tags)
                        entry['plays'].append(p)

                    else:
                        # we are actually running plays
                        for batch in self._get_serialized_batches(new_play):
                            if len(batch) == 0:
                                self._tqm.send_callback('v2_playbook_on_play_start', new_play)
                                self._tqm.send_callback('v2_playbook_on_no_hosts_matched')
                                result = 0
                                break
                            # restrict the inventory to the hosts in the serialized batch
                            self._inventory.restrict_to_hosts(batch)
                            # and run it...
                            result = self._tqm.run(play=play)
                            if result != 0:
                                break

                        if result != 0:
                            break

                    i = i + 1 # per play

                if entry:
                    entrylist.append(entry) # per playbook

            if entrylist:
                return entrylist

        finally:
            if self._tqm is not None:
                self._cleanup()

        # FIXME: this stat summary stuff should be cleaned up and moved
        #        to a new method, if it even belongs here...
        self._display.banner("PLAY RECAP")

        hosts = sorted(self._tqm._stats.processed.keys())
        for h in hosts:
            t = self._tqm._stats.summarize(h)

            self._display.display("%s : %s %s %s %s" % (
                hostcolor(h, t),
                colorize('ok', t['ok'], 'green'),
                colorize('changed', t['changed'], 'yellow'),
                colorize('unreachable', t['unreachable'], 'red'),
                colorize('failed', t['failures'], 'red')),
                screen_only=True
            )

            self._display.display("%s : %s %s %s %s" % (
                hostcolor(h, t, False),
                colorize('ok', t['ok'], None),
                colorize('changed', t['changed'], None),
                colorize('unreachable', t['unreachable'], None),
                colorize('failed', t['failures'], None)),
                log_only=True
            )

        self._display.display("", screen_only=True)
        # END STATS STUFF

        return result

    def _cleanup(self, signum=None, framenum=None):
        return self._tqm.cleanup()

    def _get_serialized_batches(self, play):
        '''
        Returns a list of hosts, subdivided into batches based on
        the serial size specified in the play.
        '''

        # make sure we have a unique list of hosts
        all_hosts = self._inventory.get_hosts(play.hosts)

        # check to see if the serial number was specified as a percentage,
        # and convert it to an integer value based on the number of hosts
        if isinstance(play.serial, basestring) and play.serial.endswith('%'):
            serial_pct = int(play.serial.replace("%",""))
            serial = int((serial_pct/100.0) * len(all_hosts))
        else:
            serial = int(play.serial)

        # if the serial count was not specified or is invalid, default to
        # a list of all hosts, otherwise split the list of hosts into chunks
        # which are based on the serial size
        if serial <= 0:
            return [all_hosts]
        else:
            serialized_batches = []

            while len(all_hosts) > 0:
                play_hosts = []
                for x in range(serial):
                    if len(all_hosts) > 0:
                        play_hosts.append(all_hosts.pop(0))

                serialized_batches.append(play_hosts)

            return serialized_batches
Beispiel #32
0
    def default(self, line, forceshell=False):
        """ actually runs modules """
        if line.startswith("#"):
            return False

        if not self.cwd:
            display.error("No host found")
            return False

        # defaults
        module = 'shell'
        module_args = line

        if forceshell is not True:
            possible_module, *possible_args = line.split()
            if module_loader.find_plugin(possible_module):
                # we found module!
                module = possible_module
                if possible_args:
                    module_args = ' '.join(possible_args)
                else:
                    module_args = ''

        if self.callback:
            cb = self.callback
        elif C.DEFAULT_LOAD_CALLBACK_PLUGINS and C.DEFAULT_STDOUT_CALLBACK != 'default':
            cb = C.DEFAULT_STDOUT_CALLBACK
        else:
            cb = 'minimal'

        result = None
        try:
            check_raw = module in C._ACTION_ALLOWS_RAW_ARGS
            task = dict(action=dict(module=module,
                                    args=parse_kv(module_args,
                                                  check_raw=check_raw)),
                        timeout=self.task_timeout)
            play_ds = dict(
                name="Ansible Shell",
                hosts=self.cwd,
                gather_facts='no',
                tasks=[task],
                remote_user=self.remote_user,
                become=self.become,
                become_user=self.become_user,
                become_method=self.become_method,
                check_mode=self.check_mode,
                diff=self.diff,
                collections=self.collections,
            )
            play = Play().load(play_ds,
                               variable_manager=self.variable_manager,
                               loader=self.loader)
        except Exception as e:
            display.error(u"Unable to build command: %s" % to_text(e))
            return False

        try:
            # now create a task queue manager to execute the play
            self._tqm = None
            try:
                self._tqm = TaskQueueManager(
                    inventory=self.inventory,
                    variable_manager=self.variable_manager,
                    loader=self.loader,
                    passwords=self.passwords,
                    stdout_callback=cb,
                    run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS,
                    run_tree=False,
                    forks=self.forks,
                )

                result = self._tqm.run(play)
                display.debug(result)
            finally:
                if self._tqm:
                    self._tqm.cleanup()
                if self.loader:
                    self.loader.cleanup_all_tmp_files()

            if result is None:
                display.error("No hosts found")
                return False
        except KeyboardInterrupt:
            display.error('User interrupted execution')
            return False
        except Exception as e:
            if self.verbosity >= 3:
                import traceback
                display.v(traceback.format_exc())
            display.error(to_text(e))
            return False
Beispiel #33
0
        'gather_facts' : 'False',
        'tasks' : [
            {
                'name' : 'shell',
                'shell' : 'ls /',
                'register' : 'result',
            },
            {
                'debug' : {
                    'msg' : ' {{ result.stdout }}',
                }
            }
        ]
    }

    play = Play().load(source, variable_manager=variable_manager, loader=loader)

    tqm = None
    tqm = TaskQueueManager(inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            options=options,
            passwords=passwords,
            stdout_callback=callback
        )

    result = tqm.run(play)

    if tqm:
        tqm.cleanup()
Beispiel #34
0
class AdHocCLI(CLI):
    ''' code behind ansible ad-hoc cli'''
    def parse(self):
        ''' create an options parser for bin/ansible '''

        self.parser = CLI.base_parser(
            usage='%prog <host-pattern> [options]',
            runas_opts=True,
            async_opts=True,
            output_opts=True,
            connect_opts=True,
            check_opts=True,
            runtask_opts=True,
            vault_opts=True,
            fork_opts=True,
        )

        # options unique to ansible ad-hoc
        self.parser.add_option('-a',
                               '--args',
                               dest='module_args',
                               help="module arguments",
                               default=C.DEFAULT_MODULE_ARGS)
        self.parser.add_option('-m',
                               '--module-name',
                               dest='module_name',
                               help="module name to execute (default=%s)" %
                               C.DEFAULT_MODULE_NAME,
                               default=C.DEFAULT_MODULE_NAME)

        self.options, self.args = self.parser.parse_args()

        if len(self.args) != 1:
            raise AnsibleOptionsError("Missing target hosts")

        self.display.verbosity = self.options.verbosity
        self.validate_conflicts(runas_opts=True,
                                vault_opts=True,
                                fork_opts=True)

        return True

    def _play_ds(self, pattern):
        return dict(
            name="Ansible Ad-Hoc",
            hosts=pattern,
            gather_facts='no',
            tasks=[
                dict(action=dict(module=self.options.module_name,
                                 args=parse_kv(self.options.module_args))),
            ])

    def run(self):
        ''' use Runner lib to do SSH things '''

        super(AdHocCLI, self).run()

        # only thing left should be host pattern
        pattern = self.args[0]

        # ignore connection password cause we are local
        if self.options.connection == "local":
            self.options.ask_pass = False

        sshpass = None
        becomepass = None
        vault_pass = None

        self.normalize_become_options()
        (sshpass, becomepass) = self.ask_passwords()
        passwords = {'conn_pass': sshpass, 'become_pass': becomepass}

        if self.options.vault_password_file:
            # read vault_pass from a file
            vault_pass = CLI.read_vault_password_file(
                self.options.vault_password_file)
        elif self.options.ask_vault_pass:
            vault_pass = self.ask_vault_passwords(ask_vault_pass=True,
                                                  ask_new_vault_pass=False,
                                                  confirm_new=False)[0]

        loader = DataLoader(vault_password=vault_pass)
        variable_manager = VariableManager()
        variable_manager.extra_vars = load_extra_vars(loader=loader,
                                                      options=self.options)

        inventory = Inventory(loader=loader,
                              variable_manager=variable_manager,
                              host_list=self.options.inventory)
        variable_manager.set_inventory(inventory)

        hosts = inventory.list_hosts(pattern)
        if len(hosts) == 0:
            self.display.warning(
                "provided hosts list is empty, only localhost is available")

        if self.options.listhosts:
            self.display.display('  hosts (%d):' % len(hosts))
            for host in hosts:
                self.display.display('    %s' % host)
            return 0

        if self.options.module_name in C.MODULE_REQUIRE_ARGS and not self.options.module_args:
            err = "No argument passed to %s module" % self.options.module_name
            if pattern.endswith(".yml"):
                err = err + ' (did you mean to run ansible-playbook?)'
            raise AnsibleOptionsError(err)

        #TODO: implement async support
        #if self.options.seconds:
        #    callbacks.display("background launch...\n\n", color='cyan')
        #    results, poller = runner.run_async(self.options.seconds)
        #    results = self.poll_while_needed(poller)
        #else:
        #    results = runner.run()

        # create a pseudo-play to execute the specified module via a single task
        play_ds = self._play_ds(pattern)
        play = Play().load(play_ds,
                           variable_manager=variable_manager,
                           loader=loader)

        if self.options.one_line:
            cb = 'oneline'
        else:
            cb = 'minimal'

        if self.options.tree:
            C.DEFAULT_CALLBACK_WHITELIST.append('tree')
            C.TREE_DIR = self.options.tree

        # now create a task queue manager to execute the play
        self._tqm = None
        try:
            self._tqm = TaskQueueManager(
                inventory=inventory,
                variable_manager=variable_manager,
                loader=loader,
                display=self.display,
                options=self.options,
                passwords=passwords,
                stdout_callback=cb,
            )
            result = self._tqm.run(play)
        finally:
            if self._tqm:
                self._tqm.cleanup()

        return result

    # ----------------------------------------------

    def poll_while_needed(self, poller):
        ''' summarize results from Runner '''

        # BACKGROUND POLL LOGIC when -B and -P are specified
        if self.options.seconds and self.options.poll_interval > 0:
            poller.wait(self.options.seconds, self.options.poll_interval)

        return poller.results
Beispiel #35
0
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
Beispiel #36
0
class PlaybookExecutor:

    '''
    This is the primary class for executing playbooks, and thus the
    basis for bin/ansible-playbook operation.
    '''

    def __init__(self, playbooks, inventory, variable_manager, loader, options, passwords, callback=None):
        self._playbooks        = playbooks
        self._inventory        = inventory
        self._variable_manager = variable_manager
        self._loader           = loader
        self._options          = options
        self.passwords         = passwords
        self.callback          = callback
        self._unreachable_hosts = dict()

        if options.listhosts or options.listtasks or options.listtags or options.syntax:
            self._tqm = None
        else:
            self._tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=self.passwords,stdout_callback=callback)

    def run(self):

        '''
        Run the given playbook, based on the settings in the play which
        may limit the runs to serialized groups, etc.
        '''

        result = 0
        entrylist = []
        entry = {}
        try:
            for playbook_path in self._playbooks:
                pb = Playbook.load(playbook_path, variable_manager=self._variable_manager, loader=self._loader)
                self._inventory.set_playbook_basedir(os.path.dirname(playbook_path))

                if self._tqm is None: # we are doing a listing
                    entry = {'playbook': playbook_path}
                    entry['plays'] = []
                else:
                    # make sure the tqm has callbacks loaded
                    self._tqm.load_callbacks()
                    self._tqm.send_callback('v2_playbook_on_start', pb)

                i = 1
                plays = pb.get_plays()
                display.vv(u'%d plays in %s' % (len(plays), to_unicode(playbook_path)))

                for play in plays:
                    if play._included_path is not None:
                        self._loader.set_basedir(play._included_path)
                    else:
                        self._loader.set_basedir(pb._basedir)

                    # clear any filters which may have been applied to the inventory
                    self._inventory.remove_restriction()

                    if play.vars_prompt:
                        for var in play.vars_prompt:
                            vname     = var['name']
                            prompt    = var.get("prompt", vname)
                            default   = var.get("default", None)
                            private   = var.get("private", True)
                            confirm   = var.get("confirm", False)
                            encrypt   = var.get("encrypt", None)
                            salt_size = var.get("salt_size", None)
                            salt      = var.get("salt", None)

                            if vname not in self._variable_manager.extra_vars:
                                if self._tqm:
                                    self._tqm.send_callback('v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt, default)
                                    play.vars[vname] = display.do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default)
                                else: # we are either in --list-<option> or syntax check
                                    play.vars[vname] = default

                    # Create a temporary copy of the play here, so we can run post_validate
                    # on it without the templating changes affecting the original object.
                    all_vars = self._variable_manager.get_vars(loader=self._loader, play=play)
                    templar = Templar(loader=self._loader, variables=all_vars)
                    new_play = play.copy()
                    new_play.post_validate(templar)

                    if self._options.syntax:
                        continue

                    if self._tqm is None:
                        # we are just doing a listing
                        entry['plays'].append(new_play)

                    else:
                        self._tqm._unreachable_hosts.update(self._unreachable_hosts)

                        previously_failed = len(self._tqm._failed_hosts)
                        previously_unreachable = len(self._tqm._unreachable_hosts)

                        break_play = False
                        # we are actually running plays
                        for batch in self._get_serialized_batches(new_play):
                            if len(batch) == 0:
                                self._tqm.send_callback('v2_playbook_on_play_start', new_play)
                                self._tqm.send_callback('v2_playbook_on_no_hosts_matched')
                                break

                            # restrict the inventory to the hosts in the serialized batch
                            self._inventory.restrict_to_hosts(batch)
                            # and run it...
                            result = self._tqm.run(play=play)

                            # break the play if the result equals the special return code
                            if result == self._tqm.RUN_FAILED_BREAK_PLAY:
                                result = self._tqm.RUN_FAILED_HOSTS
                                break_play = True

                            # check the number of failures here, to see if they're above the maximum
                            # failure percentage allowed, or if any errors are fatal. If either of those
                            # conditions are met, we break out, otherwise we only break out if the entire
                            # batch failed
                            failed_hosts_count = len(self._tqm._failed_hosts) + len(self._tqm._unreachable_hosts) - \
                                                 (previously_failed + previously_unreachable)
                            if new_play.max_fail_percentage is not None and \
                               int((new_play.max_fail_percentage)/100.0 * len(batch)) > int((len(batch) - failed_hosts_count) / len(batch) * 100.0):
                                break_play = True
                                break
                            elif len(batch) == failed_hosts_count:
                                break_play = True
                                break

                            # save the unreachable hosts from this batch
                            self._unreachable_hosts.update(self._tqm._unreachable_hosts)

                            # if the last result wasn't zero or 3 (some hosts were unreachable),
                            # break out of the serial batch loop
                            if result not in (self._tqm.RUN_OK, self._tqm.RUN_UNREACHABLE_HOSTS):
                                break

                        if break_play:
                            break

                    i = i + 1 # per play

                if entry:
                    entrylist.append(entry) # per playbook

                # send the stats callback for this playbook
                if self._tqm is not None:
                    if C.RETRY_FILES_ENABLED:
                        retries = set(self._tqm._failed_hosts.keys())
                        retries.update(self._tqm._unreachable_hosts.keys())
                        retries = sorted(retries)
                        if len(retries) > 0:
                            if C.RETRY_FILES_SAVE_PATH:
                                basedir = C.shell_expand(C.RETRY_FILES_SAVE_PATH)
                            elif playbook_path:
                                basedir = os.path.dirname(playbook_path)
                            else:
                                basedir = '~/'

                            (retry_name, _) = os.path.splitext(os.path.basename(playbook_path))
                            filename = os.path.join(basedir, "%s.retry" % retry_name)
                            if self._generate_retry_inventory(filename, retries):
                                display.display("\tto retry, use: --limit @%s\n" % filename)

                    self._tqm.send_callback('v2_playbook_on_stats', self._tqm._stats)

                # if the last result wasn't zero, break out of the playbook file name loop
                if result != 0:
                    break

            if entrylist:
                return entrylist

        finally:
            if self._tqm is not None:
                self._tqm.cleanup()
            if self._loader:
                self._loader.cleanup_all_tmp_files()

        if self._options.syntax:
            display.display("No issues encountered")
            return result

        return result

    def _get_serialized_batches(self, play):
        '''
        Returns a list of hosts, subdivided into batches based on
        the serial size specified in the play.
        '''

        # make sure we have a unique list of hosts
        all_hosts = self._inventory.get_hosts(play.hosts)

        # check to see if the serial number was specified as a percentage,
        # and convert it to an integer value based on the number of hosts
        if isinstance(play.serial, string_types) and play.serial.endswith('%'):
            serial_pct = int(play.serial.replace("%",""))
            serial = int((serial_pct/100.0) * len(all_hosts)) or 1
        else:
            if play.serial is None:
                serial = -1
            else:
                serial = int(play.serial)

        # if the serial count was not specified or is invalid, default to
        # a list of all hosts, otherwise split the list of hosts into chunks
        # which are based on the serial size
        if serial <= 0:
            return [all_hosts]
        else:
            serialized_batches = []

            while len(all_hosts) > 0:
                play_hosts = []
                for x in range(serial):
                    if len(all_hosts) > 0:
                        play_hosts.append(all_hosts.pop(0))

                serialized_batches.append(play_hosts)

            return serialized_batches

    def _generate_retry_inventory(self, retry_path, replay_hosts):
        '''
        Called when a playbook run fails. It generates an inventory which allows
        re-running on ONLY the failed hosts.  This may duplicate some variable
        information in group_vars/host_vars but that is ok, and expected.
        '''
        try:
            makedirs_safe(os.path.dirname(retry_path))
            with open(retry_path, 'w') as fd:
                for x in replay_hosts:
                    fd.write("%s\n" % x)
        except Exception as e:
            display.warning("Could not create retry file '%s'.\n\t%s" % (retry_path, to_str(e)))
            return False

        return True
Beispiel #37
0
    def _run(self,
             ips,
             key_file,
             play_file,
             expected_results=[0],
             play_vars={}):
        """
        Common code used for each run.

        :param ips: IP address(es) to check.
        :type ips: str or list
        :param key_file: Full path the the file holding the private SSH key.
        :type key_file: string
        :param play_file: Path to the ansible play file.
        :type play_file: str
        :param expected_results: List of expected return codes. Default: [0]
        :type expected_results: list
        :returns: Ansible exit code
        :type: int
        """
        if type(ips) != list:
            ips = [ips]

        ssh_args = ('-o StrictHostKeyChecking=no -o '
                    'ControlMaster=auto -o ControlPersist=60s')
        options = self.Options(connection='ssh',
                               module_path=None,
                               forks=1,
                               remote_user='******',
                               private_key_file=key_file,
                               ssh_common_args=ssh_args,
                               ssh_extra_args=ssh_args,
                               sftp_extra_args=None,
                               scp_extra_args=None,
                               become=None,
                               become_method=None,
                               become_user=None,
                               verbosity=None,
                               check=False)
        # create inventory and pass to var manager
        inventory = Inventory(loader=self.loader,
                              variable_manager=self.variable_manager,
                              host_list=ips)
        self.logger.debug('Options: {0}'.format(options))

        group = Group('commissaire_targets')
        for ip in ips:
            host = Host(ip, 22)
            group.add_host(host)

        inventory.groups.update({'commissaire_targets': group})
        self.logger.debug('Inventory: {0}'.format(inventory))

        self.variable_manager.set_inventory(inventory)

        play_source = self.loader.load_from_file(play_file)[0]
        play = Play().load(play_source,
                           variable_manager=self.variable_manager,
                           loader=self.loader)

        # Add any variables provided into the play
        play.vars.update(play_vars)

        self.logger.debug(
            'Running play for hosts {0}: play={1}, vars={2}'.format(
                ips, play_source, play.vars))

        # actually run it
        for cnt in range(0, 3):
            tqm = None
            try:
                tqm = TaskQueueManager(
                    inventory=inventory,
                    variable_manager=self.variable_manager,
                    loader=self.loader,
                    options=options,
                    passwords=self.passwords,
                    stdout_callback=LogForward(),
                )
                result = tqm.run(play)

                # Deal with unreachable hosts (result == 3) by retrying
                # up to 3 times, sleeping 5 seconds after each attempt.
                if result == 3 and cnt < 2:
                    self.logger.warn(
                        'One or more hosts in {0} is unreachable, '
                        'retrying in 5 seconds...'.format(ips))
                    sleep(5)
                else:
                    break
            finally:
                if tqm is not None:
                    self.logger.debug(
                        'Cleaning up after the TaskQueueManager.')
                    tqm.cleanup()

        if result in expected_results:
            self.logger.debug('{0}: Good result {1}'.format(ip, result))
            fact_cache = self.variable_manager._fact_cache.get(ip, {})
            return (result, fact_cache)

        self.logger.debug('{0}: Bad result {1}'.format(ip, result))
        raise Exception('Can not run for {0}'.format(ip))
Beispiel #38
0
class MyRunner:

    def __init__(self, resource):
        # Gets data from YAML/JSON files
        self.loader = DataLoader()

        # All the variables from all the various places
        self.variable_manager = VariableManager()

        # Set inventory, using most of above objects
        self.inventory = MyInventory(resource=resource, loader=self.loader, variable_manager=self.variable_manager)
        self.variable_manager.set_inventory(self.inventory)

    def init_options(self, connection='ssh', become=True):
        self.options = Options()
        self.options.connection = 'ssh'  # Need a connection type 'smart' or 'ssh'
        self.options.become = become
        self.options.become_method = 'sudo'
        self.options.become_user = '******'

    def init_task_queue_manager(self):
        # Become Pass Needed if not logging in as user root (do not support now)
        passwords = {'become_pass': ''}

        # set callback object
        self.results_callback = CallbackModule()

        # playbook
        self.tqm = TaskQueueManager(
            inventory=self.inventory,
            variable_manager=self.variable_manager,
            loader=self.loader,
            options=self.options,
            passwords=passwords,
            stdout_callback=self.results_callback,
        )

    def run(self, module_name='shell', module_args='', gather_facts=False, pattern='*', become=True):
        self.init_options(become=True)
        self.init_task_queue_manager()
        play_source = dict(
            name='Ansible Play',
            hosts=pattern,
            gather_facts=gather_facts,
            tasks=[
                dict(action=dict(module=module_name, args=module_args)),
            ]
        )

        self.play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)
        self.tqm.run(self.play)
        self.result_raw = self.results_callback.results
        return self.result_raw

    def close(self):
        self.tqm.cleanup()

    @property
    def results(self):
        """
        {'failed': {'localhost': ''}, 'ok': {'jumpserver': ''}}
        """
        result = {'failed': {}, 'ok': {}}

        results = self.result_raw[-1]
        tasks = results.get('tasks', {})
        hosts = tasks[0].get('hosts', {})

        for host, info in hosts.items():
            if info.get('unreachable') or info.get('failed'):
                result['failed'][host] = info.get('msg')
            else:
                if info.get('invocation').get('module_name') in ['raw', 'shell', 'command', 'script']:
                    if info.get('rc') == 0:
                        result['ok'][host] = info.get('stdout') + info.get('stderr')
                    else:
                        result['failed'][host] = info.get('stdout') + info.get('stderr')
                elif info.get('invocation').get('module_name') in ['setup']:
                    result['ok'][host] = info.get('ansible_facts')
                else:
                    if info.get('failed'):
                        result['failed'][host] = info.get('msg')
                    else:
                        result['ok'][host] = info.get('changed')
        return result
Beispiel #39
0
    def exec_ansible_api(self, playbooks_file):
        variable_manager = VariableManager()
        loader = DataLoader()

        ds = loader.load_from_file(playbooks_file)
        Options = namedtuple('Options', [
            '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'
        ])
        options = Options(connection='ssh',
                          module_path=None,
                          forks=100,
                          remote_user='******',
                          private_key_file='id_rsa',
                          ssh_common_args=None,
                          ssh_extra_args=None,
                          sftp_extra_args=None,
                          scp_extra_args=None,
                          become=None,
                          become_method=None,
                          become_user=None,
                          verbosity=None,
                          check=False)

        # create inventory and pass to var manager
        inventory = Inventory(loader=loader,
                              variable_manager=variable_manager,
                              host_list=Global.inventory)
        variable_manager.set_inventory(inventory)

        # Currently we are limiting to one playbook
        play_source = ds[0]
        play = Play().load(play_source,
                           variable_manager=variable_manager,
                           loader=loader)

        tqm = None
        try:
            tqm = TaskQueueManager(inventory=inventory,
                                   variable_manager=variable_manager,
                                   loader=loader,
                                   options=options,
                                   passwords=None,
                                   stdout_callback=Global.display)
            result = tqm.run(play)
            # Exit gdeploy in case of errors and user has explicitly set
            # not to ignore errors
            if result != 0 and Global.ignore_errors != 'yes':
                msg = "Error while executing playbook %s, exiting"\
                      %playbooks_file
                print msg
                Global.logger.error(msg)
                self.cleanup_and_quit(1)
            elif result != 0 and Global.ignore_errors == 'yes':
                msg = "Error while executing playbook %s, ignoring errors..."\
                      %playbooks_file
                Global.logger.error(msg)
                print msg
        except AnsibleError, e:
            print "%s" % e
    def execute(self, *args, **kwargs):
        """ Puts args and kwargs in a way ansible can understand. Calls ansible
        and interprets the result.

        """

        assert self.is_hooked_up, "the module should be hooked up to the api"

        self.module_args = module_args = self.get_module_args(args, kwargs)

        loader = DataLoader()
        inventory_manager = SourcelessInventoryManager(loader=loader)

        for server, port in self.api.servers:
            inventory_manager._inventory.add_host(server,
                                                  group='all',
                                                  port=port)

        for key, value in self.api.options.extra_vars.items():
            inventory_manager._inventory.set_variable('all', key, value)

        variable_manager = VariableManager(loader=loader,
                                           inventory=inventory_manager)

        play_source = {
            'name':
            "Suitable Play",
            'hosts':
            self.api.servers.hosts,
            'gather_facts':
            'no',
            'tasks': [{
                'action': {
                    'module': self.module_name,
                    'args': module_args,
                },
                'environment': self.api.environment
            }]
        }

        play = Play.load(play_source,
                         variable_manager=variable_manager,
                         loader=loader)

        log.info(u'running {}'.format(u'- {module_name}: {module_args}'.format(
            module_name=self.module_name, module_args=module_args)))

        start = datetime.utcnow()
        task_queue_manager = None
        callback = SilentCallbackModule()

        try:
            task_queue_manager = TaskQueueManager(
                inventory=inventory_manager,
                variable_manager=variable_manager,
                loader=loader,
                options=self.api.options,
                passwords=getattr(self.api.options, 'passwords', {}),
                stdout_callback=callback)
            task_queue_manager.run(play)
        finally:
            if task_queue_manager is not None:
                task_queue_manager.cleanup()

        log.info(u'took {} to complete'.format(datetime.utcnow() - start))

        return self.evaluate_results(callback)
Beispiel #41
0
def CallbackBaseAdHoc(hosts,
                      actions,
                      name="Ansible Play",
                      source=settings.ANSIBLE_SOURCE):
    '''
    :param hosts: 主机列表
    :param actions: 相关ad-hoc的指令,以字典形式 [dict(action=dict(module="shell", args="touch /tmp/bbb.txt", warn=False)),]
    :param name: 任务名称
    :param source ansible配置hosts文件
    :return:
    '''
    logger = logging.getLogger("django")
    dataLoader = DataLoader()
    inventory = InventoryManager(loader=dataLoader, sources=source)  #主机信息管理
    variableManager = VariableManager(loader=dataLoader,
                                      inventory=inventory)  #变量管理
    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"
    ])
    options = Options(connection='ssh',
                      remote_user=None,
                      ack_pass=None,
                      sudo_user=None,
                      forks=settings.ANSIBLE_FORKS,
                      sudo=None,
                      ask_sudo_pass=False,
                      verbosity=5,
                      module_path=None,
                      become=None,
                      become_method=None,
                      become_user=None,
                      check=False,
                      diff=False,
                      listhosts=None,
                      listtasks=None,
                      listtags=None,
                      syntax=None)
    play_source = dict(
        name=name,  # 任务名称
        hosts=hosts,  # 目标主机,可以填写具体主机也可以是主机组名称
        gather_facts="no",  # 是否收集主机配置信息
        tasks=actions  # tasks是具体执行的任务,列表形式,每个具体任务都是一个字典
    )
    play = Play().load(play_source,
                       variable_manager=variableManager,
                       loader=dataLoader)
    passwords = dict()  # 这个可以为空,因为在hosts文件中有配置或者密钥登陆
    callback = AdHocCallbackBase()

    tqm = TaskQueueManager(inventory=inventory,
                           variable_manager=variableManager,
                           loader=dataLoader,
                           options=options,
                           passwords=passwords,
                           stdout_callback=callback)
    logger_info = {"hosts": hosts, "actions": actions, "passwords": passwords}
    logger.info(str(logger_info))
    tqm.run(play)
    status_list = ['ok', 'failed', 'unreachable', 'skipped']
    result_raw = {"failed": {}, "unreachable": {}, "ok": {}, "skipped": {}}
    for status in status_list:
        for host, result in getattr(callback, 'host_' + status).items():
            result_raw[status][host] = result._result
            result_raw[status][host]["task"] = name
    logger.info(str(result_raw))
    result_raw = get_result(result_raw)
    return result_raw
            host = result._host
            print(json.dumps({host.name: result._result}, indent=4))

    context.CLIARGS = ImmutableDict(connection='local', module_path=['/to/mymodules'], forks=10, become=None,
                                    become_method=None, become_user=None, check=False, diff=False)

    loader = DataLoader()
    passwords = dict(vault_pass='******')
    results_callback = ResultCallback()
    inventory = InventoryManager(loader=loader, sources='localhost,')
    variable_manager = VariableManager(loader=loader, inventory=inventory)

    play = Play().load(playbook_path, variable_manager=variable_manager, loader=loader)

    tqm = None
    try:
        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
        )
        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
        if tqm is not None:
            tqm.cleanup()

        # Remove ansible tmpdir
        shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
Beispiel #43
0
def run_ansible(module_name, module_args, host_list, ansible_user="******"):
    """ansible api"""
    # 负责查找和读取yaml、json和ini文件
    loader = DataLoader()

    # 初始化需要的对象
    Options = namedtuple('Options', [
        'connection', 'module_path', 'forks', 'become', 'become_method',
        'private_key_file', 'become_user', 'remote_user', 'check', 'diff'
    ])
    options = Options(connection='ssh',
                      module_path=None,
                      forks=5,
                      become=True,
                      become_method='sudo',
                      private_key_file="/root/.ssh/id_rsa",
                      become_user='******',
                      remote_user=ansible_user,
                      check=False,
                      diff=False)

    passwords = dict(vault_pass='******')

    # 实例化ResultCallback来处理结果
    callback = ResultsCollector()

    # 创建库存(inventory)并传递给VariableManager
    inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts'])

    # 管理变量的类,包括主机,组,扩展等变量
    variable_manager = VariableManager(loader=loader, inventory=inventory)

    # 创建任务
    host = ",".join(host_list)

    play_source = dict(name="Ansible Play",
                       hosts=host,
                       gather_facts='no',
                       tasks=[
                           dict(action=dict(module=module_name,
                                            args=module_args),
                                register='shell_out'),
                       ])

    play = Play().load(play_source,
                       variable_manager=variable_manager,
                       loader=loader)

    # 开始执行
    tqm = None

    tqm = TaskQueueManager(
        inventory=inventory,
        variable_manager=variable_manager,
        loader=loader,
        options=options,
        passwords=passwords,
        stdout_callback=callback,
    )
    result = tqm.run(play)

    result_raw = {'success': {}, 'failed': {}, 'unreachable': {}}

    for host, result in callback.host_ok.items():
        result_raw['success'][host] = result._result

    for host, result in callback.host_failed.items():
        result_raw['failed'][host] = result._result

    for host, result in callback.host_unreachable.items():
        result_raw['unreachable'][host] = result._result

    for host, result in callback.host_skipped.items():
        result_raw['skipped'][host] = result._result

    return json.dumps(result_raw, indent=4, ensure_ascii=False)
Beispiel #44
0
    def test_strategy_base_run_handlers(self, mock_worker):
        def fake_run(*args):
            return

        mock_worker.side_effect = fake_run
        mock_play_context = MagicMock()

        mock_handler_task = MagicMock(Handler)
        mock_handler_task.action = 'foo'
        mock_handler_task.get_name.return_value = "test handler"
        mock_handler_task.has_triggered.return_value = False
        mock_handler_task.listen = None
        mock_handler_task._role = None
        mock_handler_task._parent = None
        mock_handler_task._uuid = 'xxxxxxxxxxxxxxxx'
        mock_handler_task.copy.return_value = mock_handler_task

        mock_handler = MagicMock()
        mock_handler.block = [mock_handler_task]
        mock_handler.flag_for_host.return_value = False

        mock_play = MagicMock()
        mock_play.handlers = [mock_handler]

        mock_host = MagicMock(Host)
        mock_host.name = "test01"
        mock_host.has_hostkey = True

        mock_inventory = MagicMock()
        mock_inventory.get_hosts.return_value = [mock_host]
        mock_inventory.get.return_value = mock_host
        mock_inventory.get_host.return_value = mock_host

        mock_var_mgr = MagicMock()
        mock_var_mgr.get_vars.return_value = dict()

        mock_iterator = MagicMock()
        mock_iterator._play = mock_play

        fake_loader = DictDataLoader()
        mock_options = MagicMock()
        mock_options.module_path = None

        tqm = TaskQueueManager(
            inventory=mock_inventory,
            variable_manager=mock_var_mgr,
            loader=fake_loader,
            options=mock_options,
            passwords=None,
        )
        tqm._initialize_processes(3)
        tqm._initialize_notified_handlers(mock_play)
        tqm.hostvars = dict()

        try:
            strategy_base = StrategyBase(tqm=tqm)

            strategy_base._inventory = mock_inventory
            strategy_base._notified_handlers = {
                mock_handler_task._uuid: [mock_host]
            }

            task_result = TaskResult(mock_host.name, mock_handler_task._uuid,
                                     dict(changed=False))
            strategy_base._queued_task_cache = dict()
            strategy_base._queued_task_cache[(mock_host.name,
                                              mock_handler_task._uuid)] = {
                                                  'task': mock_handler_task,
                                                  'host': mock_host,
                                                  'task_vars': {},
                                                  'play_context':
                                                  mock_play_context
                                              }
            tqm._final_q.put(task_result)

            result = strategy_base.run_handlers(iterator=mock_iterator,
                                                play_context=mock_play_context)
        finally:
            strategy_base.cleanup()
            tqm.cleanup()
Beispiel #45
0
play_source = dict(
    name='Ansible Play',
    hosts='pool',
    gather_facts='no',
    tasks=[
        dict(action=dict(module='shell', args='systemctl status indy-node'),
             register='shell_out'),
        dict(action=dict(module='debug', args=dict(
            msg='{{shell_out.stdout}}')))
    ])

play = Play().load(play_source,
                   variable_manager=variable_manager,
                   loader=loader)

if __name__ == '__main__':
    tqm = None
    try:
        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            passwords=passwords,
        )
        result = tqm.run(play)
    finally:
        if tqm is not None:
            tqm.cleanup()

        shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
Beispiel #46
0
def main():
    variable_manager = VariableManager()
    loader = DataLoader()
    passwd = None
    become_passwd = None
    display = Display()

    parser = argparse.ArgumentParser()
    prepare_parser(parser)
    args = parser.parse_args()
    if args.askpass:
        passwd = getpass.getpass("SSH password:"******"BECOME password "
                                        "[defaults to SSH password]:")
        if become_passwd == "":
            become_passwd = passwd

    options = Options(
        connection=args.connection,
        module_path=args.module_path,
        forks=args.forks,
        become=args.become,
        become_method=args.become_method,
        become_user=args.become_user,
        check=args.check,
        remote_user=args.remote_user,
        private_key_file=args.private_key_file,
        ssh_common_args=None,
        sftp_extra_args=None,
        scp_extra_args=None,
        ssh_extra_args=None,
        verbosity=args.verbose
    )

    display.verbosity = args.verbose
    cb = CallbackModule(display)
    if not os.path.isfile(args.inventory):
        exit("ERROR! Can't open host list")

    inventory = Inventory(
        loader=loader,
        variable_manager=variable_manager,
        host_list=args.inventory
    )

    inventory.subset(args.subset)

    play_source = dict(
        name="Assign roles %s" % args.roles,
        hosts='all',
        gather_facts='no',
        roles=args.roles)

    variable_manager.set_inventory(inventory)
    play = Play().load(
        play_source,
        variable_manager=variable_manager,
        loader=loader
    )

    tqm = None
    try:
        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            options=options,
            passwords={'conn_pass': passwd, 'become_pass': become_passwd},
            stdout_callback=cb
        )
        tqm.run(play)
    finally:
        if tqm is not None:
            tqm.cleanup()
Beispiel #47
0
    def execude(self):
        # since API is constructed for CLI it expects certain options to always be set, named tuple 'fakes' the args parsing options object
        Options = namedtuple('Options', [
            'connection',
            'module_path',
            'forks',
            'become',
            'become_method',
            'become_user',
            'check',
            'diff',
            'private_key_file',
        ])
        options = Options(
            connection='smart',
            module_path=['/to/mymodules'],
            forks=10,
            become=None,
            become_method=None,
            become_user='******',
            check=False,
            diff=False,
            private_key_file='~/.ssh/id_rsa',
        )

        # 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. Ansible expects this to be one of its main display outlets
        results_callback = ResultCallback()

        # create inventory, use path to host config file as source or hosts in a comma separated string
        inventory = InventoryManager(loader=loader,
                                     sources='/etc/ansible/hosts')
        # inventory.add_host(host='172.20.51.22',port=22,group='test')

        # 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)

        # 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=self.hosts,
            gather_facts='no',
            tasks=[
                dict(
                    action=dict(module='shell', args='ps -ef | grep VSM'),
                    register='shell_out',
                ),
                # dict(action=dict(module='setup', ), register='shell_out'),
                # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
            ])

        play = Play().load(
            play_source,
            variable_manager=variable_manager,
            loader=loader,
        )
        tqm = None
        try:
            tqm = TaskQueueManager(
                inventory=inventory,
                variable_manager=variable_manager,
                loader=loader,
                options=options,
                passwords=None,
                stdout_callback=results_callback,
                # Use our custom callback instead of the ``default`` callback plugin, which prints to stdout
            )
            # atest = tqm
            # atest.run(play)
            rs = tqm.run(
                play,
            )  # most interesting data for a play is actually sent to the callback's methods
            print('---')
            print()
            # if tqm._stdout_callback.consquence:
            #     for key in tqm._stdout_callback.consquence['172.20.51.22']['stderr']:
            #         print(key,)
        except BaseException:
            print(str(BaseException))
        finally:
            # we always need to cleanup child procs and the structures we use to communicate with them
            if tqm is not None:
                tqm.cleanup()

            # Remove ansible tmpdir
            shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
Beispiel #48
0
                                  args='bash /opt/remote_shift/kafka/param_run_container.sh '), 
                                  register='shell_out'),
                 dict(action=dict(module='debug', 
                                  args=dict(msg='{{shell_out.stdout}}')))

         ])

playFifteen = Play().load(play_source_fiftteen, variable_manager=variable_manager, loader=loader)


#queue'em, and run dem playbooks

final = TaskQueueManager(
             inventory=inventory,
             variable_manager=variable_manager,
             loader=loader,
             options=options,
             passwords=passwords,
             stdout_callback='default',
           )

######
# this approach of running playbooks takes too long:
#
# + resultz = [ playOne, playTwo,...]
# + for result in resultz
#        + run_playbooks = final.run(result)
#

#########
#the tedious approach, 
# yet benevolent when troubleshooting any future changes
Beispiel #49
0
    def run(self):
        ''' use Runner lib to do SSH things '''

        super(AdHocCLI, self).run()

        # only thing left should be host pattern
        pattern = self.args[0]

        # ignore connection password cause we are local
        if self.options.connection == "local":
            self.options.ask_pass = False

        sshpass = None
        becomepass = None
        vault_pass = None

        self.normalize_become_options()
        (sshpass, becomepass) = self.ask_passwords()
        passwords = {'conn_pass': sshpass, 'become_pass': becomepass}

        if self.options.vault_password_file:
            # read vault_pass from a file
            vault_pass = CLI.read_vault_password_file(
                self.options.vault_password_file)
        elif self.options.ask_vault_pass:
            vault_pass = self.ask_vault_passwords(ask_vault_pass=True,
                                                  ask_new_vault_pass=False,
                                                  confirm_new=False)[0]

        loader = DataLoader(vault_password=vault_pass)
        variable_manager = VariableManager()
        variable_manager.extra_vars = load_extra_vars(loader=loader,
                                                      options=self.options)

        inventory = Inventory(loader=loader,
                              variable_manager=variable_manager,
                              host_list=self.options.inventory)
        variable_manager.set_inventory(inventory)

        hosts = inventory.list_hosts(pattern)
        if len(hosts) == 0:
            self.display.warning(
                "provided hosts list is empty, only localhost is available")

        if self.options.listhosts:
            self.display.display('  hosts (%d):' % len(hosts))
            for host in hosts:
                self.display.display('    %s' % host)
            return 0

        if self.options.module_name in C.MODULE_REQUIRE_ARGS and not self.options.module_args:
            err = "No argument passed to %s module" % self.options.module_name
            if pattern.endswith(".yml"):
                err = err + ' (did you mean to run ansible-playbook?)'
            raise AnsibleOptionsError(err)

        #TODO: implement async support
        #if self.options.seconds:
        #    callbacks.display("background launch...\n\n", color='cyan')
        #    results, poller = runner.run_async(self.options.seconds)
        #    results = self.poll_while_needed(poller)
        #else:
        #    results = runner.run()

        # create a pseudo-play to execute the specified module via a single task
        play_ds = self._play_ds(pattern)
        play = Play().load(play_ds,
                           variable_manager=variable_manager,
                           loader=loader)

        if self.options.one_line:
            cb = 'oneline'
        else:
            cb = 'minimal'

        if self.options.tree:
            C.DEFAULT_CALLBACK_WHITELIST.append('tree')
            C.TREE_DIR = self.options.tree

        # now create a task queue manager to execute the play
        self._tqm = None
        try:
            self._tqm = TaskQueueManager(
                inventory=inventory,
                variable_manager=variable_manager,
                loader=loader,
                display=self.display,
                options=self.options,
                passwords=passwords,
                stdout_callback=cb,
            )
            result = self._tqm.run(play)
        finally:
            if self._tqm:
                self._tqm.cleanup()

        return result
Beispiel #50
0
def main():
    host_list = ['localhost', 'www.example.com', 'www.google.com']
    Options = namedtuple(
        'Options', [
            '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',
        ],
    )

    # initialize needed objects
    variable_manager = VariableManager()
    loader = DataLoader()
    options = Options(
        connection='smart', module_path='/usr/share/ansible', forks=100,
        remote_user=None, 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=None, verbosity=None, check=False,
    )

    passwords = dict()

    # create inventory and pass to var manager
    inventory = Inventory(
        loader=loader, variable_manager=variable_manager, host_list=host_list,
    )
    variable_manager.set_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,
            options=options,
            passwords=passwords,
        )
        tqm._stdout_callback = callback
        result = tqm.run(play)
    finally:
        if tqm is not None:
            tqm.cleanup()

    print('UP ***********')
    for host, result in callback.host_ok.items():
        print('{} >>> {}'.format(host, result._result['stdout']))

    print('FAILED *******')
    for host, result in callback.host_failed.items():
        print('{} >>> {}'.format(host, result._result['msg']))

    print('DOWN *********')
    for host, result in callback.host_unreachable.items():
        print('{} >>> {}'.format(host, result._result['msg']))
Beispiel #51
0
class ConsoleCLI(CLI, cmd.Cmd):
    '''
       A REPL that allows for running ad-hoc tasks against a chosen inventory
       from a nice shell with built-in tab completion (based on dominis'
       ansible-shell).

       It supports several commands, and you can modify its configuration at
       runtime:

       - `cd [pattern]`: change host/group (you can use host patterns eg.: app*.dc*:!app01*)
       - `list`: list available hosts in the current path
       - `list groups`: list groups included in the current path
       - `become`: toggle the become flag
       - `!`: forces shell module instead of the ansible module (!yum update -y)
       - `verbosity [num]`: set the verbosity level
       - `forks [num]`: set the number of forks
       - `become_user [user]`: set the become_user
       - `remote_user [user]`: set the remote_user
       - `become_method [method]`: set the privilege escalation method
       - `check [bool]`: toggle check mode
       - `diff [bool]`: toggle diff mode
       - `timeout [integer]`: set the timeout of tasks in seconds (0 to disable)
       - `help [command/module]`: display documentation for the command or module
       - `exit`: exit ansible-console
    '''

    name = 'ansible-console'
    modules = []  # type: list[str] | None
    ARGUMENTS = {
        'host-pattern':
        'A name of a group in the inventory, a shell-like glob '
        'selecting hosts in inventory or any combination of the two separated by commas.'
    }

    # use specific to console, but fallback to highlight for backwards compatibility
    NORMAL_PROMPT = C.COLOR_CONSOLE_PROMPT or C.COLOR_HIGHLIGHT

    def __init__(self, args):

        super(ConsoleCLI, self).__init__(args)

        self.intro = 'Welcome to the ansible console. Type help or ? to list commands.\n'

        self.groups = []
        self.hosts = []
        self.pattern = None
        self.variable_manager = None
        self.loader = None
        self.passwords = dict()

        self.cwd = '*'

        # Defaults for these are set from the CLI in run()
        self.remote_user = None
        self.become = None
        self.become_user = None
        self.become_method = None
        self.check_mode = None
        self.diff = None
        self.forks = None
        self.task_timeout = None
        self.collections = None

        cmd.Cmd.__init__(self)

    def init_parser(self):
        super(ConsoleCLI, self).init_parser(
            desc="REPL console for executing Ansible tasks.",
            epilog=
            "This is not a live session/connection: each task is executed in the background and returns its results."
        )
        opt_help.add_runas_options(self.parser)
        opt_help.add_inventory_options(self.parser)
        opt_help.add_connect_options(self.parser)
        opt_help.add_check_options(self.parser)
        opt_help.add_vault_options(self.parser)
        opt_help.add_fork_options(self.parser)
        opt_help.add_module_options(self.parser)
        opt_help.add_basedir_options(self.parser)
        opt_help.add_runtask_options(self.parser)
        opt_help.add_tasknoplay_options(self.parser)

        # options unique to shell
        self.parser.add_argument('pattern',
                                 help='host pattern',
                                 metavar='pattern',
                                 default='all',
                                 nargs='?')
        self.parser.add_argument(
            '--step',
            dest='step',
            action='store_true',
            help="one-step-at-a-time: confirm each task before running")

    def post_process_args(self, options):
        options = super(ConsoleCLI, self).post_process_args(options)
        display.verbosity = options.verbosity
        self.validate_conflicts(options, runas_opts=True, fork_opts=True)
        return options

    def get_names(self):
        return dir(self)

    def cmdloop(self):
        try:
            cmd.Cmd.cmdloop(self)

        except KeyboardInterrupt:
            self.cmdloop()

        except EOFError:
            self.display("[Ansible-console was exited]")
            self.do_exit(self)

    def set_prompt(self):
        login_user = self.remote_user or getpass.getuser()
        self.selected = self.inventory.list_hosts(self.cwd)
        prompt = "%s@%s (%d)[f:%s]" % (login_user, self.cwd, len(
            self.selected), self.forks)
        if self.become and self.become_user in [None, 'root']:
            prompt += "# "
            color = C.COLOR_ERROR
        else:
            prompt += "$ "
            color = self.NORMAL_PROMPT
        self.prompt = stringc(prompt, color, wrap_nonvisible_chars=True)

    def list_modules(self):
        return list_plugins('module', self.collections)

    def default(self, line, forceshell=False):
        """ actually runs modules """
        if line.startswith("#"):
            return False

        if not self.cwd:
            display.error("No host found")
            return False

        # defaults
        module = 'shell'
        module_args = line

        if forceshell is not True:
            possible_module, *possible_args = line.split()
            if module_loader.find_plugin(possible_module):
                # we found module!
                module = possible_module
                if possible_args:
                    module_args = ' '.join(possible_args)
                else:
                    module_args = ''

        if self.callback:
            cb = self.callback
        elif C.DEFAULT_LOAD_CALLBACK_PLUGINS and C.DEFAULT_STDOUT_CALLBACK != 'default':
            cb = C.DEFAULT_STDOUT_CALLBACK
        else:
            cb = 'minimal'

        result = None
        try:
            check_raw = module in C._ACTION_ALLOWS_RAW_ARGS
            task = dict(action=dict(module=module,
                                    args=parse_kv(module_args,
                                                  check_raw=check_raw)),
                        timeout=self.task_timeout)
            play_ds = dict(
                name="Ansible Shell",
                hosts=self.cwd,
                gather_facts='no',
                tasks=[task],
                remote_user=self.remote_user,
                become=self.become,
                become_user=self.become_user,
                become_method=self.become_method,
                check_mode=self.check_mode,
                diff=self.diff,
                collections=self.collections,
            )
            play = Play().load(play_ds,
                               variable_manager=self.variable_manager,
                               loader=self.loader)
        except Exception as e:
            display.error(u"Unable to build command: %s" % to_text(e))
            return False

        try:
            # now create a task queue manager to execute the play
            self._tqm = None
            try:
                self._tqm = TaskQueueManager(
                    inventory=self.inventory,
                    variable_manager=self.variable_manager,
                    loader=self.loader,
                    passwords=self.passwords,
                    stdout_callback=cb,
                    run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS,
                    run_tree=False,
                    forks=self.forks,
                )

                result = self._tqm.run(play)
                display.debug(result)
            finally:
                if self._tqm:
                    self._tqm.cleanup()
                if self.loader:
                    self.loader.cleanup_all_tmp_files()

            if result is None:
                display.error("No hosts found")
                return False
        except KeyboardInterrupt:
            display.error('User interrupted execution')
            return False
        except Exception as e:
            if self.verbosity >= 3:
                import traceback
                display.v(traceback.format_exc())
            display.error(to_text(e))
            return False

    def emptyline(self):
        return

    def do_shell(self, arg):
        """
        You can run shell commands through the shell module.

        eg.:
        shell ps uax | grep java | wc -l
        shell killall python
        shell halt -n

        You can use the ! to force the shell module. eg.:
        !ps aux | grep java | wc -l
        """
        self.default(arg, True)

    def help_shell(self):
        display.display("You can run shell commands through the shell module.")

    def do_forks(self, arg):
        """Set the number of forks"""
        if arg:
            try:
                forks = int(arg)
            except TypeError:
                display.error('Invalid argument for "forks"')
                self.usage_forks()

            if forks > 0:
                self.forks = forks
                self.set_prompt()

            else:
                display.display('forks must be greater than or equal to 1')
        else:
            self.usage_forks()

    def help_forks(self):
        display.display("Set the number of forks to use per task")
        self.usage_forks()

    def usage_forks(self):
        display.display('Usage: forks <number>')

    do_serial = do_forks
    help_serial = help_forks

    def do_collections(self, arg):
        """Set list of collections for 'short name' usage"""
        if arg in ('', 'none'):
            self.collections = None
        elif not arg:
            self.usage_collections()
        else:
            collections = arg.split(',')
            for collection in collections:
                if self.collections is None:
                    self.collections = []
                self.collections.append(collection.strip())

        if self.collections:
            display.v('Collections name search is set to: %s' %
                      ', '.join(self.collections))
        else:
            display.v('Collections name search is using defaults')

    def help_collections(self):
        display.display(
            "Set the collection name search path when using short names for plugins"
        )
        self.usage_collections()

    def usage_collections(self):
        display.display(
            'Usage: collections <collection1>[, <collection2> ...]\n Use empty quotes or "none" to reset to default.\n'
        )

    def do_verbosity(self, arg):
        """Set verbosity level"""
        if not arg:
            display.display('Usage: verbosity <number>')
        else:
            try:
                display.verbosity = int(arg)
                display.v('verbosity level set to %s' % arg)
            except (TypeError, ValueError) as e:
                display.error('The verbosity must be a valid integer: %s' %
                              to_text(e))

    def help_verbosity(self):
        display.display(
            "Set the verbosity level, equivalent to -v for 1 and -vvvv for 4.")

    def do_cd(self, arg):
        """
            Change active host/group. You can use hosts patterns as well eg.:
            cd webservers
            cd webservers:dbservers
            cd webservers:!phoenix
            cd webservers:&staging
            cd webservers:dbservers:&staging:!phoenix
        """
        if not arg:
            self.cwd = '*'
        elif arg in '/*':
            self.cwd = 'all'
        elif self.inventory.get_hosts(arg):
            self.cwd = arg
        else:
            display.display("no host matched")

        self.set_prompt()

    def help_cd(self):
        display.display("Change active host/group. ")
        self.usage_cd()

    def usage_cd(self):
        display.display("Usage: cd <group>|<host>|<host pattern>")

    def do_list(self, arg):
        """List the hosts in the current group"""
        if not arg:
            for host in self.selected:
                display.display(host.name)
        elif arg == 'groups':
            for group in self.groups:
                display.display(group)
        else:
            display.error('Invalid option passed to "list"')
            self.help_list()

    def help_list(self):
        display.display(
            "List the hosts in the current group or a list of groups if you add 'groups'."
        )

    def do_become(self, arg):
        """Toggle whether plays run with become"""
        if arg:
            self.become = boolean(arg, strict=False)
            display.v("become changed to %s" % self.become)
            self.set_prompt()
        else:
            display.display("Please specify become value, e.g. `become yes`")

    def help_become(self):
        display.display("Toggle whether the tasks are run with become")

    def do_remote_user(self, arg):
        """Given a username, set the remote user plays are run by"""
        if arg:
            self.remote_user = arg
            self.set_prompt()
        else:
            display.display(
                "Please specify a remote user, e.g. `remote_user root`")

    def help_remote_user(self):
        display.display("Set the user for use as login to the remote target")

    def do_become_user(self, arg):
        """Given a username, set the user that plays are run by when using become"""
        if arg:
            self.become_user = arg
        else:
            display.display(
                "Please specify a user, e.g. `become_user jenkins`")
            display.v("Current user is %s" % self.become_user)
        self.set_prompt()

    def help_become_user(self):
        display.display(
            "Set the user for use with privilege escalation (which remote user attempts to 'become' when become is enabled)"
        )

    def do_become_method(self, arg):
        """Given a become_method, set the privilege escalation method when using become"""
        if arg:
            self.become_method = arg
            display.v("become_method changed to %s" % self.become_method)
        else:
            display.display(
                "Please specify a become_method, e.g. `become_method su`")
            display.v("Current become_method is %s" % self.become_method)

    def help_become_method(self):
        display.display(
            "Set the privilege escalation plugin to use when become is enabled"
        )

    def do_check(self, arg):
        """Toggle whether plays run with check mode"""
        if arg:
            self.check_mode = boolean(arg, strict=False)
            display.display("check mode changed to %s" % self.check_mode)
        else:
            display.display(
                "Please specify check mode value, e.g. `check yes`")
            display.v("check mode is currently %s." % self.check_mode)

    def help_check(self):
        display.display("Toggle check_mode for the tasks")

    def do_diff(self, arg):
        """Toggle whether plays run with diff"""
        if arg:
            self.diff = boolean(arg, strict=False)
            display.display("diff mode changed to %s" % self.diff)
        else:
            display.display("Please specify a diff value , e.g. `diff yes`")
            display.v("diff mode is currently %s" % self.diff)

    def help_diff(self):
        display.display("Toggle diff output for the tasks")

    def do_timeout(self, arg):
        """Set the timeout"""
        if arg:
            try:
                timeout = int(arg)
                if timeout < 0:
                    display.error(
                        'The timeout must be greater than or equal to 1, use 0 to disable'
                    )
                else:
                    self.task_timeout = timeout
            except (TypeError, ValueError) as e:
                display.error(
                    'The timeout must be a valid positive integer, or 0 to disable: %s'
                    % to_text(e))
        else:
            self.usage_timeout()

    def help_timeout(self):
        display.display("Set task timeout in seconds")
        self.usage_timeout()

    def usage_timeout(self):
        display.display('Usage: timeout <seconds>')

    def do_exit(self, args):
        """Exits from the console"""
        sys.stdout.write('\nAnsible-console was exited.\n')
        return -1

    def help_exit(self):
        display.display("LEAVE!")

    do_EOF = do_exit
    help_EOF = help_exit

    def helpdefault(self, module_name):
        if module_name:
            in_path = module_loader.find_plugin(module_name)
            if in_path:
                oc, a, _dummy1, _dummy2 = plugin_docs.get_docstring(
                    in_path, fragment_loader)
                if oc:
                    display.display(oc['short_description'])
                    display.display('Parameters:')
                    for opt in oc['options'].keys():
                        display.display('  ' +
                                        stringc(opt, self.NORMAL_PROMPT) +
                                        ' ' +
                                        oc['options'][opt]['description'][0])
                else:
                    display.error('No documentation found for %s.' %
                                  module_name)
            else:
                display.error(
                    '%s is not a valid command, use ? to list all valid commands.'
                    % module_name)

    def help_help(self):
        display.warning("Don't be redundant!")

    def complete_cd(self, text, line, begidx, endidx):
        mline = line.partition(' ')[2]
        offs = len(mline) - len(text)

        if self.cwd in ('all', '*', '\\'):
            completions = self.hosts + self.groups
        else:
            completions = [x.name for x in self.inventory.list_hosts(self.cwd)]

        return [
            to_native(s)[offs:] for s in completions
            if to_native(s).startswith(to_native(mline))
        ]

    def completedefault(self, text, line, begidx, endidx):
        if line.split()[0] in self.list_modules():
            mline = line.split(' ')[-1]
            offs = len(mline) - len(text)
            completions = self.module_args(line.split()[0])

            return [s[offs:] + '=' for s in completions if s.startswith(mline)]

    def module_args(self, module_name):
        in_path = module_loader.find_plugin(module_name)
        oc, a, _dummy1, _dummy2 = plugin_docs.get_docstring(in_path,
                                                            fragment_loader,
                                                            is_module=True)
        return list(oc['options'].keys())

    def run(self):

        super(ConsoleCLI, self).run()

        sshpass = None
        becomepass = None

        # hosts
        self.pattern = context.CLIARGS['pattern']
        self.cwd = self.pattern

        # Defaults from the command line
        self.remote_user = context.CLIARGS['remote_user']
        self.become = context.CLIARGS['become']
        self.become_user = context.CLIARGS['become_user']
        self.become_method = context.CLIARGS['become_method']
        self.check_mode = context.CLIARGS['check']
        self.diff = context.CLIARGS['diff']
        self.forks = context.CLIARGS['forks']
        self.task_timeout = context.CLIARGS['task_timeout']

        # set module path if needed
        if context.CLIARGS['module_path']:
            for path in context.CLIARGS['module_path']:
                if path:
                    module_loader.add_directory(path)

        # dynamically add 'cannonical' modules as commands, aliases coudld be used and dynamically loaded
        self.modules = self.list_modules()
        for module in self.modules:
            setattr(
                self,
                'do_' + module,
                lambda arg, module=module: self.default(module + ' ' + arg))
            setattr(self,
                    'help_' + module,
                    lambda module=module: self.helpdefault(module))

        (sshpass, becomepass) = self.ask_passwords()
        self.passwords = {'conn_pass': sshpass, 'become_pass': becomepass}

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

        hosts = self.get_host_list(self.inventory, context.CLIARGS['subset'],
                                   self.pattern)

        self.groups = self.inventory.list_groups()
        self.hosts = [x.name for x in hosts]

        # This hack is to work around readline issues on a mac:
        #  http://stackoverflow.com/a/7116997/541202
        if 'libedit' in readline.__doc__:
            readline.parse_and_bind("bind ^I rl_complete")
        else:
            readline.parse_and_bind("tab: complete")

        histfile = os.path.join(os.path.expanduser("~"),
                                ".ansible-console_history")
        try:
            readline.read_history_file(histfile)
        except IOError:
            pass

        atexit.register(readline.write_history_file, histfile)
        self.set_prompt()
        self.cmdloop()

    def __getattr__(self, name):
        ''' handle not found to populate dynamically a module function if module matching name exists '''
        attr = None

        if name.startswith('do_'):
            module = name.replace('do_', '')
            if module_loader.find_plugin(module):
                setattr(self,
                        name,
                        lambda arg, module=module: self.default(module + ' ' +
                                                                arg))
                attr = object.__getattr__(self, name)
        elif name.startswith('help_'):
            module = name.replace('help_', '')
            if module_loader.find_plugin(module):
                setattr(self,
                        name,
                        lambda module=module: self.helpdefault(module))
                attr = object.__getattr__(self, name)

        if attr is None:
            raise AttributeError(
                f"{self.__class__} does not have a {name} attribute")

        return attr
Beispiel #52
0
    def execute(self, *args, **kwargs):
        """ Puts args and kwargs in a way ansible can understand. Calls ansible
        and interprets the result.

        """
        assert self.is_hooked_up, "the module should be hooked up to the api"

        if set_global_context:
            set_global_context(self.api.options)

        # legacy key=value pairs shorthand approach
        if args:
            self.module_args = module_args = self.get_module_args(args, kwargs)
        else:
            self.module_args = module_args = kwargs

        loader = DataLoader()
        inventory_manager = SourcelessInventoryManager(loader=loader)

        for host, host_variables in self.api.inventory.items():
            inventory_manager._inventory.add_host(host, group='all')
            for key, value in host_variables.items():
                inventory_manager._inventory.set_variable(host, key, value)

        for key, value in self.api.options.extra_vars.items():
            inventory_manager._inventory.set_variable('all', key, value)

        variable_manager = VariableManager(loader=loader,
                                           inventory=inventory_manager)

        play_source = {
            'name':
            "Suitable Play",
            'hosts':
            'all',
            'gather_facts':
            'no',
            'tasks': [{
                'action': {
                    'module': self.module_name,
                    'args': module_args,
                },
                'environment': self.api.environment,
            }]
        }

        try:
            play = Play.load(
                play_source,
                variable_manager=variable_manager,
                loader=loader,
            )

            if self.api.strategy:
                play.strategy = self.api.strategy

            log.info(u'running {}'.format(
                u'- {module_name}: {module_args}'.format(
                    module_name=self.module_name, module_args=module_args)))

            start = datetime.utcnow()
            task_queue_manager = None
            callback = SilentCallbackModule()

            # ansible uses various levels of verbosity (from -v to -vvvvvv)
            # offering various amounts of debug information
            #
            # we keep it a bit simpler by activating all of it during debug,
            # and falling back to the default of 0 otherwise
            verbosity = self.api.options.verbosity == logging.DEBUG and 6 or 0

            with ansible_verbosity(verbosity):

                # host_key_checking is special, since not each connection
                # plugin handles it the same way, we need to apply both
                # environment variable and Ansible constant when running a
                # command in the runner to be successful
                with host_key_checking(self.api.host_key_checking):
                    kwargs = dict(inventory=inventory_manager,
                                  variable_manager=variable_manager,
                                  loader=loader,
                                  options=self.api.options,
                                  passwords=getattr(self.api.options,
                                                    'passwords', {}),
                                  stdout_callback=callback)

                    if set_global_context:
                        del kwargs['options']

                    task_queue_manager = TaskQueueManager(**kwargs)

                    try:
                        task_queue_manager.run(play)
                    except SystemExit:

                        # Mitogen forks our process and exits it in one
                        # instance before returning
                        #
                        # This is fine, but it does lead to a very messy exit
                        # by py.test which will essentially return with a test
                        # that is first successful and then failed as each
                        # forked process dies.
                        #
                        # To avoid this we commit suicide if we are run inside
                        # a pytest session. Normally this would just result
                        # in a exit code of zero, which is good.
                        if 'pytest' in sys.modules:
                            try:
                                atexit._run_exitfuncs()
                            except Exception:
                                pass
                            os.kill(os.getpid(), signal.SIGKILL)

                        raise
        finally:
            if task_queue_manager is not None:
                task_queue_manager.cleanup()

            if set_global_context:
                # Ansible 2.8 introduces a global context which persists
                # during the lifetime of the process - for Suitable this
                # singleton/cache needs to be cleared after each call
                # to make sure that API calls do not carry over state.
                #
                # The docs hint at a future inclusion of local contexts, which
                # would of course be preferable.
                from ansible.utils.context_objects import GlobalCLIArgs
                GlobalCLIArgs._Singleton__instance = None

        log.debug(u'took {} to complete'.format(datetime.utcnow() - start))

        return self.evaluate_results(callback)
Beispiel #53
0
        dict(action=dict(module='debug', args=dict(
            msg='{{shell_out.stdout}}')))
    ])
# 创建play object,playbook objects使用。
# 加载而不是初始化或新方法,这也将从play_source中提供的信息自动创建任务对象。
play = Play().load(play_source,
                   variable_manager=variable_manager,
                   loader=loader)

# 运行它-实例化任务队列管理器,它负责分叉和设置所有对象,以便在主机列表和任务上迭代。
tqm = None
try:
    tqm = TaskQueueManager(
        inventory=inventory,
        variable_manager=variable_manager,
        loader=loader,
        passwords=passwords,
        stdout_callback=results_callback,  # 使用我们的自定义回调,而不是打印到stdout的"默认"回调插件
    )
    result = tqm.run(play)  # 一出戏最有趣的数据实际上是发送到回调的方法
finally:
    # 我们总是需要清理子程序和我们用来与他们沟通的结构.
    if tqm is not None:
        tqm.cleanup()
    # Remove ansible tmpdir
    shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)

if __name__ == "__main__":
    sys.stdout.write('\033[31;47;1msys.argv is %s\n\033[0m' % sys.argv)
    returnObj = ResultCallback()
    print(type(returnObj), '\n---------------\n')
Beispiel #54
0
def ansible_adhoc(host_list,
                  module_name,
                  module_args,
                  pattern,
                  play_name=None,
                  passwords=None,
                  forks=5):

    loader = DataLoader()
    variable_manager = VariableManager()
    inventory = Inventory(loader=loader,
                          variable_manager=variable_manager,
                          host_list=host_list)
    variable_manager.set_inventory(inventory)

    Options = namedtuple('Options', [
        'remote_user', 'forks', 'become_method', 'become_user', 'listhosts',
        'listtasks', 'listtags', 'syntax', 'module_path', 'become', 'check',
        'verbosity', 'connection', 'private_key_file', 'host_key_checking'
    ])
    options = Options(remote_user='******',
                      forks=10,
                      become_method='sudo',
                      become_user='******',
                      listhosts=False,
                      listtasks=False,
                      listtags=False,
                      syntax=False,
                      module_path=None,
                      become=True,
                      check=False,
                      verbosity=True,
                      connection='smart',
                      private_key_file=None,
                      host_key_checking=False)

    # variable_manager.extra_vars={"ansible_ssh_user":"******" , "ansible_ssh_pass":"******"}
    passwords = passwords
    play_source = {
        "name": play_name,
        "hosts": pattern,
        "gather_facts": "no",
        "tasks": [{
            "action": {
                "module": module_name,
                "args": module_args
            }
        }]
    }
    play = Play().load(play_source,
                       variable_manager=variable_manager,
                       loader=loader)
    tqm = None
    try:
        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            options=options,
            passwords=passwords,
            stdout_callback='json',
        )
        result_code = tqm.run(play)

    except Exception as e:
        raise Exception(e)

    finally:
        if tqm is not None:
            tqm.cleanup()
    return dict(retcode=result_code, results=tqm._stdout_callback.results)
Beispiel #55
0
class Runner(object):
    
    def __init__(self, pb_file, sources=['inventory/hosts'], **kwargs):
        self.pb_file = pb_file
        self.sources = sources
        Options = namedtuple('Options', ['connection',
                                         'module_path',
                                         'forks',
                                         'become',
                                         'become_method',
                                         'become_user',
                                         'check',
                                         'diff'])
        # initialize needed objects
        self.Options = Options(connection='smart',
                               module_path=None,
                               forks=100,
                               become=True,
                               become_method='sudo',
                               become_user='******',
                               check=False,
                               diff=False)
        self.loader = DataLoader()
        passwords = dict(vault_pass='******')

        # Instantiate our ResultCallback for handling results as they come in
        self.results_callback = ResultCallback()

        # create inventory and pass to var manager
        #self.inventory = InventoryManager(loader=loader, sources=['/home/alvin/git/ansible/ansible-playbook/inventory/hosts'])
        self.inventory = self._gen_inventory()
        self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory)
        self.variable_manager.extra_vars = kwargs

        self.tqm = TaskQueueManager(
            inventory=self.inventory,
            variable_manager=self.variable_manager,
            loader=self.loader,
            options=self.Options,
            passwords=passwords,
            stdout_callback=self.results_callback,
        )

    def _gen_inventory(self):
        if isinstance(self.sources, str):
            assert os.path.isfile(self.sources), "Inventory file ['{}'] not exist".format(self.sources)
            return InventoryManager(loader=self.loader, sources=self.sources)
        elif isinstance(self.sources, list):
            for source in self.sources:
                assert os.path.isfile(source), "One or more inventory file not exist in {}".format(self.sources)
            return InventoryManager(loader=self.loader, sources=self.sources)

    def _load_play_source(self):
        for source in self.loader.load_from_file(self.pb_file):
            self.play_source.update(source)

    def run(self):
        self.play_source = {}
        self._load_play_source()

        self.play = Play().load(self.play_source, variable_manager=self.variable_manager, loader=self.loader)

        try:
            ret = self.tqm.run(self.play)
            return ret
        finally:
            if self.tqm is not None:
                self.tqm.cleanup()
Beispiel #56
0
# create play with tasks
play_source = dict(
    name="Ansible Play",
    hosts='localhost',
    gather_facts='no',
    tasks=[
        dict(
            action=dict(module='get_version', args=dict(
                program='libreoffice'))),
    ])
play = Play().load(play_source,
                   variable_manager=variable_manager,
                   loader=loader)

# actually run it
tqm = None
try:
    tqm = TaskQueueManager(
        inventory=inventory,
        variable_manager=variable_manager,
        loader=loader,
        options=options,
        passwords=passwords,
        stdout_callback=
        results_callback,  # Use our custom callback instead of the ``default`` callback plugin
    )
    result = tqm.run(play)
finally:
    if tqm is not None:
        tqm.cleanup()
Beispiel #57
0
inventory = Inventory(loader=loader,
                      variable_manager=variable_manager,
                      host_list=["127.0.0.1"])
variable_manager.set_inventory(inventory)

play_src = dict(name='ansible api test',
                hosts='all',
                gather_facts='no',
                tasks=[
                    dict(action=dict(module='shell', args='ifconfig eth5'),
                         register='shell_out')
                ])

play = Play().load(play_src, variable_manager=variable_manager, loader=loader)

tmq = None
try:
    tmq = TaskQueueManager(
        inventory=inventory,
        variable_manager=variable_manager,
        loader=loader,
        options=options,
        passwords=passwords,
        #stdout_callback=results_callback
        stdout_callback=None)
    result = tmq.run(play)
    #print result
finally:
    if tmq is not None:
        tmq.cleanup()
class PlaybookExecutor:
    '''
    This is the primary class for executing playbooks, and thus the
    basis for bin/ansible-playbook operation.
    '''
    def __init__(self, playbooks, inventory, variable_manager, loader, options,
                 passwords):
        self._playbooks = playbooks
        self._inventory = inventory
        self._variable_manager = variable_manager
        self._loader = loader
        self._options = options
        self.passwords = passwords
        self._unreachable_hosts = dict()

        if options.listhosts or options.listtasks or options.listtags or options.syntax:
            self._tqm = None
        else:
            self._tqm = TaskQueueManager(inventory=inventory,
                                         variable_manager=variable_manager,
                                         loader=loader,
                                         options=options,
                                         passwords=self.passwords)

    def run(self):
        '''
        Run the given playbook, based on the settings in the play which
        may limit the runs to serialized groups, etc.
        '''

        signal.signal(signal.SIGINT, self._cleanup)

        result = 0
        entrylist = []
        entry = {}
        try:
            for playbook_path in self._playbooks:
                pb = Playbook.load(playbook_path,
                                   variable_manager=self._variable_manager,
                                   loader=self._loader)
                self._inventory.set_playbook_basedir(
                    os.path.dirname(playbook_path))

                if self._tqm is None:  # we are doing a listing
                    entry = {'playbook': playbook_path}
                    entry['plays'] = []

                i = 1
                plays = pb.get_plays()
                display.vv('%d plays in %s' % (len(plays), playbook_path))

                for play in plays:
                    if play._included_path is not None:
                        self._loader.set_basedir(play._included_path)
                    else:
                        self._loader.set_basedir(pb._basedir)

                    # clear any filters which may have been applied to the inventory
                    self._inventory.remove_restriction()

                    if play.vars_prompt:
                        for var in play.vars_prompt:
                            vname = var['name']
                            prompt = var.get("prompt", vname)
                            default = var.get("default", None)
                            private = var.get("private", True)
                            confirm = var.get("confirm", False)
                            encrypt = var.get("encrypt", None)
                            salt_size = var.get("salt_size", None)
                            salt = var.get("salt", None)

                            if vname not in play.vars:
                                if self._tqm:
                                    self._tqm.send_callback(
                                        'v2_playbook_on_vars_prompt', vname,
                                        private, prompt, encrypt, confirm,
                                        salt_size, salt, default)
                                play.vars[vname] = self._do_var_prompt(
                                    vname, private, prompt, encrypt, confirm,
                                    salt_size, salt, default)

                    # Create a temporary copy of the play here, so we can run post_validate
                    # on it without the templating changes affecting the original object.
                    all_vars = self._variable_manager.get_vars(
                        loader=self._loader, play=play)
                    templar = Templar(loader=self._loader, variables=all_vars)
                    new_play = play.copy()
                    new_play.post_validate(templar)

                    if self._options.syntax:
                        continue

                    if self._tqm is None:
                        # we are just doing a listing
                        entry['plays'].append(new_play)

                    else:
                        # make sure the tqm has callbacks loaded
                        self._tqm.load_callbacks()
                        self._tqm._unreachable_hosts.update(
                            self._unreachable_hosts)

                        # we are actually running plays
                        for batch in self._get_serialized_batches(new_play):
                            if len(batch) == 0:
                                self._tqm.send_callback(
                                    'v2_playbook_on_play_start', new_play)
                                self._tqm.send_callback(
                                    'v2_playbook_on_no_hosts_matched')
                                break

                            # restrict the inventory to the hosts in the serialized batch
                            self._inventory.restrict_to_hosts(batch)
                            # and run it...
                            result = self._tqm.run(play=play)

                            # check the number of failures here, to see if they're above the maximum
                            # failure percentage allowed, or if any errors are fatal. If either of those
                            # conditions are met, we break out, otherwise we only break out if the entire
                            # batch failed
                            failed_hosts_count = len(
                                self._tqm._failed_hosts) + len(
                                    self._tqm._unreachable_hosts)
                            if new_play.any_errors_fatal and failed_hosts_count > 0:
                                break
                            elif new_play.max_fail_percentage is not None and \
                               int((new_play.max_fail_percentage)/100.0 * len(batch)) > int((len(batch) - failed_hosts_count) / len(batch) * 100.0):
                                break
                            elif len(batch) == failed_hosts_count:
                                break

                            # clear the failed hosts dictionaires in the TQM for the next batch
                            self._unreachable_hosts.update(
                                self._tqm._unreachable_hosts)
                            self._tqm.clear_failed_hosts()

                        # if the last result wasn't zero or 3 (some hosts were unreachable),
                        # break out of the serial batch loop
                        if result not in (0, 3):
                            break

                    i = i + 1  # per play

                if entry:
                    entrylist.append(entry)  # per playbook

                # if the last result wasn't zero, break out of the playbook file name loop
                if result != 0:
                    break

            if entrylist:
                return entrylist

        finally:
            if self._tqm is not None:
                self._cleanup()

        if self._options.syntax:
            display.display("No issues encountered")
            return result

        # TODO: this stat summary stuff should be cleaned up and moved
        #        to a new method, if it even belongs here...
        display.banner("PLAY RECAP")

        hosts = sorted(self._tqm._stats.processed.keys())
        for h in hosts:
            t = self._tqm._stats.summarize(h)

            display.display(
                u"%s : %s %s %s %s" %
                (hostcolor(h, t), colorize(u'ok', t['ok'], 'green'),
                 colorize(u'changed', t['changed'], 'yellow'),
                 colorize(u'unreachable', t['unreachable'],
                          'red'), colorize(u'failed', t['failures'], 'red')),
                screen_only=True)

            display.display(
                u"%s : %s %s %s %s" %
                (hostcolor(h, t, False), colorize(u'ok', t['ok'], None),
                 colorize(u'changed', t['changed'], None),
                 colorize(u'unreachable', t['unreachable'],
                          None), colorize(u'failed', t['failures'], None)),
                log_only=True)

        display.display("", screen_only=True)
        # END STATS STUFF

        return result

    def _cleanup(self, signum=None, framenum=None):
        return self._tqm.cleanup()

    def _get_serialized_batches(self, play):
        '''
        Returns a list of hosts, subdivided into batches based on
        the serial size specified in the play.
        '''

        # make sure we have a unique list of hosts
        all_hosts = self._inventory.get_hosts(play.hosts)

        # check to see if the serial number was specified as a percentage,
        # and convert it to an integer value based on the number of hosts
        if isinstance(play.serial, string_types) and play.serial.endswith('%'):
            serial_pct = int(play.serial.replace("%", ""))
            serial = int((serial_pct / 100.0) * len(all_hosts))
        else:
            if play.serial is None:
                serial = -1
            else:
                serial = int(play.serial)

        # if the serial count was not specified or is invalid, default to
        # a list of all hosts, otherwise split the list of hosts into chunks
        # which are based on the serial size
        if serial <= 0:
            return [all_hosts]
        else:
            serialized_batches = []

            while len(all_hosts) > 0:
                play_hosts = []
                for x in range(serial):
                    if len(all_hosts) > 0:
                        play_hosts.append(all_hosts.pop(0))

                serialized_batches.append(play_hosts)

            return serialized_batches

    def _do_var_prompt(self,
                       varname,
                       private=True,
                       prompt=None,
                       encrypt=None,
                       confirm=False,
                       salt_size=None,
                       salt=None,
                       default=None):

        if sys.__stdin__.isatty():
            if prompt and default is not None:
                msg = "%s [%s]: " % (prompt, default)
            elif prompt:
                msg = "%s: " % prompt
            else:
                msg = 'input for %s: ' % varname

            def do_prompt(prompt, private):
                if sys.stdout.encoding:
                    msg = prompt.encode(sys.stdout.encoding)
                else:
                    # when piping the output, or at other times when stdout
                    # may not be the standard file descriptor, the stdout
                    # encoding may not be set, so default to something sane
                    msg = prompt.encode(locale.getpreferredencoding())
                if private:
                    return getpass.getpass(msg)
                return raw_input(msg)

            if confirm:
                while True:
                    result = do_prompt(msg, private)
                    second = do_prompt("confirm " + msg, private)
                    if result == second:
                        break
                    display.display("***** VALUES ENTERED DO NOT MATCH ****")
            else:
                result = do_prompt(msg, private)
        else:
            result = None
            display.warning("Not prompting as we are not in interactive mode")

        # if result is false and default is not None
        if not result and default is not None:
            result = default

        if encrypt:
            result = do_encrypt(result, encrypt, salt_size, salt)

        # handle utf-8 chars
        result = to_unicode(result, errors='strict')
        return result
Beispiel #59
0
 def _run_playbook(self, yamlfile, is_checksyntax=False):
     if not is_checksyntax :
         if self.options.flush_cache:
             self._flush_cache()
                 
         self._loading_callback(yamlfile)
         # self._unreachable_hosts = dict()
         
         tqm = TaskQueueManager(
             inventory=self.inventory,
             variable_manager=self.variable_manager,
             loader=self.loader,
             options=self.options,
             passwords=self.passwords,
             stdout_callback=self.callback,
         )
     
         check_for_controlpersist(C.ANSIBLE_SSH_EXECUTABLE)
     else :
         tqm = None
         
     try :   
         pb = Playbook.load(
             yamlfile,
             variable_manager=self.variable_manager,
             loader=self.loader
         )
         self.inventory.set_playbook_basedir(yamlfile)
 
         if tqm is not None :
             tqm.load_callbacks()
             tqm.send_callback('v2_playbook_on_start', pb)
             self.logger.debug(self.log_prefix + '任务开始执行')
 
         plays = pb.get_plays()
 
         for play in plays:
             if play._included_path is not None:
                 self.loader.set_basedir(play._included_path)
             else:
                 self.loader.set_basedir(pb._basedir)
 
             self.inventory.remove_restriction()
             all_vars = self.variable_manager.get_vars(loader=self.loader, play=play)
 
             templar = Templar(loader=self.loader, variables=all_vars)
             new_play = play.copy()
             new_play.post_validate(templar)
             
             if is_checksyntax or tqm is None:
                 return True
 
             # tqm._unreachable_hosts.update(self._unreachable_hosts)
                         
             batches = self._get_serialized_batches(new_play)
             if len(batches) == 0:
                 tqm.send_callback('v2_playbook_on_play_start', new_play)
                 tqm.send_callback('v2_playbook_on_no_hosts_matched')
                 self.logger.debug(self.log_prefix + '任务开始执行,但没有匹配主机')
                 # 需要写日志,需要写该模块
                 continue
                            
             for batch in batches:
                 self.inventory.restrict_to_hosts(batch)
                 try :
                     tqm.run(play)
                 except Exception as e:
                     print(e)
                     pass
                                 
             # self._unreachable_hosts.update(tqm._unreachable_hosts)
 
         tqm.send_callback('v2_playbook_on_stats', tqm._stats)
         self.logger.debug(self.log_prefix + '任务执行完比')
         # self.host_list = self.inventory.get_hosts(play.hosts)
                     
         tqm.cleanup()
         self.loader.cleanup_all_tmp_files()
         return True
     except Exception as e:
         print(e)
         if is_checksyntax :
             return False
         else :
             return False
Beispiel #60
0
class TestTaskQueueManagerCallbacks(unittest.TestCase):
    def setUp(self):
        inventory = MagicMock()
        variable_manager = MagicMock()
        loader = MagicMock()
        passwords = []

        # Reset the stored command line args
        co.GlobalCLIArgs._Singleton__instance = None
        self._tqm = TaskQueueManager(inventory, variable_manager, loader,
                                     passwords)
        self._playbook = Playbook(loader)

        # we use a MagicMock to register the result of the call we
        # expect to `v2_playbook_on_call`. We don't mock out the
        # method since we're testing code that uses `inspect` to
        # look at that method's argspec and we want to ensure this
        # test is easy to reason about.
        self._register = MagicMock()

    def tearDown(self):
        # Reset the stored command line args
        co.GlobalCLIArgs._Singleton__instance = None

    def test_task_queue_manager_callbacks_v2_playbook_on_start(self):
        """
        Assert that no exceptions are raised when sending a Playbook
        start callback to a current callback module plugin.
        """
        register = self._register

        class CallbackModule(CallbackBase):
            """
            This is a callback module with the current
            method signature for `v2_playbook_on_start`.
            """
            CALLBACK_VERSION = 2.0
            CALLBACK_TYPE = 'notification'
            CALLBACK_NAME = 'current_module'

            def v2_playbook_on_start(self, playbook):
                register(self, playbook)

        callback_module = CallbackModule()
        self._tqm._callback_plugins.append(callback_module)
        self._tqm.send_callback('v2_playbook_on_start', self._playbook)
        register.assert_called_once_with(callback_module, self._playbook)

    def test_task_queue_manager_callbacks_v2_playbook_on_start_wrapped(self):
        """
        Assert that no exceptions are raised when sending a Playbook
        start callback to a wrapped current callback module plugin.
        """
        register = self._register

        def wrap_callback(func):
            """
            This wrapper changes the exposed argument
            names for a method from the original names
            to (*args, **kwargs). This is used in order
            to validate that wrappers which change par-
            ameter names do not break the TQM callback
            system.

            :param func: function to decorate
            :return: decorated function
            """
            def wrapper(*args, **kwargs):
                return func(*args, **kwargs)

            return wrapper

        class WrappedCallbackModule(CallbackBase):
            """
            This is a callback module with the current
            method signature for `v2_playbook_on_start`
            wrapped in order to change the signature.
            """
            CALLBACK_VERSION = 2.0
            CALLBACK_TYPE = 'notification'
            CALLBACK_NAME = 'current_module'

            @wrap_callback
            def v2_playbook_on_start(self, playbook):
                register(self, playbook)

        callback_module = WrappedCallbackModule()
        self._tqm._callback_plugins.append(callback_module)
        self._tqm.send_callback('v2_playbook_on_start', self._playbook)
        register.assert_called_once_with(callback_module, self._playbook)