salt/tests/pytests/unit/state/test_reactor_compiler.py

669 lines
24 KiB
Python

import logging
import pytest
import salt.minion
import salt.state
from salt.utils.odict import OrderedDict
from tests.support.mock import MagicMock, patch
log = logging.getLogger(__name__)
pytestmark = [
pytest.mark.core_test,
]
def test_compiler_render_template(minion_opts, tmp_path):
"""
Test Compiler.render_template
"""
minion = "poc-minion"
kwargs = {
"tag": f"salt/minion/{minion}/start",
"data": {
"id": minion,
"cmd": "_minion_event",
"pretag": None,
"data": f"Minion {minion} started at Thu Sep 14 07:31:04 2023",
"tag": f"salt/minion/{minion}/start",
"_stamp": "2023-09-14T13:31:05.000316",
},
}
reactor_file = tmp_path / "reactor.sls"
content = f"""
highstate_run:
local.state.apply:
- tgt: {minion}
- args:
- mods: test
"""
with salt.utils.files.fopen(reactor_file, "w") as fp:
fp.write(content)
mminion = salt.minion.MasterMinion(minion_opts)
comp = salt.state.Compiler(minion_opts, mminion.rend)
ret = comp.render_template(template=str(reactor_file), kwargs=kwargs)
assert ret["highstate_run"]["local"][0]["tgt"] == minion
assert ret["highstate_run"]["local"][1]["args"][0]["mods"] == "test"
def test_compiler_render_template_doesnotexist(minion_opts, tmp_path):
"""
Test Compiler.render_template when
the reactor file does not exist
"""
minion = "poc-minion"
kwargs = {
"tag": f"salt/minion/{minion}/start",
"data": {
"id": minion,
"cmd": "_minion_event",
"pretag": None,
"data": f"Minion {minion} started at Thu Sep 14 07:31:04 2023",
"tag": f"salt/minion/{minion}/start",
"_stamp": "2023-09-14T13:31:05.000316",
},
}
reactor_file = tmp_path / "reactor.sls"
mminion = salt.minion.MasterMinion(minion_opts)
comp = salt.state.Compiler(minion_opts, mminion.rend)
mock_pad = MagicMock(return_value=None)
patch_pad = patch.object(comp, "pad_funcs", mock_pad)
with patch_pad:
ret = comp.render_template(template=str(reactor_file), kwargs=kwargs)
assert ret == {}
mock_pad.assert_not_called()
def test_compiler_pad_funcs(minion_opts, tmp_path):
"""
Test Compiler.pad_funcs
"""
high = OrderedDict(
[
(
"highstate_run",
OrderedDict(
[
(
"local.state.apply",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[("args", [OrderedDict([("mods", "test")])])]
),
],
)
]
),
)
]
)
exp = OrderedDict(
[
(
"highstate_run",
OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[("args", [OrderedDict([("mods", "test")])])]
),
"state.apply",
],
)
]
),
)
]
)
mminion = salt.minion.MasterMinion(minion_opts)
comp = salt.state.Compiler(minion_opts, mminion.rend)
ret = comp.pad_funcs(high)
assert ret == exp
def test_compiler_pad_funcs_short_sls(minion_opts, tmp_path):
"""
Test Compiler.pad_funcs when using a shorter
sls with no extra arguments
"""
high = OrderedDict([("master_pub", "wheel.key.master_key_str")])
exp = OrderedDict([("master_pub", {"wheel": ["key.master_key_str"]})])
mminion = salt.minion.MasterMinion(minion_opts)
comp = salt.state.Compiler(minion_opts, mminion.rend)
ret = comp.pad_funcs(high)
assert ret == exp
@pytest.mark.parametrize(
"high,exp",
[
(
{
"master_pub": {
"wheel": ["key.master_key_str"],
"__sls__": "/srv/reactor/start.sls",
}
},
[],
),
(set(), ["High data is not a dictionary and is invalid"]),
(
{
1234: {
"wheel": ["key.master_key_str"],
"__sls__": "/srv/reactor/start.sls",
}
},
[
"ID '1234' in SLS '/srv/reactor/start.sls' is not formed as a string, but is a int. It may need to be quoted"
],
),
(
{
b"test": {
"wheel": ["key.master_key_str"],
"__sls__": "/srv/reactor/start.sls",
}
},
[
"ID 'b'test'' in SLS '/srv/reactor/start.sls' is not formed as a string, but is a bytes. It may need to be quoted"
],
),
(
{
True: {
"wheel": ["key.master_key_str"],
"__sls__": "/srv/reactor/start.sls",
}
},
[
"ID 'True' in SLS '/srv/reactor/start.sls' is not formed as a string, but is a bool. It may need to be quoted"
],
),
(
{"master_pub": ["wheel", "key.master_key_str"]},
[
"The type master_pub in ['wheel', 'key.master_key_str'] is not formatted as a dictionary"
],
),
(
{
"master_pub": {
"wheel": {"key.master_key_str"},
"__sls__": "/srv/reactor/start.sls",
}
},
[
"State 'master_pub' in SLS '/srv/reactor/start.sls' is not formed as a list"
],
),
(
{
"master_pub": {
"wheel": ["key. master_key_str"],
"__sls__": "/srv/reactor/start.sls",
}
},
[
'The function "key. master_key_str" in state "master_pub" in SLS "/srv/reactor/start.sls" has whitespace, a function with whitespace is not supported, perhaps this is an argument that is missing a ":"'
],
),
(
{
"master_pub": {
"wheel": ["key.master_key_str "],
"__sls__": "/srv/reactor/start.sls",
}
},
[],
),
],
)
def test_compiler_verify_high_short_sls(minion_opts, tmp_path, high, exp):
"""
Test Compiler.verify_high when using
a shorter sls with know extra arguments
"""
mminion = salt.minion.MasterMinion(minion_opts)
comp = salt.state.Compiler(minion_opts, mminion.rend)
ret = comp.verify_high(high)
# empty is successful. Means we have no errors
assert ret == exp
@pytest.mark.parametrize(
"high,exp",
[
(
{
"add_test_1": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test1")]
)
],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
"add_test_2": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test2")]
)
],
)
]
),
OrderedDict(
[
(
"require",
[OrderedDict([("local", "add_test_1")])],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
},
[],
),
(
{
"add_test_1": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test1")]
)
],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
"add_test_2": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test2")]
)
],
)
]
),
OrderedDict([("require", {"local": "add_test_1"})]),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
},
[
"The require statement in state 'add_test_2' in SLS '/srv/reactor/start.sls' needs to be formed as a list"
],
),
(
{
"add_test_1": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test1")]
)
],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
"add_test_2": OrderedDict(
[
(
"local.cmd.run",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test2")]
)
],
)
]
),
OrderedDict([("require", {"local": "add_test_1"})]),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
},
[
"The require statement in state 'add_test_2' in SLS '/srv/reactor/start.sls' needs to be formed as a list",
"Too many functions declared in state 'add_test_2' in SLS '/srv/reactor/start.sls'. Please choose one of the following: cmd.run, cmd.run",
],
),
(
{
"add_test_1": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[("args", ([("cmd", "touch /tmp/test1")]))]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
"add_test_2": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test2")]
)
],
)
]
),
OrderedDict([("require", ([("local", "add_test_1")]))]),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
},
[
"Requisite declaration ('local', 'add_test_1') in SLS /srv/reactor/start.sls is not formed as a single key dictionary"
],
),
(
{
"add_test_1": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test1")]
)
],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
"add_test_2": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test2")]
)
],
)
]
),
OrderedDict(
[
(
"require",
[
OrderedDict(
[("local", (["add_test_1"]))]
)
],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
},
["Illegal requisite \"['add_test_1']\", is SLS /srv/reactor/start.sls\n"],
),
(
{
"add_test_1": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test1")]
)
],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
"add_test_2": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test2")]
)
],
)
]
),
OrderedDict(
[
(
"require",
[OrderedDict([("local", "add_test_2")])],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
},
[
'A recursive requisite was found, SLS "/srv/reactor/start.sls" ID "add_test_2" ID "add_test_2"'
],
),
(
{
"add_test_1": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test1")]
)
],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
"add_test_2": OrderedDict(
[
(
"local",
[
OrderedDict([("tgt", "poc-minion")]),
OrderedDict(
[
(
"args",
[
OrderedDict(
[("cmd", "touch /tmp/test2")]
)
],
)
]
),
OrderedDict(
[
(
"require",
[OrderedDict([("local", "add_test_1")])],
)
]
),
"cmd.run",
],
),
("__sls__", "/srv/reactor/start.sls"),
]
),
},
[],
),
],
)
def test_compiler_verify_high_sls_requisites(minion_opts, tmp_path, high, exp):
"""
Test Compiler.verify_high when using
a sls with requisites
"""
mminion = salt.minion.MasterMinion(minion_opts)
comp = salt.state.Compiler(minion_opts, mminion.rend)
ret = comp.verify_high(high)
# empty is successful. Means we have no errors
assert ret == exp