Fix calling ansible modules.

They cannot be called by passing their path, for example:
```
Traceback (most recent call last):
  File ".nox/pytest-parametrized-3-7-crypto-none-transport-zeromq-coverage-false/lib/python3.7/site-packages/ansible/modules/ping.py", line 63, in <module>
    from ansible.module_utils.basic import AnsibleModule
  File "/home/vampas/projects/SaltStack/salt/hotfix/ansiblegate-59792/.nox/pytest-parametrized-3-7-crypto-none-transport-zeromq-coverage-false/lib/python3.7/site-packages/ansible/module_utils/basic.py", line 53, in <module>
    import tempfile
  File "/home/vampas/projects/SaltStack/salt/hotfix/ansiblegate-59792/.nox/pytest-parametrized-3-7-crypto-none-transport-zeromq-coverage-false/lib/python3.7/site-packages/ansible/modules/tempfile.py", line 79, in <module>
    from tempfile import mkstemp, mkdtemp
ImportError: cannot import name 'mkstemp' from 'tempfile' (/home/vampas/projects/SaltStack/salt/hotfix/ansiblegate-59792/.nox/pytest-parametrized-3-7-crypto-none-transport-zeromq-coverage-false/lib/python3.7/site-packages/ansible/modules/tempfile.py)
```
This commit is contained in:
Pedro Algarvio 2021-05-19 07:44:24 +01:00 committed by Gareth J. Greenaway
parent e466589a6e
commit 241009d4fa
3 changed files with 60 additions and 71 deletions

View file

@ -171,25 +171,24 @@ class AnsibleModuleCaller:
)
if args:
kwargs["_raw_params"] = " ".join(args)
js_args = str(
'{{"ANSIBLE_MODULE_ARGS": {args}}}'
) # future lint: disable=blacklisted-function
js_args = js_args.format(args=salt.utils.json.dumps(kwargs))
js_args = salt.utils.json.dumps({"ANSIBLE_MODULE_ARGS": kwargs})
proc_out = salt.utils.timed_subprocess.TimedProc(
["echo", "{}".format(js_args)],
proc_exc = subprocess.run(
[
sys.executable,
"-c",
"import sys, {0}; print({0}.main(), file=sys.stdout); sys.stdout.flush()".format(
module.__name__
),
],
input=js_args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=self.timeout,
universal_newlines=True,
check=True,
shell=False,
)
proc_out.run()
proc_out_stdout = salt.utils.stringutils.to_str(proc_out.stdout)
proc_exc = salt.utils.timed_subprocess.TimedProc(
[sys.executable, module.__file__],
stdin=proc_out_stdout,
stdout=subprocess.PIPE,
timeout=self.timeout,
)
proc_exc.run()
try:
out = salt.utils.json.loads(proc_exc.stdout)
@ -249,14 +248,13 @@ def __virtual__():
"""
if salt.utils.platform.is_windows():
return False, "The ansiblegate module isn't supported on Windows"
ret = ansible is not None
msg = not ret and "Ansible is not installed on this system" or None
if ret:
global _resolver
global _caller
_resolver = AnsibleModuleResolver(__opts__).resolve().install()
_caller = AnsibleModuleCaller(_resolver)
_set_callables(list_())
if ansible is None:
return False, "Ansible is not installed on this system"
global _resolver
global _caller
_resolver = AnsibleModuleResolver(__opts__).resolve().install()
_caller = AnsibleModuleCaller(_resolver)
_set_callables(list_())
return __virtualname__

View file

@ -32,6 +32,7 @@ salt/modules/ansiblegate.py:
- unit.states.test_ansiblegate
- integration.states.test_ansiblegate
- pytests.functional.modules.test_ansiblegate
- pytests.unit.modules.test_ansiblegate
salt/modules/*apache.py:
- pytests.unit.states.apache.test_apache

View file

@ -4,23 +4,23 @@ import os
import sys
import pytest
import salt.modules.ansiblegate as ansible
import salt.modules.ansiblegate as ansiblegate
from salt.exceptions import LoaderError
from tests.support.mock import MagicMock, MockTimedProc, patch
from tests.support.mock import MagicMock, patch
pytestmark = [
pytest.mark.skip_on_windows,
pytest.mark.skip_on_windows(reason="Not supported on Windows"),
]
@pytest.fixture
def configure_loader_modules():
return {ansible: {}}
return {ansiblegate: {}}
@pytest.fixture
def resolver():
_resolver = ansible.AnsibleModuleResolver({})
_resolver = ansiblegate.AnsibleModuleResolver({})
_resolver._modules_map = {
"one.two.three": os.sep + os.path.join("one", "two", "three.py"),
"four.five.six": os.sep + os.path.join("four", "five", "six.py"),
@ -52,10 +52,10 @@ description:
describe the second part
"""
with patch.object(ansible, "_resolver", resolver), patch.object(
ansible._resolver, "load_module", MagicMock(return_value=Module())
with patch.object(ansiblegate, "_resolver", resolver), patch.object(
ansiblegate._resolver, "load_module", MagicMock(return_value=Module())
):
ret = ansible.help("dummy")
ret = ansiblegate.help("dummy")
assert sorted(
ret.get('Available sections on module "{}"'.format(Module().__name__))
) == ["one", "two"]
@ -87,11 +87,11 @@ def test_resolver_module_loader_failure(resolver):
:return:
"""
mod = "four.five.six"
with pytest.raises(ImportError) as import_error:
with pytest.raises(ImportError):
resolver.load_module(mod)
mod = "i.even.do.not.exist.at.all"
with pytest.raises(LoaderError) as loader_error:
with pytest.raises(LoaderError):
resolver.load_module(mod)
@ -114,7 +114,7 @@ def test_resolver_module_loader_import_failure(resolver):
with patch("salt.modules.ansiblegate.importlib", MagicMock()), patch(
"salt.modules.ansiblegate.importlib.import_module", lambda x: x
):
with pytest.raises(LoaderError) as loader_error:
with pytest.raises(LoaderError):
resolver.load_module("something.strange")
@ -124,9 +124,16 @@ def test_virtual_function(resolver):
:return:
"""
with patch("salt.modules.ansiblegate.ansible", None):
assert ansible.__virtual__() == "ansible"
assert ansiblegate.__virtual__() == (
False,
"Ansible is not installed on this system",
)
@pytest.mark.skipif(
sys.version_info < (3, 6),
reason="Skipped on Py3.5, the mock of subprocess.run is different",
)
def test_ansible_module_call(resolver):
"""
Test Ansible module call from ansible gate module
@ -144,45 +151,28 @@ def test_ansible_module_call(resolver):
def main(): # pylint: disable=no-method-argument
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=b'{"completed": true}', stderr=None),
]
)
with patch.object(ansible, "_resolver", resolver), patch.object(
ansible._resolver, "load_module", MagicMock(return_value=Module())
with patch.object(ansiblegate, "_resolver", resolver), patch.object(
ansiblegate._resolver, "load_module", MagicMock(return_value=Module())
):
_ansible_module_caller = ansible.AnsibleModuleCaller(ansible._resolver)
with patch("salt.utils.timed_subprocess.TimedProc", proc):
_ansible_module_caller = ansiblegate.AnsibleModuleCaller(ansiblegate._resolver)
with patch("subprocess.run") as proc_run_mock:
proc_run_mock.return_value.stdout = '{"completed": true}'
ret = _ansible_module_caller.call("one.two.three", "arg_1", kwarg1="foobar")
proc.assert_any_call(
[sys.executable, "foofile"],
stdin=ANSIBLE_MODULE_ARGS,
proc_run_mock.assert_any_call(
[
sys.executable,
"-c",
"import sys, one.two.three; print(one.two.three.main(), file=sys.stdout); sys.stdout.flush()",
],
input='{"ANSIBLE_MODULE_ARGS": {"kwarg1": "foobar", "_raw_params": "arg_1"}}',
stdout=-1,
stderr=-1,
check=True,
shell=False,
universal_newlines=True,
timeout=1200,
)
try:
proc.assert_any_call(
[
"echo",
'{"ANSIBLE_MODULE_ARGS": {"kwarg1": "foobar", "_raw_params": "arg_1"}}',
],
stdout=-1,
timeout=1200,
)
except AssertionError:
proc.assert_any_call(
[
"echo",
'{"ANSIBLE_MODULE_ARGS": {"_raw_params": "arg_1", "kwarg1": "foobar"}}',
],
stdout=-1,
timeout=1200,
)
assert ret == {"completed": True, "timeout": 1200}
@ -193,8 +183,8 @@ def test_ansible_playbooks_return_retcode(resolver):
"""
ref_out = {"retcode": 0, "stdout": '{"foo": "bar"}'}
cmd_run_all = MagicMock(return_value=ref_out)
with patch.dict(ansible.__salt__, {"cmd.run_all": cmd_run_all}), patch(
with patch.dict(ansiblegate.__salt__, {"cmd.run_all": cmd_run_all}), patch(
"salt.utils.path.which", MagicMock(return_value=True)
):
ret = ansible.playbooks("fake-playbook.yml")
ret = ansiblegate.playbooks("fake-playbook.yml")
assert "retcode" in ret