summaryrefslogtreecommitdiff
path: root/lib/ansible/executor
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/executor')
-rw-r--r--lib/ansible/executor/action_write_locks.py43
-rw-r--r--lib/ansible/executor/module_common.py8
-rw-r--r--lib/ansible/executor/task_queue_manager.py1
3 files changed, 48 insertions, 4 deletions
diff --git a/lib/ansible/executor/action_write_locks.py b/lib/ansible/executor/action_write_locks.py
new file mode 100644
index 0000000000..413d56d9d7
--- /dev/null
+++ b/lib/ansible/executor/action_write_locks.py
@@ -0,0 +1,43 @@
+# (c) 2016 - Red Hat, Inc. <support@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from multiprocessing import Lock
+from ansible.module_utils.facts import Facts
+
+if 'action_write_locks' not in globals():
+ # Do not initialize this more than once because it seems to bash
+ # the existing one. multiprocessing must be reloading the module
+ # when it forks?
+ action_write_locks = dict()
+
+ # Below is a Lock for use when we weren't expecting a named module.
+ # It gets used when an action plugin directly invokes a module instead
+ # of going through the strategies. Slightly less efficient as all
+ # processes with unexpected module names will wait on this lock
+ action_write_locks[None] = Lock()
+
+ # These plugins are called directly by action plugins (not going through
+ # a strategy). We precreate them here as an optimization
+ mods = set(p['name'] for p in Facts.PKG_MGRS)
+ mods.update(('copy', 'file', 'setup', 'slurp', 'stat'))
+ for mod_name in mods:
+ action_write_locks[mod_name] = Lock()
+
diff --git a/lib/ansible/executor/module_common.py b/lib/ansible/executor/module_common.py
index d7dac13de0..86549ea0b7 100644
--- a/lib/ansible/executor/module_common.py
+++ b/lib/ansible/executor/module_common.py
@@ -36,7 +36,7 @@ from ansible.module_utils._text import to_bytes, to_text
# Must import strategy and use write_locks from there
# If we import write_locks directly then we end up binding a
# variable to the object and then it never gets updated.
-from ansible.plugins import strategy
+from ansible.executor import action_write_locks
try:
from __main__ import display
@@ -605,16 +605,16 @@ def _find_snippet_imports(module_name, module_data, module_path, module_args, ta
display.debug('ANSIBALLZ: using cached module: %s' % cached_module_filename)
zipdata = open(cached_module_filename, 'rb').read()
else:
- if module_name in strategy.action_write_locks:
+ if module_name in action_write_locks.action_write_locks:
display.debug('ANSIBALLZ: Using lock for %s' % module_name)
- lock = strategy.action_write_locks[module_name]
+ lock = action_write_locks.action_write_locks[module_name]
else:
# If the action plugin directly invokes the module (instead of
# going through a strategy) then we don't have a cross-process
# Lock specifically for this module. Use the "unexpected
# module" lock instead
display.debug('ANSIBALLZ: Using generic lock for %s' % module_name)
- lock = strategy.action_write_locks[None]
+ lock = action_write_locks.action_write_locks[None]
display.debug('ANSIBALLZ: Acquiring lock')
with lock:
diff --git a/lib/ansible/executor/task_queue_manager.py b/lib/ansible/executor/task_queue_manager.py
index c003275306..2e6948f1e0 100644
--- a/lib/ansible/executor/task_queue_manager.py
+++ b/lib/ansible/executor/task_queue_manager.py
@@ -285,6 +285,7 @@ class TaskQueueManager:
for host_name in iterator.get_failed_hosts():
self._failed_hosts[host_name] = True
+ strategy.cleanup()
self._cleanup_processes()
return play_return