Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow saltcheck to use remote file client functions and render pyobjects states #62726

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/62398.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix ability to execute remote file client methods in saltcheck
1 change: 1 addition & 0 deletions changelog/62523.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix rendering of pyobjects states in saltcheck
27 changes: 20 additions & 7 deletions salt/modules/saltcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,11 @@

log = logging.getLogger(__name__)

global_scheck = None
try:
__context__
except NameError:
__context__ = {}
__context__["global_scheck"] = None

__virtualname__ = "saltcheck"

Expand Down Expand Up @@ -457,8 +461,7 @@ def run_state_tests(state, saltenv=None, check_all=False, only_fails=False):
saltenv = "base"

# Use global scheck variable for reuse in each multiprocess
global global_scheck
global_scheck = SaltCheck(saltenv)
__context__["global_scheck"] = SaltCheck(saltenv)

parallel = __salt__["config.get"]("saltcheck_parallel")
num_proc = __salt__["config.get"]("saltcheck_processes")
Expand Down Expand Up @@ -508,7 +511,7 @@ def run_state_tests(state, saltenv=None, check_all=False, only_fails=False):
results_dict[key] = value
else:
for key, value in stl.test_dict.items():
result = global_scheck.run_test(value)
result = __context__["global_scheck"].run_test(value)
results_dict[key] = result

# If passed a duplicate state, don't overwrite with empty res
Expand All @@ -522,7 +525,7 @@ def parallel_scheck(data):
key = data[0]
value = data[1]
results = {}
results[key] = global_scheck.run_test(value)
results[key] = __context__["global_scheck"].run_test(value)
return results


Expand Down Expand Up @@ -620,7 +623,9 @@ def _render_file(file_path):
call the salt utility to render a file
"""
# salt-call slsutil.renderer /srv/salt/jinjatest/saltcheck-tests/test1.tst
rendered = __salt__["slsutil.renderer"](file_path, saltenv=global_scheck.saltenv)
rendered = __salt__["slsutil.renderer"](
file_path, saltenv=__context__["global_scheck"].saltenv
)
log.info("rendered: %s", rendered)
return rendered

Expand Down Expand Up @@ -747,12 +752,20 @@ def _call_salt_command(self, fun, args, kwargs):
"""
Generic call of salt Caller command
"""
# remote functions and modules won't work with local file client
# these aren't exhaustive lists, so add to them when a module or
# function can't operate without the remote file client
remote_functions = ["file.check_managed_changes"]
remote_modules = ["cp"]
mod = fun.split(".", maxsplit=1)[0]

conf_file = __opts__["conf_file"]
local_opts = salt.config.minion_config(conf_file)
# Save orginal file_client to restore after salt.client.Caller run
orig_file_client = local_opts["file_client"]
mlocal_opts = copy.deepcopy(local_opts)
mlocal_opts["file_client"] = "local"
if fun not in remote_functions and mod not in remote_modules:
mlocal_opts["file_client"] = "local"
value = False
if args and kwargs:
value = salt.client.Caller(mopts=mlocal_opts).cmd(fun, *args, **kwargs)
Expand Down
82 changes: 82 additions & 0 deletions tests/pytests/integration/modules/test_saltcheck.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import pytest


@pytest.mark.slow_test
def test_saltcheck_render_pyobjects_state(salt_master, salt_call_cli):
with pytest.helpers.temp_file("pyobj_touched.txt") as tpath:
sls_content = """
#!pyobjects

File.touch("{}")
""".format(
tpath
)

tst_content = """
is_stuff_there:
module_and_function: file.file_exists
args:
- "{}"
assertion: assertTrue
""".format(
tpath
)

with salt_master.state_tree.base.temp_file(
"pyobj_touched/init.sls", sls_content
):
with salt_master.state_tree.base.temp_file(
"pyobj_touched/saltcheck-tests/init.tst", tst_content
):
ret = salt_call_cli.run(
"--local",
"saltcheck.run_state_tests",
"pyobj_touched",
)
assert (
ret.data[0]["pyobj_touched"]["is_stuff_there"]["status"] == "Pass"
)
assert ret.data[1]["TEST RESULTS"]["Passed"] == 1
assert ret.data[1]["TEST RESULTS"]["Missing Tests"] == 0
assert ret.data[1]["TEST RESULTS"]["Failed"] == 0
assert ret.data[1]["TEST RESULTS"]["Skipped"] == 0


@pytest.mark.slow_test
def test_saltcheck_allow_remote_fileclient(salt_master, salt_call_cli):
sls_content = """
test_state:
test.show_notification:
- text: The test state
"""

tst_content = """
test cp.cache_file:
module_and_function: cp.cache_file
args:
- salt://sltchk_remote/download_me.txt
kwargs:
saltenv: base
assertion: assertNotEmpty
output_details: True
"""

with salt_master.state_tree.base.temp_file("sltchk_remote/init.sls", sls_content):
with salt_master.state_tree.base.temp_file(
"sltchk_remote/saltcheck-tests/init.tst", tst_content
):
with salt_master.state_tree.base.temp_file(
"sltchk_remote/download_me.txt", "salty"
):
ret = salt_call_cli.run(
"saltcheck.run_state_tests",
"sltchk_remote",
)
assert (
ret.data[0]["sltchk_remote"]["test cp.cache_file"]["status"]
== "Pass"
)
assert ret.data[1]["TEST RESULTS"]["Passed"] == 1
assert ret.data[1]["TEST RESULTS"]["Missing Tests"] == 0
assert ret.data[1]["TEST RESULTS"]["Failed"] == 0
assert ret.data[1]["TEST RESULTS"]["Skipped"] == 0