6430be99be
OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=194
1064 lines
39 KiB
Diff
1064 lines
39 KiB
Diff
From e28a67ec69b4781fc9c667a9cdec66192e4cca45 Mon Sep 17 00:00:00 2001
|
|
From: Alexander Graul <agraul@suse.com>
|
|
Date: Wed, 19 Jan 2022 17:45:01 +0100
|
|
Subject: [PATCH] Refactor and improvements for "transactional-updates"
|
|
module
|
|
|
|
Add --no-return-event option to salt-call
|
|
|
|
Act on concurrent flag when running highstate
|
|
|
|
Simplify transactional_update module to not use SSH wrapper
|
|
|
|
Fix tests for transactional update
|
|
|
|
Add changelog
|
|
|
|
Fix pylint issues
|
|
|
|
Fix failing unit test for state.highstate after refactor
|
|
|
|
Remove hack about tukit issue that has been already fixed
|
|
---
|
|
changelog/61188.fixed | 3 +
|
|
salt/cli/caller.py | 2 +-
|
|
salt/modules/state.py | 12 +-
|
|
salt/modules/transactional_update.py | 235 ++---------
|
|
salt/utils/parsers.py | 6 +
|
|
.../pytests/unit/modules/state/test_state.py | 2 +-
|
|
.../unit/modules/test_transactional_update.py | 389 ++----------------
|
|
7 files changed, 81 insertions(+), 568 deletions(-)
|
|
create mode 100644 changelog/61188.fixed
|
|
|
|
diff --git a/changelog/61188.fixed b/changelog/61188.fixed
|
|
new file mode 100644
|
|
index 0000000000..102a8982a6
|
|
--- /dev/null
|
|
+++ b/changelog/61188.fixed
|
|
@@ -0,0 +1,3 @@
|
|
+Add "--no-return-event" option to salt-call to prevent sending return event back to master.
|
|
+Make "state.highstate" to acts on concurrent flag.
|
|
+Simplify "transactional_update" module to not use SSH wrapper and allow more flexible execution
|
|
diff --git a/salt/cli/caller.py b/salt/cli/caller.py
|
|
index 795d32e4c9..10eb5e397a 100644
|
|
--- a/salt/cli/caller.py
|
|
+++ b/salt/cli/caller.py
|
|
@@ -293,7 +293,7 @@ class BaseCaller:
|
|
pass
|
|
|
|
# return the job infos back up to the respective minion's master
|
|
- if not is_local:
|
|
+ if not is_local and not self.opts.get("no_return_event", False):
|
|
try:
|
|
mret = ret.copy()
|
|
mret["jid"] = "req"
|
|
diff --git a/salt/modules/state.py b/salt/modules/state.py
|
|
index c78072131b..0c3dfc3317 100644
|
|
--- a/salt/modules/state.py
|
|
+++ b/salt/modules/state.py
|
|
@@ -1053,9 +1053,15 @@ def highstate(test=None, queue=False, **kwargs):
|
|
}
|
|
return ret
|
|
|
|
- conflict = _check_queue(queue, kwargs)
|
|
- if conflict is not None:
|
|
- return conflict
|
|
+ concurrent = kwargs.get("concurrent", False)
|
|
+
|
|
+ if queue:
|
|
+ _wait(kwargs.get("__pub_jid"))
|
|
+ else:
|
|
+ conflict = running(concurrent)
|
|
+ if conflict:
|
|
+ __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
|
|
+ return conflict
|
|
|
|
orig_test = __opts__.get("test", None)
|
|
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
|
|
diff --git a/salt/modules/transactional_update.py b/salt/modules/transactional_update.py
|
|
index 799fe08e4d..28b02f8fec 100644
|
|
--- a/salt/modules/transactional_update.py
|
|
+++ b/salt/modules/transactional_update.py
|
|
@@ -275,11 +275,7 @@ transaction.
|
|
|
|
"""
|
|
|
|
-import copy
|
|
import logging
|
|
-import os
|
|
-import sys
|
|
-import tempfile
|
|
|
|
# required by _check_queue invocation later
|
|
import time # pylint: disable=unused-import
|
|
@@ -312,11 +308,6 @@ def __virtual__():
|
|
return (False, "Module transactional_update requires a transactional system")
|
|
|
|
|
|
-class TransactionalUpdateHighstate(salt.client.ssh.state.SSHHighState):
|
|
- def _master_tops(self):
|
|
- return self.client.master_tops()
|
|
-
|
|
-
|
|
def _global_params(self_update, snapshot=None, quiet=False):
|
|
"""Utility function to prepare common global parameters."""
|
|
params = ["--non-interactive", "--drop-if-no-change"]
|
|
@@ -950,65 +941,42 @@ def call(function, *args, **kwargs):
|
|
|
|
activate_transaction = kwargs.pop("activate_transaction", False)
|
|
|
|
- # Generate the salt-thin and create a temporary directory in a
|
|
- # place that the new transaction will have access to, and where we
|
|
- # can untar salt-thin
|
|
- thin_path = __utils__["thin.gen_thin"](
|
|
- __opts__["cachedir"],
|
|
- extra_mods=__salt__["config.option"]("thin_extra_mods", ""),
|
|
- so_mods=__salt__["config.option"]("thin_so_mods", ""),
|
|
- )
|
|
- thin_dest_path = tempfile.mkdtemp(dir=__opts__["cachedir"])
|
|
- # Some bug in Salt is preventing us to use `archive.tar` here. A
|
|
- # AsyncZeroMQReqChannel is not closed at the end of the salt-call,
|
|
- # and makes the client never exit.
|
|
- #
|
|
- # stdout = __salt__['archive.tar']('xzf', thin_path, dest=thin_dest_path)
|
|
- #
|
|
- stdout = __salt__["cmd.run"](["tar", "xzf", thin_path, "-C", thin_dest_path])
|
|
- if stdout:
|
|
- __utils__["files.rm_rf"](thin_dest_path)
|
|
- return {"result": False, "comment": stdout}
|
|
-
|
|
try:
|
|
safe_kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
|
salt_argv = (
|
|
[
|
|
- "python{}".format(sys.version_info[0]),
|
|
- os.path.join(thin_dest_path, "salt-call"),
|
|
- "--metadata",
|
|
- "--local",
|
|
- "--log-file",
|
|
- os.path.join(thin_dest_path, "log"),
|
|
- "--cachedir",
|
|
- os.path.join(thin_dest_path, "cache"),
|
|
+ "salt-call",
|
|
"--out",
|
|
"json",
|
|
"-l",
|
|
"quiet",
|
|
+ "--no-return-event",
|
|
"--",
|
|
function,
|
|
]
|
|
+ list(args)
|
|
+ ["{}={}".format(k, v) for (k, v) in safe_kwargs.items()]
|
|
)
|
|
+
|
|
try:
|
|
ret_stdout = run([str(x) for x in salt_argv], snapshot="continue")
|
|
except salt.exceptions.CommandExecutionError as e:
|
|
+ # This happens when there was an problem with salt-call execution
|
|
ret_stdout = e.message
|
|
|
|
# Process "real" result in stdout
|
|
try:
|
|
data = __utils__["json.find_json"](ret_stdout)
|
|
local = data.get("local", data)
|
|
- if isinstance(local, dict) and "retcode" in local:
|
|
- __context__["retcode"] = local["retcode"]
|
|
- return local.get("return", data)
|
|
+ if isinstance(local, dict):
|
|
+ if "retcode" in local:
|
|
+ __context__["retcode"] = local["retcode"]
|
|
+ return local.get("return", local)
|
|
+ else:
|
|
+ return local
|
|
except ValueError:
|
|
return {"result": False, "retcode": 1, "comment": ret_stdout}
|
|
finally:
|
|
- __utils__["files.rm_rf"](thin_dest_path)
|
|
-
|
|
# Check if reboot is needed
|
|
if activate_transaction and pending_transaction():
|
|
reboot()
|
|
@@ -1044,49 +1012,7 @@ def apply_(mods=None, **kwargs):
|
|
return highstate(**kwargs)
|
|
|
|
|
|
-def _create_and_execute_salt_state(
|
|
- chunks, file_refs, test, hash_type, activate_transaction
|
|
-):
|
|
- """Create the salt_state tarball, and execute it in a transaction"""
|
|
-
|
|
- # Create the tar containing the state pkg and relevant files.
|
|
- salt.client.ssh.wrapper.state._cleanup_slsmod_low_data(chunks)
|
|
- trans_tar = salt.client.ssh.state.prep_trans_tar(
|
|
- salt.fileclient.get_file_client(__opts__), chunks, file_refs, __pillar__.value()
|
|
- )
|
|
- trans_tar_sum = salt.utils.hashutils.get_hash(trans_tar, hash_type)
|
|
-
|
|
- ret = None
|
|
-
|
|
- # Create a temporary directory accesible later by the transaction
|
|
- # where we can move the salt_state.tgz
|
|
- salt_state_path = tempfile.mkdtemp(dir=__opts__["cachedir"])
|
|
- salt_state_path = os.path.join(salt_state_path, "salt_state.tgz")
|
|
- try:
|
|
- salt.utils.files.copyfile(trans_tar, salt_state_path)
|
|
- ret = call(
|
|
- "state.pkg",
|
|
- salt_state_path,
|
|
- test=test,
|
|
- pkg_sum=trans_tar_sum,
|
|
- hash_type=hash_type,
|
|
- activate_transaction=activate_transaction,
|
|
- )
|
|
- finally:
|
|
- __utils__["files.rm_rf"](salt_state_path)
|
|
-
|
|
- return ret
|
|
-
|
|
-
|
|
-def sls(
|
|
- mods,
|
|
- saltenv="base",
|
|
- test=None,
|
|
- exclude=None,
|
|
- activate_transaction=False,
|
|
- queue=False,
|
|
- **kwargs
|
|
-):
|
|
+def sls(mods, activate_transaction=False, queue=False, **kwargs):
|
|
"""Execute the states in one or more SLS files inside a transaction.
|
|
|
|
saltenv
|
|
@@ -1132,55 +1058,14 @@ def sls(
|
|
if conflict is not None:
|
|
return conflict
|
|
|
|
- # Get a copy of the pillar data, to avoid overwriting the current
|
|
- # pillar, instead the one delegated
|
|
- pillar = copy.deepcopy(__pillar__.value())
|
|
- pillar.update(kwargs.get("pillar", {}))
|
|
-
|
|
- # Clone the options data and apply some default values. May not be
|
|
- # needed, as this module just delegate
|
|
- opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
|
|
- st_ = TransactionalUpdateHighstate(
|
|
- opts, pillar, __salt__, salt.fileclient.get_file_client(__opts__)
|
|
- )
|
|
-
|
|
- if isinstance(mods, str):
|
|
- mods = mods.split(",")
|
|
-
|
|
- high_data, errors = st_.render_highstate({saltenv: mods})
|
|
- if exclude:
|
|
- if isinstance(exclude, str):
|
|
- exclude = exclude.split(",")
|
|
- if "__exclude__" in high_data:
|
|
- high_data["__exclude__"].extend(exclude)
|
|
- else:
|
|
- high_data["__exclude__"] = exclude
|
|
-
|
|
- high_data, ext_errors = st_.state.reconcile_extend(high_data)
|
|
- errors += ext_errors
|
|
- errors += st_.state.verify_high(high_data)
|
|
- if errors:
|
|
- return errors
|
|
-
|
|
- high_data, req_in_errors = st_.state.requisite_in(high_data)
|
|
- errors += req_in_errors
|
|
- if errors:
|
|
- return errors
|
|
-
|
|
- high_data = st_.state.apply_exclude(high_data)
|
|
-
|
|
- # Compile and verify the raw chunks
|
|
- chunks = st_.state.compile_high_data(high_data)
|
|
- file_refs = salt.client.ssh.state.lowstate_file_refs(
|
|
- chunks,
|
|
- salt.client.ssh.wrapper.state._merge_extra_filerefs(
|
|
- kwargs.get("extra_filerefs", ""), opts.get("extra_filerefs", "")
|
|
- ),
|
|
- )
|
|
+ concurrent = kwargs.pop("concurrent", True)
|
|
|
|
- hash_type = opts["hash_type"]
|
|
- return _create_and_execute_salt_state(
|
|
- chunks, file_refs, test, hash_type, activate_transaction
|
|
+ return call(
|
|
+ "state.sls",
|
|
+ mods,
|
|
+ activate_transaction=activate_transaction,
|
|
+ concurrent=concurrent,
|
|
+ **kwargs
|
|
)
|
|
|
|
|
|
@@ -1216,40 +1101,15 @@ def highstate(activate_transaction=False, queue=False, **kwargs):
|
|
if conflict is not None:
|
|
return conflict
|
|
|
|
- # Get a copy of the pillar data, to avoid overwriting the current
|
|
- # pillar, instead the one delegated
|
|
- pillar = copy.deepcopy(__pillar__.value())
|
|
- pillar.update(kwargs.get("pillar", {}))
|
|
-
|
|
- # Clone the options data and apply some default values. May not be
|
|
- # needed, as this module just delegate
|
|
- opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
|
|
- st_ = TransactionalUpdateHighstate(
|
|
- opts, pillar, __salt__, salt.fileclient.get_file_client(__opts__)
|
|
- )
|
|
-
|
|
- # Compile and verify the raw chunks
|
|
- chunks = st_.compile_low_chunks()
|
|
- file_refs = salt.client.ssh.state.lowstate_file_refs(
|
|
- chunks,
|
|
- salt.client.ssh.wrapper.state._merge_extra_filerefs(
|
|
- kwargs.get("extra_filerefs", ""), opts.get("extra_filerefs", "")
|
|
- ),
|
|
- )
|
|
- # Check for errors
|
|
- for chunk in chunks:
|
|
- if not isinstance(chunk, dict):
|
|
- __context__["retcode"] = 1
|
|
- return chunks
|
|
-
|
|
- test = kwargs.pop("test", False)
|
|
- hash_type = opts["hash_type"]
|
|
- return _create_and_execute_salt_state(
|
|
- chunks, file_refs, test, hash_type, activate_transaction
|
|
+ return call(
|
|
+ "state.highstate",
|
|
+ activate_transaction=activate_transaction,
|
|
+ concurrent=True,
|
|
+ **kwargs
|
|
)
|
|
|
|
|
|
-def single(fun, name, test=None, activate_transaction=False, queue=False, **kwargs):
|
|
+def single(fun, name, activate_transaction=False, queue=False, **kwargs):
|
|
"""Execute a single state function with the named kwargs, returns
|
|
False if insufficient data is sent to the command
|
|
|
|
@@ -1282,44 +1142,11 @@ def single(fun, name, test=None, activate_transaction=False, queue=False, **kwar
|
|
if conflict is not None:
|
|
return conflict
|
|
|
|
- # Get a copy of the pillar data, to avoid overwriting the current
|
|
- # pillar, instead the one delegated
|
|
- pillar = copy.deepcopy(__pillar__.value())
|
|
- pillar.update(kwargs.get("pillar", {}))
|
|
-
|
|
- # Clone the options data and apply some default values. May not be
|
|
- # needed, as this module just delegate
|
|
- opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
|
|
- st_ = salt.client.ssh.state.SSHState(opts, pillar)
|
|
-
|
|
- # state.fun -> [state, fun]
|
|
- comps = fun.split(".")
|
|
- if len(comps) < 2:
|
|
- __context__["retcode"] = 1
|
|
- return "Invalid function passed"
|
|
-
|
|
- # Create the low chunk, using kwargs as a base
|
|
- kwargs.update({"state": comps[0], "fun": comps[1], "__id__": name, "name": name})
|
|
-
|
|
- # Verify the low chunk
|
|
- err = st_.verify_data(kwargs)
|
|
- if err:
|
|
- __context__["retcode"] = 1
|
|
- return err
|
|
-
|
|
- # Must be a list of low-chunks
|
|
- chunks = [kwargs]
|
|
-
|
|
- # Retrieve file refs for the state run, so we can copy relevant
|
|
- # files down to the minion before executing the state
|
|
- file_refs = salt.client.ssh.state.lowstate_file_refs(
|
|
- chunks,
|
|
- salt.client.ssh.wrapper.state._merge_extra_filerefs(
|
|
- kwargs.get("extra_filerefs", ""), opts.get("extra_filerefs", "")
|
|
- ),
|
|
- )
|
|
-
|
|
- hash_type = opts["hash_type"]
|
|
- return _create_and_execute_salt_state(
|
|
- chunks, file_refs, test, hash_type, activate_transaction
|
|
+ return call(
|
|
+ "state.single",
|
|
+ fun=fun,
|
|
+ name=name,
|
|
+ activate_transaction=activate_transaction,
|
|
+ concurrent=True,
|
|
+ **kwargs
|
|
)
|
|
diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py
|
|
index c0820e5df0..5ff3c964be 100644
|
|
--- a/salt/utils/parsers.py
|
|
+++ b/salt/utils/parsers.py
|
|
@@ -3108,6 +3108,12 @@ class SaltCallOptionParser(
|
|
action="store_true",
|
|
help="Force a refresh of the grains cache.",
|
|
)
|
|
+ self.add_option(
|
|
+ "--no-return-event",
|
|
+ default=False,
|
|
+ action="store_true",
|
|
+ help=("Do not produce the return event back to master."),
|
|
+ )
|
|
self.add_option(
|
|
"-t",
|
|
"--timeout",
|
|
diff --git a/tests/pytests/unit/modules/state/test_state.py b/tests/pytests/unit/modules/state/test_state.py
|
|
index 3fa663edeb..02fd2dd307 100644
|
|
--- a/tests/pytests/unit/modules/state/test_state.py
|
|
+++ b/tests/pytests/unit/modules/state/test_state.py
|
|
@@ -777,7 +777,7 @@ def test_highstate():
|
|
}
|
|
|
|
mock = MagicMock(side_effect=["A", None, None])
|
|
- with patch.object(state, "_check_queue", mock):
|
|
+ with patch.object(state, "running", mock):
|
|
assert state.highstate("whitelist=sls1.sls") == "A"
|
|
|
|
with patch.dict(state.__opts__, {"test": "A"}):
|
|
diff --git a/tests/pytests/unit/modules/test_transactional_update.py b/tests/pytests/unit/modules/test_transactional_update.py
|
|
index 032ca0c9e8..40dab0e2f6 100644
|
|
--- a/tests/pytests/unit/modules/test_transactional_update.py
|
|
+++ b/tests/pytests/unit/modules/test_transactional_update.py
|
|
@@ -1,5 +1,3 @@
|
|
-import sys
|
|
-
|
|
import pytest
|
|
import salt.loader.context
|
|
import salt.modules.state as statemod
|
|
@@ -353,114 +351,23 @@ def test_call_fails_input_validation():
|
|
tu.call("")
|
|
|
|
|
|
-@patch("tempfile.mkdtemp", MagicMock(return_value="/var/cache/salt/minion/tmp01"))
|
|
-def test_call_fails_untar():
|
|
- """Test transactional_update.call when tar fails"""
|
|
- utils_mock = {
|
|
- "thin.gen_thin": MagicMock(return_value="/salt-thin.tgz"),
|
|
- "files.rm_rf": MagicMock(),
|
|
- }
|
|
- opts_mock = {"cachedir": "/var/cache/salt/minion"}
|
|
- salt_mock = {
|
|
- "cmd.run": MagicMock(return_value="Error"),
|
|
- "config.option": MagicMock(),
|
|
- }
|
|
- with patch.dict(tu.__utils__, utils_mock), patch.dict(
|
|
- tu.__opts__, opts_mock
|
|
- ), patch.dict(tu.__salt__, salt_mock):
|
|
- assert tu.call("/chroot", "test.ping") == {
|
|
- "result": False,
|
|
- "comment": "Error",
|
|
- }
|
|
-
|
|
- utils_mock["thin.gen_thin"].assert_called_once()
|
|
- salt_mock["config.option"].assert_called()
|
|
- salt_mock["cmd.run"].assert_called_once()
|
|
- utils_mock["files.rm_rf"].assert_called_once()
|
|
-
|
|
-
|
|
-@patch("tempfile.mkdtemp", MagicMock(return_value="/var/cache/salt/minion/tmp01"))
|
|
-def test_call_fails_salt_thin():
|
|
- """Test transactional_update.chroot when fails salt_thin"""
|
|
- utils_mock = {
|
|
- "thin.gen_thin": MagicMock(return_value="/salt-thin.tgz"),
|
|
- "files.rm_rf": MagicMock(),
|
|
- "json.find_json": MagicMock(side_effect=ValueError()),
|
|
- }
|
|
- opts_mock = {"cachedir": "/var/cache/salt/minion"}
|
|
- salt_mock = {
|
|
- "cmd.run": MagicMock(return_value=""),
|
|
- "config.option": MagicMock(),
|
|
- "cmd.run_all": MagicMock(return_value={"retcode": 1, "stderr": "Error"}),
|
|
- }
|
|
- with patch.dict(tu.__utils__, utils_mock), patch.dict(
|
|
- tu.__opts__, opts_mock
|
|
- ), patch.dict(tu.__salt__, salt_mock):
|
|
- assert tu.call("test.ping") == {
|
|
- "result": False,
|
|
- "retcode": 1,
|
|
- "comment": "Error",
|
|
- }
|
|
-
|
|
- utils_mock["thin.gen_thin"].assert_called_once()
|
|
- salt_mock["config.option"].assert_called()
|
|
- salt_mock["cmd.run"].assert_called_once()
|
|
- salt_mock["cmd.run_all"].assert_called_with(
|
|
- [
|
|
- "transactional-update",
|
|
- "--non-interactive",
|
|
- "--drop-if-no-change",
|
|
- "--no-selfupdate",
|
|
- "--continue",
|
|
- "--quiet",
|
|
- "run",
|
|
- "python{}".format(sys.version_info[0]),
|
|
- "/var/cache/salt/minion/tmp01/salt-call",
|
|
- "--metadata",
|
|
- "--local",
|
|
- "--log-file",
|
|
- "/var/cache/salt/minion/tmp01/log",
|
|
- "--cachedir",
|
|
- "/var/cache/salt/minion/tmp01/cache",
|
|
- "--out",
|
|
- "json",
|
|
- "-l",
|
|
- "quiet",
|
|
- "--",
|
|
- "test.ping",
|
|
- ]
|
|
- )
|
|
- utils_mock["files.rm_rf"].assert_called_once()
|
|
-
|
|
-
|
|
-@patch("tempfile.mkdtemp", MagicMock(return_value="/var/cache/salt/minion/tmp01"))
|
|
def test_call_fails_function():
|
|
"""Test transactional_update.chroot when fails the function"""
|
|
utils_mock = {
|
|
- "thin.gen_thin": MagicMock(return_value="/salt-thin.tgz"),
|
|
- "files.rm_rf": MagicMock(),
|
|
"json.find_json": MagicMock(side_effect=ValueError()),
|
|
}
|
|
- opts_mock = {"cachedir": "/var/cache/salt/minion"}
|
|
salt_mock = {
|
|
- "cmd.run": MagicMock(return_value=""),
|
|
- "config.option": MagicMock(),
|
|
"cmd.run_all": MagicMock(
|
|
return_value={"retcode": 0, "stdout": "Not found", "stderr": ""}
|
|
),
|
|
}
|
|
- with patch.dict(tu.__utils__, utils_mock), patch.dict(
|
|
- tu.__opts__, opts_mock
|
|
- ), patch.dict(tu.__salt__, salt_mock):
|
|
+ with patch.dict(tu.__utils__, utils_mock), patch.dict(tu.__salt__, salt_mock):
|
|
assert tu.call("test.ping") == {
|
|
"result": False,
|
|
"retcode": 1,
|
|
"comment": "Not found",
|
|
}
|
|
|
|
- utils_mock["thin.gen_thin"].assert_called_once()
|
|
- salt_mock["config.option"].assert_called()
|
|
- salt_mock["cmd.run"].assert_called_once()
|
|
salt_mock["cmd.run_all"].assert_called_with(
|
|
[
|
|
"transactional-update",
|
|
@@ -470,47 +377,29 @@ def test_call_fails_function():
|
|
"--continue",
|
|
"--quiet",
|
|
"run",
|
|
- "python{}".format(sys.version_info[0]),
|
|
- "/var/cache/salt/minion/tmp01/salt-call",
|
|
- "--metadata",
|
|
- "--local",
|
|
- "--log-file",
|
|
- "/var/cache/salt/minion/tmp01/log",
|
|
- "--cachedir",
|
|
- "/var/cache/salt/minion/tmp01/cache",
|
|
+ "salt-call",
|
|
"--out",
|
|
"json",
|
|
"-l",
|
|
"quiet",
|
|
+ "--no-return-event",
|
|
"--",
|
|
"test.ping",
|
|
]
|
|
)
|
|
- utils_mock["files.rm_rf"].assert_called_once()
|
|
|
|
|
|
-@patch("tempfile.mkdtemp", MagicMock(return_value="/var/cache/salt/minion/tmp01"))
|
|
def test_call_success_no_reboot():
|
|
"""Test transactional_update.chroot when succeed"""
|
|
utils_mock = {
|
|
- "thin.gen_thin": MagicMock(return_value="/salt-thin.tgz"),
|
|
- "files.rm_rf": MagicMock(),
|
|
"json.find_json": MagicMock(return_value={"return": "result"}),
|
|
}
|
|
- opts_mock = {"cachedir": "/var/cache/salt/minion"}
|
|
salt_mock = {
|
|
- "cmd.run": MagicMock(return_value=""),
|
|
- "config.option": MagicMock(),
|
|
"cmd.run_all": MagicMock(return_value={"retcode": 0, "stdout": ""}),
|
|
}
|
|
- with patch.dict(tu.__utils__, utils_mock), patch.dict(
|
|
- tu.__opts__, opts_mock
|
|
- ), patch.dict(tu.__salt__, salt_mock):
|
|
+ with patch.dict(tu.__utils__, utils_mock), patch.dict(tu.__salt__, salt_mock):
|
|
assert tu.call("test.ping") == "result"
|
|
|
|
- utils_mock["thin.gen_thin"].assert_called_once()
|
|
- salt_mock["config.option"].assert_called()
|
|
- salt_mock["cmd.run"].assert_called_once()
|
|
salt_mock["cmd.run_all"].assert_called_with(
|
|
[
|
|
"transactional-update",
|
|
@@ -520,43 +409,30 @@ def test_call_success_no_reboot():
|
|
"--continue",
|
|
"--quiet",
|
|
"run",
|
|
- "python{}".format(sys.version_info[0]),
|
|
- "/var/cache/salt/minion/tmp01/salt-call",
|
|
- "--metadata",
|
|
- "--local",
|
|
- "--log-file",
|
|
- "/var/cache/salt/minion/tmp01/log",
|
|
- "--cachedir",
|
|
- "/var/cache/salt/minion/tmp01/cache",
|
|
+ "salt-call",
|
|
"--out",
|
|
"json",
|
|
"-l",
|
|
"quiet",
|
|
+ "--no-return-event",
|
|
"--",
|
|
"test.ping",
|
|
]
|
|
)
|
|
- utils_mock["files.rm_rf"].assert_called_once()
|
|
|
|
|
|
-@patch("tempfile.mkdtemp", MagicMock(return_value="/var/cache/salt/minion/tmp01"))
|
|
def test_call_success_reboot():
|
|
"""Test transactional_update.chroot when succeed and reboot"""
|
|
pending_transaction_mock = MagicMock(return_value=True)
|
|
reboot_mock = MagicMock()
|
|
utils_mock = {
|
|
- "thin.gen_thin": MagicMock(return_value="/salt-thin.tgz"),
|
|
- "files.rm_rf": MagicMock(),
|
|
"json.find_json": MagicMock(return_value={"return": "result"}),
|
|
}
|
|
- opts_mock = {"cachedir": "/var/cache/salt/minion"}
|
|
salt_mock = {
|
|
- "cmd.run": MagicMock(return_value=""),
|
|
- "config.option": MagicMock(),
|
|
"cmd.run_all": MagicMock(return_value={"retcode": 0, "stdout": ""}),
|
|
}
|
|
with patch.dict(tu.__utils__, utils_mock), patch.dict(
|
|
- tu.__opts__, opts_mock
|
|
+ tu.__salt__, salt_mock
|
|
), patch.dict(tu.__salt__, salt_mock), patch(
|
|
"salt.modules.transactional_update.pending_transaction",
|
|
pending_transaction_mock,
|
|
@@ -567,9 +443,6 @@ def test_call_success_reboot():
|
|
tu.call("transactional_update.dup", activate_transaction=True) == "result"
|
|
)
|
|
|
|
- utils_mock["thin.gen_thin"].assert_called_once()
|
|
- salt_mock["config.option"].assert_called()
|
|
- salt_mock["cmd.run"].assert_called_once()
|
|
salt_mock["cmd.run_all"].assert_called_with(
|
|
[
|
|
"transactional-update",
|
|
@@ -579,49 +452,31 @@ def test_call_success_reboot():
|
|
"--continue",
|
|
"--quiet",
|
|
"run",
|
|
- "python{}".format(sys.version_info[0]),
|
|
- "/var/cache/salt/minion/tmp01/salt-call",
|
|
- "--metadata",
|
|
- "--local",
|
|
- "--log-file",
|
|
- "/var/cache/salt/minion/tmp01/log",
|
|
- "--cachedir",
|
|
- "/var/cache/salt/minion/tmp01/cache",
|
|
+ "salt-call",
|
|
"--out",
|
|
"json",
|
|
"-l",
|
|
"quiet",
|
|
+ "--no-return-event",
|
|
"--",
|
|
"transactional_update.dup",
|
|
]
|
|
)
|
|
- utils_mock["files.rm_rf"].assert_called_once()
|
|
pending_transaction_mock.assert_called_once()
|
|
reboot_mock.assert_called_once()
|
|
|
|
|
|
-@patch("tempfile.mkdtemp", MagicMock(return_value="/var/cache/salt/minion/tmp01"))
|
|
def test_call_success_parameters():
|
|
"""Test transactional_update.chroot when succeed with parameters"""
|
|
utils_mock = {
|
|
- "thin.gen_thin": MagicMock(return_value="/salt-thin.tgz"),
|
|
- "files.rm_rf": MagicMock(),
|
|
"json.find_json": MagicMock(return_value={"return": "result"}),
|
|
}
|
|
- opts_mock = {"cachedir": "/var/cache/salt/minion"}
|
|
salt_mock = {
|
|
- "cmd.run": MagicMock(return_value=""),
|
|
- "config.option": MagicMock(),
|
|
"cmd.run_all": MagicMock(return_value={"retcode": 0, "stdout": ""}),
|
|
}
|
|
- with patch.dict(tu.__utils__, utils_mock), patch.dict(
|
|
- tu.__opts__, opts_mock
|
|
- ), patch.dict(tu.__salt__, salt_mock):
|
|
+ with patch.dict(tu.__utils__, utils_mock), patch.dict(tu.__salt__, salt_mock):
|
|
assert tu.call("module.function", key="value") == "result"
|
|
|
|
- utils_mock["thin.gen_thin"].assert_called_once()
|
|
- salt_mock["config.option"].assert_called()
|
|
- salt_mock["cmd.run"].assert_called_once()
|
|
salt_mock["cmd.run_all"].assert_called_with(
|
|
[
|
|
"transactional-update",
|
|
@@ -631,75 +486,32 @@ def test_call_success_parameters():
|
|
"--continue",
|
|
"--quiet",
|
|
"run",
|
|
- "python{}".format(sys.version_info[0]),
|
|
- "/var/cache/salt/minion/tmp01/salt-call",
|
|
- "--metadata",
|
|
- "--local",
|
|
- "--log-file",
|
|
- "/var/cache/salt/minion/tmp01/log",
|
|
- "--cachedir",
|
|
- "/var/cache/salt/minion/tmp01/cache",
|
|
+ "salt-call",
|
|
"--out",
|
|
"json",
|
|
"-l",
|
|
"quiet",
|
|
+ "--no-return-event",
|
|
"--",
|
|
"module.function",
|
|
"key=value",
|
|
]
|
|
)
|
|
- utils_mock["files.rm_rf"].assert_called_once()
|
|
|
|
|
|
def test_sls():
|
|
"""Test transactional_update.sls"""
|
|
- transactional_update_highstate_mock = MagicMock()
|
|
- transactional_update_highstate_mock.return_value = (
|
|
- transactional_update_highstate_mock
|
|
- )
|
|
- transactional_update_highstate_mock.render_highstate.return_value = (None, [])
|
|
- transactional_update_highstate_mock.state.reconcile_extend.return_value = (None, [])
|
|
- transactional_update_highstate_mock.state.requisite_in.return_value = (None, [])
|
|
- transactional_update_highstate_mock.state.verify_high.return_value = []
|
|
-
|
|
- _create_and_execute_salt_state_mock = MagicMock(return_value="result")
|
|
- opts_mock = {
|
|
- "hash_type": "md5",
|
|
- }
|
|
salt_mock = {
|
|
"saltutil.is_running": MagicMock(return_value=[]),
|
|
}
|
|
- get_sls_opts_mock = MagicMock(return_value=opts_mock)
|
|
- with patch.dict(tu.__opts__, opts_mock), patch.dict(
|
|
- statemod.__salt__, salt_mock
|
|
- ), patch("salt.utils.state.get_sls_opts", get_sls_opts_mock), patch(
|
|
- "salt.fileclient.get_file_client", MagicMock()
|
|
- ), patch(
|
|
- "salt.modules.transactional_update.TransactionalUpdateHighstate",
|
|
- transactional_update_highstate_mock,
|
|
- ), patch(
|
|
- "salt.modules.transactional_update._create_and_execute_salt_state",
|
|
- _create_and_execute_salt_state_mock,
|
|
+ with patch.dict(statemod.__salt__, salt_mock), patch(
|
|
+ "salt.modules.transactional_update.call", MagicMock(return_value="result")
|
|
):
|
|
assert tu.sls("module") == "result"
|
|
- _create_and_execute_salt_state_mock.assert_called_once()
|
|
|
|
|
|
def test_sls_queue_true():
|
|
"""Test transactional_update.sls"""
|
|
- transactional_update_highstate_mock = MagicMock()
|
|
- transactional_update_highstate_mock.return_value = (
|
|
- transactional_update_highstate_mock
|
|
- )
|
|
- transactional_update_highstate_mock.render_highstate.return_value = (None, [])
|
|
- transactional_update_highstate_mock.state.reconcile_extend.return_value = (None, [])
|
|
- transactional_update_highstate_mock.state.requisite_in.return_value = (None, [])
|
|
- transactional_update_highstate_mock.state.verify_high.return_value = []
|
|
-
|
|
- _create_and_execute_salt_state_mock = MagicMock(return_value="result")
|
|
- opts_mock = {
|
|
- "hash_type": "md5",
|
|
- }
|
|
salt_mock = {
|
|
"saltutil.is_running": MagicMock(
|
|
side_effect=[
|
|
@@ -714,37 +526,14 @@ def test_sls_queue_true():
|
|
]
|
|
),
|
|
}
|
|
- get_sls_opts_mock = MagicMock(return_value=opts_mock)
|
|
- with patch.dict(tu.__opts__, opts_mock), patch.dict(
|
|
- statemod.__salt__, salt_mock
|
|
- ), patch("salt.utils.state.get_sls_opts", get_sls_opts_mock), patch(
|
|
- "salt.fileclient.get_file_client", MagicMock()
|
|
- ), patch(
|
|
- "salt.modules.transactional_update.TransactionalUpdateHighstate",
|
|
- transactional_update_highstate_mock,
|
|
- ), patch(
|
|
- "salt.modules.transactional_update._create_and_execute_salt_state",
|
|
- _create_and_execute_salt_state_mock,
|
|
+ with patch.dict(statemod.__salt__, salt_mock), patch(
|
|
+ "salt.modules.transactional_update.call", MagicMock(return_value="result")
|
|
):
|
|
assert tu.sls("module", queue=True) == "result"
|
|
- _create_and_execute_salt_state_mock.assert_called_once()
|
|
|
|
|
|
def test_sls_queue_false_failing():
|
|
"""Test transactional_update.sls"""
|
|
- transactional_update_highstate_mock = MagicMock()
|
|
- transactional_update_highstate_mock.return_value = (
|
|
- transactional_update_highstate_mock
|
|
- )
|
|
- transactional_update_highstate_mock.render_highstate.return_value = (None, [])
|
|
- transactional_update_highstate_mock.state.reconcile_extend.return_value = (None, [])
|
|
- transactional_update_highstate_mock.state.requisite_in.return_value = (None, [])
|
|
- transactional_update_highstate_mock.state.verify_high.return_value = []
|
|
-
|
|
- _create_and_execute_salt_state_mock = MagicMock(return_value="result")
|
|
- opts_mock = {
|
|
- "hash_type": "md5",
|
|
- }
|
|
salt_mock = {
|
|
"saltutil.is_running": MagicMock(
|
|
side_effect=[
|
|
@@ -759,65 +548,27 @@ def test_sls_queue_false_failing():
|
|
]
|
|
),
|
|
}
|
|
- get_sls_opts_mock = MagicMock(return_value=opts_mock)
|
|
- with patch.dict(tu.__opts__, opts_mock), patch.dict(
|
|
- statemod.__salt__, salt_mock
|
|
- ), patch("salt.utils.state.get_sls_opts", get_sls_opts_mock), patch(
|
|
- "salt.fileclient.get_file_client", MagicMock()
|
|
- ), patch(
|
|
- "salt.modules.transactional_update.TransactionalUpdateHighstate",
|
|
- transactional_update_highstate_mock,
|
|
- ), patch(
|
|
- "salt.modules.transactional_update._create_and_execute_salt_state",
|
|
- _create_and_execute_salt_state_mock,
|
|
+ with patch.dict(statemod.__salt__, salt_mock), patch(
|
|
+ "salt.modules.transactional_update.call", MagicMock(return_value="result")
|
|
):
|
|
assert tu.sls("module", queue=False) == [
|
|
'The function "state.running" is running as PID 4126 and was started at 2015, Mar 25 12:34:07.204096 with jid 20150325123407204096'
|
|
]
|
|
- _create_and_execute_salt_state_mock.assert_not_called()
|
|
|
|
|
|
def test_highstate():
|
|
"""Test transactional_update.highstage"""
|
|
- transactional_update_highstate_mock = MagicMock()
|
|
- transactional_update_highstate_mock.return_value = (
|
|
- transactional_update_highstate_mock
|
|
- )
|
|
-
|
|
- _create_and_execute_salt_state_mock = MagicMock(return_value="result")
|
|
- opts_mock = {
|
|
- "hash_type": "md5",
|
|
- }
|
|
salt_mock = {
|
|
"saltutil.is_running": MagicMock(return_value=[]),
|
|
}
|
|
- get_sls_opts_mock = MagicMock(return_value=opts_mock)
|
|
- with patch.dict(tu.__opts__, opts_mock), patch.dict(
|
|
- statemod.__salt__, salt_mock
|
|
- ), patch("salt.utils.state.get_sls_opts", get_sls_opts_mock), patch(
|
|
- "salt.fileclient.get_file_client", MagicMock()
|
|
- ), patch(
|
|
- "salt.modules.transactional_update.TransactionalUpdateHighstate",
|
|
- transactional_update_highstate_mock,
|
|
- ), patch(
|
|
- "salt.modules.transactional_update._create_and_execute_salt_state",
|
|
- _create_and_execute_salt_state_mock,
|
|
+ with patch.dict(statemod.__salt__, salt_mock), patch(
|
|
+ "salt.modules.transactional_update.call", MagicMock(return_value="result")
|
|
):
|
|
assert tu.highstate() == "result"
|
|
- _create_and_execute_salt_state_mock.assert_called_once()
|
|
|
|
|
|
def test_highstate_queue_true():
|
|
"""Test transactional_update.highstage"""
|
|
- transactional_update_highstate_mock = MagicMock()
|
|
- transactional_update_highstate_mock.return_value = (
|
|
- transactional_update_highstate_mock
|
|
- )
|
|
-
|
|
- _create_and_execute_salt_state_mock = MagicMock(return_value="result")
|
|
- opts_mock = {
|
|
- "hash_type": "md5",
|
|
- }
|
|
salt_mock = {
|
|
"saltutil.is_running": MagicMock(
|
|
side_effect=[
|
|
@@ -832,33 +583,14 @@ def test_highstate_queue_true():
|
|
]
|
|
),
|
|
}
|
|
- get_sls_opts_mock = MagicMock(return_value=opts_mock)
|
|
- with patch.dict(tu.__opts__, opts_mock), patch.dict(
|
|
- statemod.__salt__, salt_mock
|
|
- ), patch("salt.utils.state.get_sls_opts", get_sls_opts_mock), patch(
|
|
- "salt.fileclient.get_file_client", MagicMock()
|
|
- ), patch(
|
|
- "salt.modules.transactional_update.TransactionalUpdateHighstate",
|
|
- transactional_update_highstate_mock,
|
|
- ), patch(
|
|
- "salt.modules.transactional_update._create_and_execute_salt_state",
|
|
- _create_and_execute_salt_state_mock,
|
|
+ with patch.dict(statemod.__salt__, salt_mock), patch(
|
|
+ "salt.modules.transactional_update.call", MagicMock(return_value="result")
|
|
):
|
|
assert tu.highstate(queue=True) == "result"
|
|
- _create_and_execute_salt_state_mock.assert_called_once()
|
|
|
|
|
|
def test_highstate_queue_false_failing():
|
|
"""Test transactional_update.highstage"""
|
|
- transactional_update_highstate_mock = MagicMock()
|
|
- transactional_update_highstate_mock.return_value = (
|
|
- transactional_update_highstate_mock
|
|
- )
|
|
-
|
|
- _create_and_execute_salt_state_mock = MagicMock(return_value="result")
|
|
- opts_mock = {
|
|
- "hash_type": "md5",
|
|
- }
|
|
salt_mock = {
|
|
"saltutil.is_running": MagicMock(
|
|
side_effect=[
|
|
@@ -873,62 +605,27 @@ def test_highstate_queue_false_failing():
|
|
]
|
|
),
|
|
}
|
|
- get_sls_opts_mock = MagicMock(return_value=opts_mock)
|
|
- with patch.dict(tu.__opts__, opts_mock), patch.dict(
|
|
- statemod.__salt__, salt_mock
|
|
- ), patch("salt.utils.state.get_sls_opts", get_sls_opts_mock), patch(
|
|
- "salt.fileclient.get_file_client", MagicMock()
|
|
- ), patch(
|
|
- "salt.modules.transactional_update.TransactionalUpdateHighstate",
|
|
- transactional_update_highstate_mock,
|
|
- ), patch(
|
|
- "salt.modules.transactional_update._create_and_execute_salt_state",
|
|
- _create_and_execute_salt_state_mock,
|
|
+ with patch.dict(statemod.__salt__, salt_mock), patch(
|
|
+ "salt.modules.transactional_update.call", MagicMock(return_value="result")
|
|
):
|
|
assert tu.highstate(queue=False) == [
|
|
'The function "state.running" is running as PID 4126 and was started at 2015, Mar 25 12:34:07.204096 with jid 20150325123407204096'
|
|
]
|
|
- _create_and_execute_salt_state_mock.assert_not_called()
|
|
|
|
|
|
def test_single():
|
|
"""Test transactional_update.single"""
|
|
- ssh_state_mock = MagicMock()
|
|
- ssh_state_mock.return_value = ssh_state_mock
|
|
- ssh_state_mock.verify_data.return_value = None
|
|
-
|
|
- _create_and_execute_salt_state_mock = MagicMock(return_value="result")
|
|
- opts_mock = {
|
|
- "hash_type": "md5",
|
|
- }
|
|
salt_mock = {
|
|
"saltutil.is_running": MagicMock(return_value=[]),
|
|
}
|
|
- get_sls_opts_mock = MagicMock(return_value=opts_mock)
|
|
- with patch.dict(tu.__opts__, opts_mock), patch.dict(
|
|
- statemod.__salt__, salt_mock
|
|
- ), patch("salt.utils.state.get_sls_opts", get_sls_opts_mock), patch(
|
|
- "salt.fileclient.get_file_client", MagicMock()
|
|
- ), patch(
|
|
- "salt.client.ssh.state.SSHState", ssh_state_mock
|
|
- ), patch(
|
|
- "salt.modules.transactional_update._create_and_execute_salt_state",
|
|
- _create_and_execute_salt_state_mock,
|
|
+ with patch.dict(statemod.__salt__, salt_mock), patch(
|
|
+ "salt.modules.transactional_update.call", MagicMock(return_value="result")
|
|
):
|
|
assert tu.single("pkg.installed", name="emacs") == "result"
|
|
- _create_and_execute_salt_state_mock.assert_called_once()
|
|
|
|
|
|
def test_single_queue_false_failing():
|
|
"""Test transactional_update.single"""
|
|
- ssh_state_mock = MagicMock()
|
|
- ssh_state_mock.return_value = ssh_state_mock
|
|
- ssh_state_mock.verify_data.return_value = None
|
|
-
|
|
- _create_and_execute_salt_state_mock = MagicMock(return_value="result")
|
|
- opts_mock = {
|
|
- "hash_type": "md5",
|
|
- }
|
|
salt_mock = {
|
|
"saltutil.is_running": MagicMock(
|
|
side_effect=[
|
|
@@ -943,33 +640,16 @@ def test_single_queue_false_failing():
|
|
]
|
|
),
|
|
}
|
|
- get_sls_opts_mock = MagicMock(return_value=opts_mock)
|
|
- with patch.dict(tu.__opts__, opts_mock), patch.dict(
|
|
- statemod.__salt__, salt_mock
|
|
- ), patch("salt.utils.state.get_sls_opts", get_sls_opts_mock), patch(
|
|
- "salt.fileclient.get_file_client", MagicMock()
|
|
- ), patch(
|
|
- "salt.client.ssh.state.SSHState", ssh_state_mock
|
|
- ), patch(
|
|
- "salt.modules.transactional_update._create_and_execute_salt_state",
|
|
- _create_and_execute_salt_state_mock,
|
|
+ with patch.dict(statemod.__salt__, salt_mock), patch(
|
|
+ "salt.modules.transactional_update.call", MagicMock(return_value="result")
|
|
):
|
|
assert tu.single("pkg.installed", name="emacs", queue=False) == [
|
|
'The function "state.running" is running as PID 4126 and was started at 2015, Mar 25 12:34:07.204096 with jid 20150325123407204096'
|
|
]
|
|
- _create_and_execute_salt_state_mock.assert_not_called()
|
|
|
|
|
|
def test_single_queue_true():
|
|
"""Test transactional_update.single"""
|
|
- ssh_state_mock = MagicMock()
|
|
- ssh_state_mock.return_value = ssh_state_mock
|
|
- ssh_state_mock.verify_data.return_value = None
|
|
-
|
|
- _create_and_execute_salt_state_mock = MagicMock(return_value="result")
|
|
- opts_mock = {
|
|
- "hash_type": "md5",
|
|
- }
|
|
salt_mock = {
|
|
"saltutil.is_running": MagicMock(
|
|
side_effect=[
|
|
@@ -984,16 +664,7 @@ def test_single_queue_true():
|
|
]
|
|
),
|
|
}
|
|
- get_sls_opts_mock = MagicMock(return_value=opts_mock)
|
|
- with patch.dict(tu.__opts__, opts_mock), patch.dict(
|
|
- statemod.__salt__, salt_mock
|
|
- ), patch("salt.utils.state.get_sls_opts", get_sls_opts_mock), patch(
|
|
- "salt.fileclient.get_file_client", MagicMock()
|
|
- ), patch(
|
|
- "salt.client.ssh.state.SSHState", ssh_state_mock
|
|
- ), patch(
|
|
- "salt.modules.transactional_update._create_and_execute_salt_state",
|
|
- _create_and_execute_salt_state_mock,
|
|
+ with patch.dict(statemod.__salt__, salt_mock), patch(
|
|
+ "salt.modules.transactional_update.call", MagicMock(return_value="result")
|
|
):
|
|
assert tu.single("pkg.installed", name="emacs", queue=True) == "result"
|
|
- _create_and_execute_salt_state_mock.assert_called_once()
|
|
--
|
|
2.34.1
|
|
|
|
|