mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge 3006.x into master
This commit is contained in:
commit
6d17f6e8ca
9 changed files with 638 additions and 5 deletions
1
changelog/65027.fixed.md
Normal file
1
changelog/65027.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Ensure sync from _grains occurs before attempting pillar compilation in case custom grain used in pillar file
|
|
@ -41,12 +41,16 @@ log = logging.getLogger(__name__)
|
|||
MAX_FILENAME_LENGTH = 255
|
||||
|
||||
|
||||
def get_file_client(opts, pillar=False):
|
||||
def get_file_client(opts, pillar=False, force_local=False):
|
||||
"""
|
||||
Read in the ``file_client`` option and return the correct type of file
|
||||
server
|
||||
"""
|
||||
client = opts.get("file_client", "remote")
|
||||
if force_local:
|
||||
client = "local"
|
||||
else:
|
||||
client = opts.get("file_client", "remote")
|
||||
|
||||
if pillar and client == "local":
|
||||
client = "pillar"
|
||||
return {"remote": RemoteClient, "local": FSClient, "pillar": PillarClient}.get(
|
||||
|
|
|
@ -46,6 +46,7 @@ import salt.utils.dictdiffer
|
|||
import salt.utils.dictupdate
|
||||
import salt.utils.error
|
||||
import salt.utils.event
|
||||
import salt.utils.extmods
|
||||
import salt.utils.files
|
||||
import salt.utils.jid
|
||||
import salt.utils.minion
|
||||
|
@ -114,6 +115,29 @@ log = logging.getLogger(__name__)
|
|||
# 6. Handle publications
|
||||
|
||||
|
||||
def _sync_grains(opts):
|
||||
# need sync of custom grains as may be used in pillar compilation
|
||||
# if coming up initially and remote client, the first sync _grains
|
||||
# doesn't have opts["master_uri"] set yet during the sync, so need
|
||||
# to force local, otherwise will throw an exception when attempting
|
||||
# to retrieve opts["master_uri"] when retrieving key for remote communication
|
||||
# in addition opts sometimes does not contain extmod_whitelist and extmod_blacklist
|
||||
# hence set those to defaults, empty dict, if not part of opts, as ref'd in
|
||||
# salt.utils.extmod sync function
|
||||
if opts.get("extmod_whitelist", None) is None:
|
||||
opts["extmod_whitelist"] = {}
|
||||
|
||||
if opts.get("extmod_blacklist", None) is None:
|
||||
opts["extmod_blacklist"] = {}
|
||||
|
||||
if opts.get("file_client", "remote") == "remote" and not opts.get(
|
||||
"master_uri", None
|
||||
):
|
||||
salt.utils.extmods.sync(opts, "grains", force_local=True)
|
||||
else:
|
||||
salt.utils.extmods.sync(opts, "grains")
|
||||
|
||||
|
||||
def resolve_dns(opts, fallback=True):
|
||||
"""
|
||||
Resolves the master_ip and master_uri options
|
||||
|
@ -921,6 +945,7 @@ class SMinion(MinionBase):
|
|||
# Late setup of the opts grains, so we can log from the grains module
|
||||
import salt.loader
|
||||
|
||||
_sync_grains(opts)
|
||||
opts["grains"] = salt.loader.grains(opts)
|
||||
super().__init__(opts)
|
||||
|
||||
|
@ -3935,6 +3960,8 @@ class SProxyMinion(SMinion):
|
|||
|
||||
salt '*' sys.reload_modules
|
||||
"""
|
||||
# need sync of custom grains as may be used in pillar compilation
|
||||
salt.utils.extmods.sync(self.opts, "grains")
|
||||
self.opts["grains"] = salt.loader.grains(self.opts)
|
||||
self.opts["pillar"] = salt.pillar.get_pillar(
|
||||
self.opts,
|
||||
|
|
|
@ -32,7 +32,14 @@ def _listdir_recursively(rootdir):
|
|||
return file_list
|
||||
|
||||
|
||||
def sync(opts, form, saltenv=None, extmod_whitelist=None, extmod_blacklist=None):
|
||||
def sync(
|
||||
opts,
|
||||
form,
|
||||
saltenv=None,
|
||||
extmod_whitelist=None,
|
||||
extmod_blacklist=None,
|
||||
force_local=False,
|
||||
):
|
||||
"""
|
||||
Sync custom modules into the extension_modules directory
|
||||
"""
|
||||
|
@ -75,7 +82,9 @@ def sync(opts, form, saltenv=None, extmod_whitelist=None, extmod_blacklist=None)
|
|||
"Cannot create cache module directory %s. Check permissions.",
|
||||
mod_dir,
|
||||
)
|
||||
with salt.fileclient.get_file_client(opts) as fileclient:
|
||||
with salt.fileclient.get_file_client(
|
||||
opts, pillar=False, force_local=force_local
|
||||
) as fileclient:
|
||||
for sub_env in saltenv:
|
||||
log.info("Syncing %s for environment '%s'", form, sub_env)
|
||||
cache = []
|
||||
|
|
|
@ -429,3 +429,74 @@ def test_local_salt_call_no_function_no_retcode(salt_call_cli):
|
|||
assert "test" in ret.data
|
||||
assert ret.data["test"] == "'test' is not available."
|
||||
assert "test.echo" in ret.data
|
||||
|
||||
|
||||
def test_state_highstate_custom_grains(salt_master, salt_minion_factory):
|
||||
"""
|
||||
This test ensure that custom grains in salt://_grains are loaded before pillar compilation
|
||||
to ensure that any use of custom grains in pillar files are available, this implies that
|
||||
a sync of grains occurs before loading the regular /etc/salt/grains or configuration file
|
||||
grains, as well as the usual grains.
|
||||
|
||||
Note: cannot use salt_minion and salt_call_cli, since these will be loaded before
|
||||
the pillar and custom_grains files are written, hence using salt_minion_factory.
|
||||
"""
|
||||
pillar_top_sls = """
|
||||
base:
|
||||
'*':
|
||||
- defaults
|
||||
"""
|
||||
|
||||
pillar_defaults_sls = """
|
||||
mypillar: "{{ grains['custom_grain'] }}"
|
||||
"""
|
||||
|
||||
salt_top_sls = """
|
||||
base:
|
||||
'*':
|
||||
- test
|
||||
"""
|
||||
|
||||
salt_test_sls = """
|
||||
"donothing":
|
||||
test.nop: []
|
||||
"""
|
||||
|
||||
salt_custom_grains_py = """
|
||||
def main():
|
||||
return {'custom_grain': 'test_value'}
|
||||
"""
|
||||
assert salt_master.is_running()
|
||||
with salt_minion_factory.started():
|
||||
salt_minion = salt_minion_factory
|
||||
salt_call_cli = salt_minion_factory.salt_call_cli()
|
||||
with salt_minion.pillar_tree.base.temp_file(
|
||||
"top.sls", pillar_top_sls
|
||||
), salt_minion.pillar_tree.base.temp_file(
|
||||
"defaults.sls", pillar_defaults_sls
|
||||
), salt_minion.state_tree.base.temp_file(
|
||||
"top.sls", salt_top_sls
|
||||
), salt_minion.state_tree.base.temp_file(
|
||||
"test.sls", salt_test_sls
|
||||
), salt_minion.state_tree.base.temp_file(
|
||||
"_grains/custom_grain.py", salt_custom_grains_py
|
||||
):
|
||||
ret = salt_call_cli.run("--local", "state.highstate")
|
||||
assert ret.returncode == 0
|
||||
ret = salt_call_cli.run("--local", "pillar.items")
|
||||
assert ret.returncode == 0
|
||||
assert ret.data
|
||||
pillar_items = ret.data
|
||||
assert "mypillar" in pillar_items
|
||||
assert pillar_items["mypillar"] == "test_value"
|
||||
|
||||
|
||||
def test_salt_call_versions(salt_call_cli, caplog):
|
||||
"""
|
||||
Call test.versions without '--local' to test grains
|
||||
are sync'd without any missing keys in opts
|
||||
"""
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
ret = salt_call_cli.run("test.versions")
|
||||
assert ret.returncode == 0
|
||||
assert "Failed to sync grains module: 'master_uri'" not in caplog.messages
|
||||
|
|
|
@ -456,6 +456,103 @@ def test_owner():
|
|||
assert aptpkg.owner(*paths) == "wget"
|
||||
|
||||
|
||||
def test_owner_no_path():
|
||||
"""
|
||||
Test owner when path is not passed
|
||||
"""
|
||||
ret = aptpkg.owner()
|
||||
assert ret == ""
|
||||
|
||||
|
||||
def test_owner_doesnotexist():
|
||||
"""
|
||||
Test owner when the path does not exist
|
||||
"""
|
||||
mock = MagicMock(return_value="")
|
||||
with patch.dict(aptpkg.__salt__, {"cmd.run_stdout": mock}):
|
||||
ret = aptpkg.owner("/doesnotexist")
|
||||
assert ret == ""
|
||||
|
||||
|
||||
def test_get_http_proxy_url_username_passwd():
|
||||
"""
|
||||
Test _get_http_proxy_url when username and passwod set
|
||||
"""
|
||||
host = "repo.saltproject.io"
|
||||
port = "888"
|
||||
user = "user"
|
||||
passwd = "password"
|
||||
mock_conf = MagicMock()
|
||||
mock_conf.side_effect = [host, port, user, passwd]
|
||||
patch_conf = patch.dict(aptpkg.__salt__, {"config.option": mock_conf})
|
||||
with patch_conf:
|
||||
ret = aptpkg._get_http_proxy_url()
|
||||
assert ret == f"http://{user}:{passwd}@{host}:{port}"
|
||||
|
||||
|
||||
def test_get_http_proxy_url():
|
||||
"""
|
||||
Test basic functionality for _get_http_proxy_url
|
||||
"""
|
||||
host = "repo.saltproject.io"
|
||||
port = "888"
|
||||
user = ""
|
||||
passwd = ""
|
||||
mock_conf = MagicMock()
|
||||
mock_conf.side_effect = [host, port, user, passwd]
|
||||
patch_conf = patch.dict(aptpkg.__salt__, {"config.option": mock_conf})
|
||||
with patch_conf:
|
||||
ret = aptpkg._get_http_proxy_url()
|
||||
assert ret == f"http://{host}:{port}"
|
||||
|
||||
|
||||
def test_get_http_proxy_url_empty():
|
||||
"""
|
||||
Test _get_http_proxy_Url when host and port are empty
|
||||
"""
|
||||
host = ""
|
||||
port = ""
|
||||
user = ""
|
||||
passwd = ""
|
||||
mock_conf = MagicMock()
|
||||
mock_conf.side_effect = [host, port, user, passwd]
|
||||
patch_conf = patch.dict(aptpkg.__salt__, {"config.option": mock_conf})
|
||||
with patch_conf:
|
||||
ret = aptpkg._get_http_proxy_url()
|
||||
assert ret == ""
|
||||
|
||||
|
||||
def test_list_upgrades():
|
||||
"""
|
||||
Test basic functinoality for list_upgrades
|
||||
"""
|
||||
patch_data = patch("salt.utils.data.is_true", return_value=True)
|
||||
patch_refresh = patch("salt.modules.aptpkg.refresh_db")
|
||||
apt_ret = {
|
||||
"pid": 2791,
|
||||
"retcode": 0,
|
||||
"stdout": "Reading package lists...\nBuilding dependency tree...\nReading state information...\nCalculating upgrade...\nThe following NEW packages will be installed:\n linux-cloud-tools-5.15.0-86 linux-cloud-tools-5.15.0-86-generic\n linux-headers-5.15.0-86 linux-headers-5.15.0-86-generic\n linux-image-5.15.0-86-generic linux-modules-5.15.0-86-generic\n linux-modules-extra-5.15.0-86-generic\nThe following packages have been kept back:\n libnetplan0 libsgutils2-2 netplan. io sg3-utils sg3-utils-udev\nThe following packages will be upgraded:\n linux-cloud-tools-virtual linux-generic linux-headers-generic\n linux-image-generic\n4 upgraded, 7 newly installed, 0 to remove and 5 not upgraded.\nInst linux-cloud-tools-5.15.0-86 (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nInst linux-cloud-tools-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nInst linux-cloud-tools-virtual [5.15.0.69.67] (5.15.0.86.83 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nInst linux-modules-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64]) []\nInst linux-image-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nInst linux-modules-extra-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nInst linux-generic [5.15.0.69.67] (5.15.0.86.83 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64]) []\nInst linux-image-generic [5.15.0.69.67] (5.15.0.86.83 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64]) []\nInst linux-headers-5.15.0-86 (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [all]) []\nInst linux-headers-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64]) []\nInst linux-headers-generic [5.15.0.69.67] (5.15.0.86.83 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-cloud-tools-5.15.0-86 (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-cloud-tools-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-cloud-tools-virtual (5.15.0.86.83 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-modules-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-image-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-modules-extra-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-generic (5.15.0.86.83 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-image-generic (5.15.0.86.83 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-headers-5.15.0-86 (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [all])\nConf linux-headers-5.15.0-86-generic (5.15.0-86.96 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])\nConf linux-headers-generic (5.15.0.86.83 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [amd64])",
|
||||
"stderr": "Running scope as unit: run-r014f3eae66364254b1cdacf701f1ab73.scope",
|
||||
}
|
||||
mock_apt = MagicMock(return_value=apt_ret)
|
||||
patch_apt = patch("salt.modules.aptpkg._call_apt", mock_apt)
|
||||
with patch_data, patch_refresh, patch_apt:
|
||||
ret = aptpkg.list_upgrades(dist_upgrade=False)
|
||||
assert ret == {
|
||||
"linux-cloud-tools-5.15.0-86": "5.15.0-86.96",
|
||||
"linux-cloud-tools-5.15.0-86-generic": "5.15.0-86.96",
|
||||
"linux-cloud-tools-virtual": "5.15.0.86.83",
|
||||
"linux-modules-5.15.0-86-generic": "5.15.0-86.96",
|
||||
"linux-image-5.15.0-86-generic": "5.15.0-86.96",
|
||||
"linux-modules-extra-5.15.0-86-generic": "5.15.0-86.96",
|
||||
"linux-generic": "5.15.0.86.83",
|
||||
"linux-image-generic": "5.15.0.86.83",
|
||||
"linux-headers-5.15.0-86": "5.15.0-86.96",
|
||||
"linux-headers-5.15.0-86-generic": "5.15.0-86.96",
|
||||
"linux-headers-generic": "5.15.0.86.83",
|
||||
}
|
||||
|
||||
|
||||
def test_refresh_db(apt_q_update_var):
|
||||
"""
|
||||
Test - Updates the APT database to latest packages based upon repositories.
|
||||
|
@ -1559,6 +1656,130 @@ def test_latest_version_names_empty():
|
|||
assert ret == ""
|
||||
|
||||
|
||||
def test_latest_version_fromrepo():
|
||||
"""
|
||||
test latest_version when `fromrepo` is passed in as a kwarg
|
||||
"""
|
||||
version = "5.15.0.86.83"
|
||||
fromrepo = "jammy-updates"
|
||||
list_ret = {"linux-cloud-tools-virtual": [version]}
|
||||
apt_ret = {
|
||||
"pid": 4361,
|
||||
"retcode": 0,
|
||||
"stdout": "linux-cloud-tools-virtual:\n"
|
||||
f"Installed: 5.15.0.69.67\n Candidate: {version}\n Version"
|
||||
f"table:\n {version} 990\n 990"
|
||||
f"https://mirrors.edge.kernel.org/ubuntu {fromrepo}/main amd64"
|
||||
"Packages\n 500 https://mirrors.edge.kernel.org/ubuntu"
|
||||
"jammy-security/main amd64 Packages\n ***5.15.0.69.67 100\n"
|
||||
"100 /var/lib/dpkg/status\n 5.15.0.25.27 500\n 500"
|
||||
"https://mirrors.edge.kernel.org/ubuntu jammy/main amd64 Packages",
|
||||
"stderr": "",
|
||||
}
|
||||
mock_apt = MagicMock(return_value=apt_ret)
|
||||
patch_apt = patch("salt.modules.aptpkg._call_apt", mock_apt)
|
||||
mock_list_pkgs = MagicMock(return_value=list_ret)
|
||||
patch_list_pkgs = patch("salt.modules.aptpkg.list_pkgs", mock_list_pkgs)
|
||||
with patch_apt, patch_list_pkgs:
|
||||
ret = aptpkg.latest_version(
|
||||
"linux-cloud-tools-virtual",
|
||||
fromrepo=fromrepo,
|
||||
refresh=False,
|
||||
show_installed=True,
|
||||
)
|
||||
assert ret == version
|
||||
assert mock_apt.call_args == call(
|
||||
[
|
||||
"apt-cache",
|
||||
"-q",
|
||||
"policy",
|
||||
"linux-cloud-tools-virtual",
|
||||
"-o",
|
||||
f"APT::Default-Release={fromrepo}",
|
||||
],
|
||||
scope=False,
|
||||
)
|
||||
|
||||
|
||||
def test_latest_version_fromrepo_multiple_names():
|
||||
"""
|
||||
test latest_version when multiple names of pkgs are pased
|
||||
"""
|
||||
version = "5.15.0.86.83"
|
||||
fromrepo = "jammy-updates"
|
||||
list_ret = {
|
||||
"linux-cloud-tools-virtual": ["5.15.0.69.67"],
|
||||
"linux-generic": ["5.15.0.69.67"],
|
||||
}
|
||||
apt_ret_cloud = {
|
||||
"pid": 4361,
|
||||
"retcode": 0,
|
||||
"stdout": "linux-cloud-tools-virtual:\n"
|
||||
f"Installed: 5.15.0.69.67\n Candidate: {version}\n Version"
|
||||
f"table:\n {version} 990\n 990"
|
||||
f"https://mirrors.edge.kernel.org/ubuntu {fromrepo}/main amd64"
|
||||
"Packages\n 500 https://mirrors.edge.kernel.org/ubuntu"
|
||||
"jammy-security/main amd64 Packages\n ***5.15.0.69.67 100\n"
|
||||
"100 /var/lib/dpkg/status\n 5.15.0.25.27 500\n 500"
|
||||
"https://mirrors.edge.kernel.org/ubuntu jammy/main amd64 Packages",
|
||||
"stderr": "",
|
||||
}
|
||||
apt_ret_generic = {
|
||||
"pid": 4821,
|
||||
"retcode": 0,
|
||||
"stdout": "linux-generic:\n"
|
||||
f"Installed: 5.15.0.69.67\n Candidate: {version}\n"
|
||||
f"Version table:\n {version} 990\n 990"
|
||||
"https://mirrors.edge.kernel.org/ubuntu"
|
||||
"jammy-updates/main amd64 Packages\n 500"
|
||||
"https://mirrors.edge.kernel.org/ubuntu"
|
||||
"jammy-security/main amd64 Packages\n *** 5.15.0.69.67"
|
||||
"100\n 100 /var/lib/dpkg/status\n 5.15.0.25.27"
|
||||
"500\n 500 https://mirrors.edge.kernel.org/ubuntu"
|
||||
"jammy/main amd64 Packages",
|
||||
"stderr": "",
|
||||
}
|
||||
|
||||
mock_apt = MagicMock()
|
||||
mock_apt.side_effect = [apt_ret_cloud, apt_ret_generic]
|
||||
patch_apt = patch("salt.modules.aptpkg._call_apt", mock_apt)
|
||||
mock_list_pkgs = MagicMock(return_value=list_ret)
|
||||
patch_list_pkgs = patch("salt.modules.aptpkg.list_pkgs", mock_list_pkgs)
|
||||
with patch_apt, patch_list_pkgs:
|
||||
ret = aptpkg.latest_version(
|
||||
"linux-cloud-tools-virtual",
|
||||
"linux-generic",
|
||||
fromrepo=fromrepo,
|
||||
refresh=False,
|
||||
show_installed=True,
|
||||
)
|
||||
assert ret == {"linux-cloud-tools-virtual": version, "linux-generic": version}
|
||||
assert mock_apt.call_args_list == [
|
||||
call(
|
||||
[
|
||||
"apt-cache",
|
||||
"-q",
|
||||
"policy",
|
||||
"linux-cloud-tools-virtual",
|
||||
"-o",
|
||||
"APT::Default-Release=jammy-updates",
|
||||
],
|
||||
scope=False,
|
||||
),
|
||||
call(
|
||||
[
|
||||
"apt-cache",
|
||||
"-q",
|
||||
"policy",
|
||||
"linux-generic",
|
||||
"-o",
|
||||
"APT::Default-Release=jammy-updates",
|
||||
],
|
||||
scope=False,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def test_hold():
|
||||
"""
|
||||
test aptpkg.hold() when passing in the name of a package
|
||||
|
|
201
tests/pytests/unit/state/test_state_basic.py
Normal file
201
tests/pytests/unit/state/test_state_basic.py
Normal file
|
@ -0,0 +1,201 @@
|
|||
"""
|
||||
Test functions in state.py that are not a part of a class
|
||||
"""
|
||||
import pytest
|
||||
|
||||
import salt.state
|
||||
from salt.utils.odict import OrderedDict
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.core_test,
|
||||
]
|
||||
|
||||
|
||||
def test_state_args():
|
||||
"""
|
||||
Testing state.state_args when this state is being used:
|
||||
|
||||
/etc/foo.conf:
|
||||
file.managed:
|
||||
- contents: "blah"
|
||||
- mkdirs: True
|
||||
- user: ch3ll
|
||||
- group: ch3ll
|
||||
- mode: 755
|
||||
|
||||
/etc/bar.conf:
|
||||
file.managed:
|
||||
- use:
|
||||
- file: /etc/foo.conf
|
||||
"""
|
||||
id_ = "/etc/bar.conf"
|
||||
state = "file"
|
||||
high = OrderedDict(
|
||||
[
|
||||
(
|
||||
"/etc/foo.conf",
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"file",
|
||||
[
|
||||
OrderedDict([("contents", "blah")]),
|
||||
OrderedDict([("mkdirs", True)]),
|
||||
OrderedDict([("user", "ch3ll")]),
|
||||
OrderedDict([("group", "ch3ll")]),
|
||||
OrderedDict([("mode", 755)]),
|
||||
"managed",
|
||||
{"order": 10000},
|
||||
],
|
||||
),
|
||||
("__sls__", "test"),
|
||||
("__env__", "base"),
|
||||
]
|
||||
),
|
||||
),
|
||||
(
|
||||
"/etc/bar.conf",
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"file",
|
||||
[
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"use",
|
||||
[OrderedDict([("file", "/etc/foo.conf")])],
|
||||
)
|
||||
]
|
||||
),
|
||||
"managed",
|
||||
{"order": 10001},
|
||||
],
|
||||
),
|
||||
("__sls__", "test"),
|
||||
("__env__", "base"),
|
||||
]
|
||||
),
|
||||
),
|
||||
]
|
||||
)
|
||||
ret = salt.state.state_args(id_, state, high)
|
||||
assert ret == {"order", "use"}
|
||||
|
||||
|
||||
def test_state_args_id_not_high():
|
||||
"""
|
||||
Testing state.state_args when id_ is not in high
|
||||
"""
|
||||
id_ = "/etc/bar.conf2"
|
||||
state = "file"
|
||||
high = OrderedDict(
|
||||
[
|
||||
(
|
||||
"/etc/foo.conf",
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"file",
|
||||
[
|
||||
OrderedDict([("contents", "blah")]),
|
||||
OrderedDict([("mkdirs", True)]),
|
||||
OrderedDict([("user", "ch3ll")]),
|
||||
OrderedDict([("group", "ch3ll")]),
|
||||
OrderedDict([("mode", 755)]),
|
||||
"managed",
|
||||
{"order": 10000},
|
||||
],
|
||||
),
|
||||
("__sls__", "test"),
|
||||
("__env__", "base"),
|
||||
]
|
||||
),
|
||||
),
|
||||
(
|
||||
"/etc/bar.conf",
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"file",
|
||||
[
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"use",
|
||||
[OrderedDict([("file", "/etc/foo.conf")])],
|
||||
)
|
||||
]
|
||||
),
|
||||
"managed",
|
||||
{"order": 10001},
|
||||
],
|
||||
),
|
||||
("__sls__", "test"),
|
||||
("__env__", "base"),
|
||||
]
|
||||
),
|
||||
),
|
||||
]
|
||||
)
|
||||
ret = salt.state.state_args(id_, state, high)
|
||||
assert ret == set()
|
||||
|
||||
|
||||
def test_state_args_state_not_high():
|
||||
"""
|
||||
Testing state.state_args when state is not in high date
|
||||
"""
|
||||
id_ = "/etc/bar.conf"
|
||||
state = "file2"
|
||||
high = OrderedDict(
|
||||
[
|
||||
(
|
||||
"/etc/foo.conf",
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"file",
|
||||
[
|
||||
OrderedDict([("contents", "blah")]),
|
||||
OrderedDict([("mkdirs", True)]),
|
||||
OrderedDict([("user", "ch3ll")]),
|
||||
OrderedDict([("group", "ch3ll")]),
|
||||
OrderedDict([("mode", 755)]),
|
||||
"managed",
|
||||
{"order": 10000},
|
||||
],
|
||||
),
|
||||
("__sls__", "test"),
|
||||
("__env__", "base"),
|
||||
]
|
||||
),
|
||||
),
|
||||
(
|
||||
"/etc/bar.conf",
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"file",
|
||||
[
|
||||
OrderedDict(
|
||||
[
|
||||
(
|
||||
"use",
|
||||
[OrderedDict([("file", "/etc/foo.conf")])],
|
||||
)
|
||||
]
|
||||
),
|
||||
"managed",
|
||||
{"order": 10001},
|
||||
],
|
||||
),
|
||||
("__sls__", "test"),
|
||||
("__env__", "base"),
|
||||
]
|
||||
),
|
||||
),
|
||||
]
|
||||
)
|
||||
ret = salt.state.state_args(id_, state, high)
|
||||
assert ret == set()
|
|
@ -1302,3 +1302,37 @@ def test_check_refresh_pillar(minion_opts, caplog):
|
|||
state_obj.check_refresh(data, ret)
|
||||
mock_refresh.assert_called_once()
|
||||
assert "Refreshing pillar..." in caplog.text
|
||||
|
||||
|
||||
def test_module_refresh_runtimeerror(minion_opts, caplog):
|
||||
"""
|
||||
test module_refresh when runtimerror occurs
|
||||
"""
|
||||
mock_importlib = MagicMock()
|
||||
mock_importlib.side_effect = RuntimeError("Error")
|
||||
patch_importlib = patch("importlib.reload", mock_importlib)
|
||||
patch_pillar = patch("salt.state.State._gather_pillar", return_value="")
|
||||
with patch_importlib, patch_pillar:
|
||||
state_obj = salt.state.State(minion_opts)
|
||||
state_obj.module_refresh()
|
||||
assert (
|
||||
"Error encountered during module reload. Modules were not reloaded."
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
|
||||
def test_module_refresh_typeerror(minion_opts, caplog):
|
||||
"""
|
||||
test module_refresh when typeerror occurs
|
||||
"""
|
||||
mock_importlib = MagicMock()
|
||||
mock_importlib.side_effect = TypeError("Error")
|
||||
patch_importlib = patch("importlib.reload", mock_importlib)
|
||||
patch_pillar = patch("salt.state.State._gather_pillar", return_value="")
|
||||
with patch_importlib, patch_pillar:
|
||||
state_obj = salt.state.State(minion_opts)
|
||||
state_obj.module_refresh()
|
||||
assert (
|
||||
"Error encountered during module reload. Modules were not reloaded."
|
||||
in caplog.text
|
||||
)
|
||||
|
|
|
@ -8,7 +8,7 @@ import textwrap
|
|||
import pytest # pylint: disable=unused-import
|
||||
|
||||
import salt.state
|
||||
from salt.utils.odict import OrderedDict
|
||||
from salt.utils.odict import DefaultOrderedDict, OrderedDict
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -352,3 +352,68 @@ def test_dont_extend_in_excluded_sls_file(highstate, state_tree_dir):
|
|||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_verify_tops(highstate):
|
||||
"""
|
||||
test basic functionality of verify_tops
|
||||
"""
|
||||
tops = DefaultOrderedDict(OrderedDict)
|
||||
tops["base"] = OrderedDict([("*", ["test", "test2"])])
|
||||
matches = highstate.verify_tops(tops)
|
||||
# [] means there where no errors when verifying tops
|
||||
assert matches == []
|
||||
|
||||
|
||||
def test_verify_tops_not_dict(highstate):
|
||||
"""
|
||||
test verify_tops when top data is not a dict
|
||||
"""
|
||||
matches = highstate.verify_tops(["base", "test", "test2"])
|
||||
assert matches == ["Top data was not formed as a dict"]
|
||||
|
||||
|
||||
def test_verify_tops_env_empty(highstate):
|
||||
"""
|
||||
test verify_tops when the environment is empty
|
||||
"""
|
||||
tops = DefaultOrderedDict(OrderedDict)
|
||||
tops[""] = OrderedDict([("*", ["test", "test2"])])
|
||||
matches = highstate.verify_tops(tops)
|
||||
assert matches == ["Empty saltenv statement in top file"]
|
||||
|
||||
|
||||
def test_verify_tops_sls_not_list(highstate):
|
||||
"""
|
||||
test verify_tops when the sls files are not a list
|
||||
"""
|
||||
tops = DefaultOrderedDict(OrderedDict)
|
||||
tops["base"] = OrderedDict([("*", "test test2")])
|
||||
matches = highstate.verify_tops(tops)
|
||||
# [] means there where no errors when verifying tops
|
||||
assert matches == ["Malformed topfile (state declarations not formed as a list)"]
|
||||
|
||||
|
||||
def test_verify_tops_match(highstate):
|
||||
"""
|
||||
test basic functionality of verify_tops when using a matcher
|
||||
like `match: glob`.
|
||||
"""
|
||||
tops = DefaultOrderedDict(OrderedDict)
|
||||
tops["base"] = OrderedDict(
|
||||
[("*", [OrderedDict([("match", "glob")]), "test", "test2"])]
|
||||
)
|
||||
matches = highstate.verify_tops(tops)
|
||||
# [] means there where no errors when verifying tops
|
||||
assert matches == []
|
||||
|
||||
|
||||
def test_verify_tops_match_none(highstate):
|
||||
"""
|
||||
test basic functionality of verify_tops when using a matcher
|
||||
when it is empty, like `match: ""`.
|
||||
"""
|
||||
tops = DefaultOrderedDict(OrderedDict)
|
||||
tops["base"] = OrderedDict([("*", [OrderedDict([("match", "")]), "test", "test2"])])
|
||||
matches = highstate.verify_tops(tops)
|
||||
assert "Improperly formatted top file matcher in saltenv" in matches[0]
|
||||
|
|
Loading…
Add table
Reference in a new issue