From 313108543a3052e1e832db46bccc917e2f3f2c02 Mon Sep 17 00:00:00 2001 From: Alex Schultz Date: Tue, 19 May 2020 10:20:00 -0600 Subject: [PATCH] Implement run_once Prior to this patch, run_once was basically ignored. This patch adds tracking on tasks that are tagged with run_once and will only allow it to be invoked once. This means if the run_once task fails, all the other hosts will continue to process their tasks like nothing happened. The play itself will exit if the run_once task fails at the end. For tripleo this means that run_once should not be used for any required tasks within a play but can be used to make sure a task will only run once time for a given play. Change-Id: Iaa1278763d56429b2886371a18477e1f54680e19 (cherry picked from commit 894a853a5ef0af869624376a04a8f12dfe5c801c) --- .../ansible_plugins/strategy/tripleo_free.py | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tripleo_ansible/ansible_plugins/strategy/tripleo_free.py b/tripleo_ansible/ansible_plugins/strategy/tripleo_free.py index 3fdd87a1e..bd6794be5 100644 --- a/tripleo_ansible/ansible_plugins/strategy/tripleo_free.py +++ b/tripleo_ansible/ansible_plugins/strategy/tripleo_free.py @@ -36,6 +36,13 @@ DOCUMENTATION = ''' - Will fail playbook if any hosts have a failure during the execution and any_errors_fatal is true (free does not do this). - Should be backwards compatible for Ansible 2.8 + - Handles run_once to only invoke the task a single time for a + given run. It should be noted that run_once does not ensure the + task actually is successful but rather that it is only triggered + once time for the host groups. If the task fails, the playbook + will fail at the end of the play but there is no assurance that + the task will actually complete successfully for a given playbook + execution. Other tasks will continue on the other hosts. version_added: "2.9" author: Alex Schultz ''' @@ -70,6 +77,7 @@ class StrategyModule(StrategyBase): self._play_context = None self._strat_results = [] self._workers_free = 0 + self._run_once_tasks = set() # these were defined in 2.9 self._has_hosts_cache = False self._has_hosts_cache_all = False @@ -198,13 +206,23 @@ class StrategyModule(StrategyBase): run_once = (templar.template(task.run_once) or action and getattr(action, 'BYPASS_HOST_LOOP', False)) - # TODO(mwhahaha): make it work by caching it across all hosts if run_once: + display.warning('tripleo_free run_once does not ensure a task ' + 'is successful for a given playbook but rather ' + 'it is only attempted to execute once.') if action and getattr(action, 'BYPASS_HOST_LOOP', False): raise AnsibleError('Cannot bypass host loop with strategy') else: - display.warning("Using run_once does not work with the" - "tripleo_free strategy") + if task._uuid in self._run_once_tasks: + # If the task was previously executed, just drop it + # by clearing the blocked host and telling the parent + # function to continue. + self._debug("Skipping run_once task {} on {}".format( + task._uuid, host)) + del self._blocked_hosts[host_name] + raise TripleoFreeContinue() + else: + self._run_once_tasks.add(task._uuid) # handle role deduplication logic if task._role and task._role.has_run(host):