def _register_play_vars(host, result): # when 'register' is used, persist the result in the vars cache # rather than the setup cache - vars should be transient between # playbook executions if 'stdout' in result and 'stdout_lines' not in result: result['stdout_lines'] = result['stdout'].splitlines() utils.update_hash(self.VARS_CACHE, host, {task.register: result})
def _save_play_facts(host, facts): # saves play facts in SETUP_CACHE, unless the module executed was # set_fact, in which case we add them to the VARS_CACHE if task.module_name == 'set_fact': utils.update_hash(self.VARS_CACHE, host, facts) else: utils.update_hash(self.SETUP_CACHE, host, facts)
def _save_play_facts(host, facts): # saves play facts in SETUP_CACHE, unless the module executed was # set_fact, in which case we add them to the VARS_CACHE if task.module_name in ('set_fact', 'include_vars'): utils.update_hash(self.VARS_CACHE, host, facts) else: utils.update_hash(self.SETUP_CACHE, host, facts)
def _update_hash(self, hash, key, new_value): # If two or more nodes delegate to the same node and attempt to update # the fact-cache for that node simultaneously we need to lock using # mutex around the update_hash action to stop a collision. # Because instances of this callback plugin live within multiple subprocesses # during execution, we can't rely on a threading.RLock; nor can we use a # POSIX multiprocess.Lock object since there's no way to ensure that the # object is correctly created in the parent process. # Instead, we'll use a traditional file-based lock for the key item. with open("%s/.lock_%s" % (C.CACHE_PLUGIN_CONNECTION, key), "w+") as f: fcntl.flock(f, fcntl.LOCK_EX) utils.update_hash(hash, key, new_value)
def _do_setup_step(self, play): ''' get facts from the remote system ''' host_list = self._trim_unavailable_hosts(play._play_hosts) if play.gather_facts is None and C.DEFAULT_GATHERING == 'smart': host_list = [h for h in host_list if h not in self.SETUP_CACHE or 'module_setup' not in self.SETUP_CACHE[h]] if len(host_list) == 0: return {} elif play.gather_facts is False or (play.gather_facts is None and C.DEFAULT_GATHERING == 'explicit'): return {} self.callbacks.on_setup() self.inventory.restrict_to(host_list) ansible.callbacks.set_task(self.callbacks, None) ansible.callbacks.set_task(self.runner_callbacks, None) # push any variables down to the system setup_results = ansible.runner.Runner( basedir=self.basedir, pattern=play.hosts, module_name='setup', module_args={}, inventory=self.inventory, forks=self.forks, module_path=self.module_path, timeout=self.timeout, remote_user=play.remote_user, remote_pass=self.remote_pass, remote_port=play.remote_port, private_key_file=self.private_key_file, setup_cache=self.SETUP_CACHE, vars_cache=self.VARS_CACHE, callbacks=self.runner_callbacks, sudo=play.sudo, sudo_user=play.sudo_user, sudo_pass=self.sudo_pass, su=play.su, su_user=play.su_user, su_pass=self.su_pass, vault_pass=self.vault_password, transport=play.transport, is_playbook=True, module_vars=play.vars, default_vars=play.default_vars, check=self.check, diff=self.diff, accelerate=play.accelerate, accelerate_port=play.accelerate_port, ).run() self.stats.compute(setup_results, setup=True) self.inventory.lift_restriction() # now for each result, load into the setup cache so we can # let runner template out future commands setup_ok = setup_results.get('contacted', {}) for (host, result) in setup_ok.iteritems(): utils.update_hash(self.SETUP_CACHE, host, {'module_setup': True}) utils.update_hash(self.SETUP_CACHE, host, result.get('ansible_facts', {})) return setup_results
def _do_setup_step(self, play): ''' get facts from the remote system ''' host_list = self._trim_unavailable_hosts(play._play_hosts) if play.gather_facts is None and C.DEFAULT_GATHERING == 'smart': host_list = [ h for h in host_list if h not in self.SETUP_CACHE or 'module_setup' not in self.SETUP_CACHE[h] ] if len(host_list) == 0: return {} elif play.gather_facts is False or (play.gather_facts is None and C.DEFAULT_GATHERING == 'explicit'): return {} self.callbacks.on_setup() self.inventory.restrict_to(host_list) ansible.callbacks.set_task(self.callbacks, None) ansible.callbacks.set_task(self.runner_callbacks, None) # push any variables down to the system setup_results = ansible.runner.Runner( basedir=self.basedir, pattern=play.hosts, module_name='setup', module_args={}, inventory=self.inventory, forks=self.forks, module_path=self.module_path, timeout=self.timeout, remote_user=play.remote_user, remote_pass=self.remote_pass, remote_port=play.remote_port, private_key_file=self.private_key_file, setup_cache=self.SETUP_CACHE, vars_cache=self.VARS_CACHE, callbacks=self.runner_callbacks, become=play.become, become_method=play.become_method, become_user=play.become_user, become_pass=self.become_pass, vault_pass=self.vault_password, transport=play.transport, is_playbook=True, module_vars=play.vars, play_vars=play.vars, play_file_vars=play.vars_file_vars, role_vars=play.role_vars, default_vars=play.default_vars, check=self.check, diff=self.diff, accelerate=play.accelerate, accelerate_port=play.accelerate_port, ).run() self.stats.compute(setup_results, setup=True) self.inventory.lift_restriction() # now for each result, load into the setup cache so we can # let runner template out future commands setup_ok = setup_results.get('contacted', {}) for (host, result) in setup_ok.iteritems(): utils.update_hash(self.SETUP_CACHE, host, {'module_setup': True}) utils.update_hash(self.SETUP_CACHE, host, result.get('ansible_facts', {})) return setup_results
def _run_task(self, play, task, is_handler): ''' run a single task in the playbook and recursively run any subtasks. ''' ansible.callbacks.set_task(self.callbacks, task) ansible.callbacks.set_task(self.runner_callbacks, task) if task.role_name: name = '%s | %s' % (task.role_name, task.name) else: name = task.name self.callbacks.on_task_start( template(play.basedir, name, task.module_vars, lookup_fatal=False, filter_fatal=False), is_handler) if hasattr(self.callbacks, 'skip_task') and self.callbacks.skip_task: ansible.callbacks.set_task(self.callbacks, None) ansible.callbacks.set_task(self.runner_callbacks, None) return True # template ignore_errors cond = template(play.basedir, task.ignore_errors, task.module_vars, expand_lists=False) task.ignore_errors = utils.check_conditional( cond, play.basedir, task.module_vars, fail_on_undefined=C.DEFAULT_UNDEFINED_VAR_BEHAVIOR) # load up an appropriate ansible runner to run the task in parallel results = self._run_task_internal(task) # if no hosts are matched, carry on hosts_remaining = True if results is None: hosts_remaining = False results = {} contacted = results.get('contacted', {}) self.stats.compute(results, ignore_errors=task.ignore_errors) def _register_play_vars(host, result): # when 'register' is used, persist the result in the vars cache # rather than the setup cache - vars should be transient between playbook executions if 'stdout' in result and 'stdout_lines' not in result: result['stdout_lines'] = result['stdout'].splitlines() utils.update_hash(self.VARS_CACHE, host, {task.register: result}) # add facts to the global setup cache for host, result in contacted.iteritems(): if 'results' in result: # task ran with_ lookup plugin, so facts are encapsulated in # multiple list items in the results key for res in result['results']: if type(res) == dict: facts = res.get('ansible_facts', {}) utils.update_hash(self.SETUP_CACHE, host, facts) else: # when facts are returned, persist them in the setup cache facts = result.get('ansible_facts', {}) utils.update_hash(self.SETUP_CACHE, host, facts) if task.register: _register_play_vars(host, result) # also have to register some failed, but ignored, tasks if task.ignore_errors and task.register: failed = results.get('failed', {}) for host, result in failed.iteritems(): _register_play_vars(host, result) # flag which notify handlers need to be run if len(task.notify) > 0: for host, results in results.get('contacted', {}).iteritems(): if results.get('changed', False): for handler_name in task.notify: self._flag_handler( play, template(play.basedir, handler_name, task.module_vars), host) ansible.callbacks.set_task(self.callbacks, None) ansible.callbacks.set_task(self.runner_callbacks, None) return hosts_remaining
def _run_task(self, play, task, is_handler): ''' run a single task in the playbook and recursively run any subtasks. ''' ansible.callbacks.set_task(self.callbacks, task) ansible.callbacks.set_task(self.runner_callbacks, task) if task.role_name: name = '%s | %s' % (task.role_name, task.name) else: name = task.name self.callbacks.on_task_start(template(play.basedir, name, task.module_vars, lookup_fatal=False, filter_fatal=False), is_handler) if hasattr(self.callbacks, 'skip_task') and self.callbacks.skip_task: ansible.callbacks.set_task(self.callbacks, None) ansible.callbacks.set_task(self.runner_callbacks, None) return True # template ignore_errors cond = template(play.basedir, task.ignore_errors, task.module_vars, expand_lists=False) task.ignore_errors = utils.check_conditional(cond, play.basedir, task.module_vars, fail_on_undefined=C.DEFAULT_UNDEFINED_VAR_BEHAVIOR) # load up an appropriate ansible runner to run the task in parallel results = self._run_task_internal(task) # if no hosts are matched, carry on hosts_remaining = True if results is None: hosts_remaining = False results = {} contacted = results.get('contacted', {}) self.stats.compute(results, ignore_errors=task.ignore_errors) def _register_play_vars(host, result): # when 'register' is used, persist the result in the vars cache # rather than the setup cache - vars should be transient between playbook executions if 'stdout' in result and 'stdout_lines' not in result: result['stdout_lines'] = result['stdout'].splitlines() utils.update_hash(self.VARS_CACHE, host, {task.register: result}) # add facts to the global setup cache for host, result in contacted.iteritems(): if 'results' in result: # task ran with_ lookup plugin, so facts are encapsulated in # multiple list items in the results key for res in result['results']: if type(res) == dict: facts = res.get('ansible_facts', {}) utils.update_hash(self.SETUP_CACHE, host, facts) else: # when facts are returned, persist them in the setup cache facts = result.get('ansible_facts', {}) utils.update_hash(self.SETUP_CACHE, host, facts) if task.register: _register_play_vars(host, result) # also have to register some failed, but ignored, tasks if task.ignore_errors and task.register: failed = results.get('failed', {}) for host, result in failed.iteritems(): _register_play_vars(host, result) # flag which notify handlers need to be run if len(task.notify) > 0: for host, results in results.get('contacted',{}).iteritems(): if results.get('changed', False): for handler_name in task.notify: self._flag_handler(play, template(play.basedir, handler_name, task.module_vars), host) ansible.callbacks.set_task(self.callbacks, None) ansible.callbacks.set_task(self.runner_callbacks, None) return hosts_remaining