Merge "Fix infinite recursion on action module import" into feature/zuulv3
diff --git a/zuul/ansible/action/normal.py b/zuul/ansible/action/normal.py
index a50125c..b18cb51 100644
--- a/zuul/ansible/action/normal.py
+++ b/zuul/ansible/action/normal.py
@@ -13,12 +13,8 @@
# You should have received a copy of the GNU General Public License
# along with this software. If not, see <http://www.gnu.org/licenses/>.
-# TODO(mordred) Figure out how to not need to do this to get the base class
-import ansible.plugins.action
-import imp
-normal = imp.load_module(
- 'ansible.plugins.action.normal',
- *imp.find_module('normal', ansible.plugins.action.__path__))
+from zuul.ansible import paths
+normal = paths._import_ansible_action_plugin('normal')
class ActionModule(normal.ActionModule):
diff --git a/zuul/ansible/paths.py b/zuul/ansible/paths.py
index 2bd0181..cde43f1 100644
--- a/zuul/ansible/paths.py
+++ b/zuul/ansible/paths.py
@@ -13,8 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with this software. If not, see <http://www.gnu.org/licenses/>.
+import imp
import os
+import ansible.plugins.action
+
def _is_safe_path(path):
if os.path.isabs(path):
@@ -31,3 +34,21 @@
path=path,
msg="{prefix} outside the working dir is prohibited".format(
prefix=prefix))
+
+
+def _import_ansible_action_plugin(name):
+ # Ansible forces the import of our action plugins
+ # (zuul.ansible.action.foo) as ansible.plugins.action.foo, which
+ # is the import path of the ansible implementation. Our
+ # implementations need to subclass that, but if we try to import
+ # it with that name, we will get our own module. This bypasses
+ # Python's module namespace to load the actual ansible modules.
+ # We need to give it a name, however. If we load it with its
+ # actual name, we will end up overwriting our module in Python's
+ # namespace, causing infinite recursion. So we supply an
+ # otherwise unused name for the module:
+ # zuul.ansible.protected.action.foo.
+
+ return imp.load_module(
+ 'zuul.ansible.protected.action.' + name,
+ *imp.find_module(name, ansible.plugins.action.__path__))