dede5bd1d4
OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=166
219 lines
7.8 KiB
Diff
219 lines
7.8 KiB
Diff
From 235cca81be2f64ed3feb48ed42bfa3f9196bff39 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 | 35 ++---------------------------
|
|
4 files changed, 85 insertions(+), 36 deletions(-)
|
|
|
|
diff --git a/salt/modules/ansiblegate.py b/salt/modules/ansiblegate.py
|
|
index 6b903c2b94..8e28fcafa3 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 805a60377c..67ecb4838a 100644
|
|
--- a/tests/support/mock.py
|
|
+++ b/tests/support/mock.py
|
|
@@ -461,6 +461,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 5613a0e79b..b7b43efda4 100644
|
|
--- a/tests/unit/modules/test_ansiblegate.py
|
|
+++ b/tests/unit/modules/test_ansiblegate.py
|
|
@@ -29,11 +29,13 @@ from tests.support.unit import TestCase, skipIf
|
|
from tests.support.mock import (
|
|
patch,
|
|
MagicMock,
|
|
+ MockTimedProc,
|
|
)
|
|
|
|
import salt.modules.ansiblegate as ansible
|
|
import salt.utils.platform
|
|
from salt.exceptions import LoaderError
|
|
+from salt.ext import six
|
|
|
|
|
|
@skipIf(NO_PYTEST, False)
|
|
@@ -134,3 +136,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 8170a56b4e..f8fba59294 100644
|
|
--- a/tests/unit/modules/test_cmdmod.py
|
|
+++ b/tests/unit/modules/test_cmdmod.py
|
|
@@ -26,6 +26,7 @@ from tests.support.helpers import TstSuiteLoggingHandler
|
|
from tests.support.mock import (
|
|
mock_open,
|
|
Mock,
|
|
+ MockTimedProc,
|
|
MagicMock,
|
|
patch
|
|
)
|
|
@@ -36,39 +37,7 @@ 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):
|
|
'''
|
|
Unit tests for the salt.modules.cmdmod module
|
|
--
|
|
2.16.4
|
|
|
|
|