SHA256
1
0
forked from pool/salt
salt/do-not-make-ansiblegate-to-crash-on-python3-minions.patch

220 lines
7.8 KiB
Diff

From ee69f252a71b950377987d7fad3515082e09abff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Fri, 28 Jun 2019 15:17:56 +0100
Subject: [PATCH] Do not make ansiblegate to crash on Python3 minions
Fix pylint issues
Move MockTimedProc implementation to tests.support.mock
Add unit test for ansible caller
---
salt/modules/ansiblegate.py | 14 +++++++++---
tests/support/mock.py | 31 +++++++++++++++++++++++++
tests/unit/modules/test_ansiblegate.py | 41 ++++++++++++++++++++++++++++++++++
tests/unit/modules/test_cmdmod.py | 34 +---------------------------
4 files changed, 84 insertions(+), 36 deletions(-)
diff --git a/salt/modules/ansiblegate.py b/salt/modules/ansiblegate.py
index 771db6d6aa..88e8147573 100644
--- a/salt/modules/ansiblegate.py
+++ b/salt/modules/ansiblegate.py
@@ -147,6 +147,10 @@ class AnsibleModuleCaller(object):
:param kwargs: keywords to the module
:return:
'''
+ if six.PY3:
+ python_exec = 'python3'
+ else:
+ python_exec = 'python'
module = self._resolver.load_module(module)
if not hasattr(module, 'main'):
@@ -162,9 +166,13 @@ class AnsibleModuleCaller(object):
["echo", "{0}".format(js_args)],
stdout=subprocess.PIPE, timeout=self.timeout)
proc_out.run()
+ if six.PY3:
+ proc_out_stdout = proc_out.stdout.decode()
+ else:
+ proc_out_stdout = proc_out.stdout
proc_exc = salt.utils.timed_subprocess.TimedProc(
- ['python', module.__file__],
- stdin=proc_out.stdout, stdout=subprocess.PIPE, timeout=self.timeout)
+ [python_exec, module.__file__],
+ stdin=proc_out_stdout, stdout=subprocess.PIPE, timeout=self.timeout)
proc_exc.run()
try:
@@ -263,7 +271,7 @@ def help(module=None, *args):
description = doc.get('description') or ''
del doc['description']
ret['Description'] = description
- ret['Available sections on module "{}"'.format(module.__name__.replace('ansible.modules.', ''))] = doc.keys()
+ ret['Available sections on module "{}"'.format(module.__name__.replace('ansible.modules.', ''))] = [i for i in doc.keys()]
else:
for arg in args:
info = doc.get(arg)
diff --git a/tests/support/mock.py b/tests/support/mock.py
index 38b68bd5c4..4b44c112ee 100644
--- a/tests/support/mock.py
+++ b/tests/support/mock.py
@@ -510,6 +510,37 @@ class MockOpen(object):
ret.extend(fh_.writelines_calls)
return ret
+class MockTimedProc(object):
+ '''
+ Class used as a stand-in for salt.utils.timed_subprocess.TimedProc
+ '''
+ class _Process(object):
+ '''
+ Used to provide a dummy "process" attribute
+ '''
+ def __init__(self, returncode=0, pid=12345):
+ self.returncode = returncode
+ self.pid = pid
+
+ def __init__(self, stdout=None, stderr=None, returncode=0, pid=12345):
+ if stdout is not None and not isinstance(stdout, bytes):
+ raise TypeError('Must pass stdout to MockTimedProc as bytes')
+ if stderr is not None and not isinstance(stderr, bytes):
+ raise TypeError('Must pass stderr to MockTimedProc as bytes')
+ self._stdout = stdout
+ self._stderr = stderr
+ self.process = self._Process(returncode=returncode, pid=pid)
+
+ def run(self):
+ pass
+
+ @property
+ def stdout(self):
+ return self._stdout
+
+ @property
+ def stderr(self):
+ return self._stderr
# reimplement mock_open to support multiple filehandles
mock_open = MockOpen
diff --git a/tests/unit/modules/test_ansiblegate.py b/tests/unit/modules/test_ansiblegate.py
index 1fbb083eb7..70b47f8bc2 100644
--- a/tests/unit/modules/test_ansiblegate.py
+++ b/tests/unit/modules/test_ansiblegate.py
@@ -29,6 +29,7 @@ from tests.support.unit import TestCase, skipIf
from tests.support.mock import (
patch,
MagicMock,
+ MockTimedProc,
NO_MOCK,
NO_MOCK_REASON
)
@@ -36,6 +37,7 @@ from tests.support.mock import (
import salt.modules.ansiblegate as ansible
import salt.utils.platform
from salt.exceptions import LoaderError
+from salt.ext import six
@skipIf(NO_MOCK, NO_MOCK_REASON)
@@ -137,3 +139,42 @@ description:
'''
with patch('salt.modules.ansiblegate.ansible', None):
assert ansible.__virtual__() == 'ansible'
+
+ def test_ansible_module_call(self):
+ '''
+ Test Ansible module call from ansible gate module
+
+ :return:
+ '''
+
+ class Module(object):
+ '''
+ An ansible module mock.
+ '''
+ __name__ = 'one.two.three'
+ __file__ = 'foofile'
+
+ def main():
+ pass
+
+ ANSIBLE_MODULE_ARGS = '{"ANSIBLE_MODULE_ARGS": ["arg_1", {"kwarg1": "foobar"}]}'
+
+ proc = MagicMock(side_effect=[
+ MockTimedProc(
+ stdout=ANSIBLE_MODULE_ARGS.encode(),
+ stderr=None),
+ MockTimedProc(stdout='{"completed": true}'.encode(), stderr=None)
+ ])
+
+ with patch.object(ansible, '_resolver', self.resolver), \
+ patch.object(ansible._resolver, 'load_module', MagicMock(return_value=Module())):
+ _ansible_module_caller = ansible.AnsibleModuleCaller(ansible._resolver)
+ with patch('salt.utils.timed_subprocess.TimedProc', proc):
+ ret = _ansible_module_caller.call("one.two.three", "arg_1", kwarg1="foobar")
+ if six.PY3:
+ proc.assert_any_call(['echo', '{"ANSIBLE_MODULE_ARGS": {"kwarg1": "foobar", "_raw_params": "arg_1"}}'], stdout=-1, timeout=1200)
+ proc.assert_any_call(['python3', 'foofile'], stdin=ANSIBLE_MODULE_ARGS, stdout=-1, timeout=1200)
+ else:
+ proc.assert_any_call(['echo', '{"ANSIBLE_MODULE_ARGS": {"_raw_params": "arg_1", "kwarg1": "foobar"}}'], stdout=-1, timeout=1200)
+ proc.assert_any_call(['python', 'foofile'], stdin=ANSIBLE_MODULE_ARGS, stdout=-1, timeout=1200)
+ assert ret == {"completed": True, "timeout": 1200}
diff --git a/tests/unit/modules/test_cmdmod.py b/tests/unit/modules/test_cmdmod.py
index 8da672dd22..a20afaca0f 100644
--- a/tests/unit/modules/test_cmdmod.py
+++ b/tests/unit/modules/test_cmdmod.py
@@ -24,6 +24,7 @@ from tests.support.paths import FILES
from tests.support.mock import (
mock_open,
Mock,
+ MockTimedProc,
MagicMock,
NO_MOCK,
NO_MOCK_REASON,
@@ -36,39 +37,6 @@ MOCK_SHELL_FILE = '# List of acceptable shells\n' \
'/bin/bash\n'
-class MockTimedProc(object):
- '''
- Class used as a stand-in for salt.utils.timed_subprocess.TimedProc
- '''
- class _Process(object):
- '''
- Used to provide a dummy "process" attribute
- '''
- def __init__(self, returncode=0, pid=12345):
- self.returncode = returncode
- self.pid = pid
-
- def __init__(self, stdout=None, stderr=None, returncode=0, pid=12345):
- if stdout is not None and not isinstance(stdout, bytes):
- raise TypeError('Must pass stdout to MockTimedProc as bytes')
- if stderr is not None and not isinstance(stderr, bytes):
- raise TypeError('Must pass stderr to MockTimedProc as bytes')
- self._stdout = stdout
- self._stderr = stderr
- self.process = self._Process(returncode=returncode, pid=pid)
-
- def run(self):
- pass
-
- @property
- def stdout(self):
- return self._stdout
-
- @property
- def stderr(self):
- return self._stderr
-
-
@skipIf(NO_MOCK, NO_MOCK_REASON)
class CMDMODTestCase(TestCase, LoaderModuleMockMixin):
'''
--
2.16.4