SHA256
1
0
forked from pool/salt

Accepting request 1085020 from systemsmanagement:saltstack

- Update to Salt release version 3006.0 (jsc#PED-3139)
  * See release notes: https://docs.saltproject.io/en/latest/topics/releases/3006.0.html

- Add python3-looseversion as new dependency for salt
- Add python3-packaging as new dependency for salt
- Drop conflictive patch dicarded from upstream
- Fix SLS rendering error when Jinja macros are used
- Fix version detection and avoid building and testing failures

OBS-URL: https://build.opensuse.org/request/show/1085020
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/salt?expand=0&rev=137
This commit is contained in:
Dominique Leuenberger 2023-05-06 20:08:37 +00:00 committed by Git OBS Bridge
commit 21a97bca4b
91 changed files with 2298 additions and 5264 deletions

View File

@ -1,4 +1,4 @@
From a5027f623a0a2e7f49109af9e2fa3ce409a31a64 Mon Sep 17 00:00:00 2001
From 327a5e5b24c4fa047df44b245abd672e02999cca Mon Sep 17 00:00:00 2001
From: Michael Calmer <Michael.Calmer@suse.de>
Date: Mon, 23 Jan 2023 14:33:26 +0100
Subject: [PATCH] 3005.1 implement zypper removeptf (#573)
@ -13,15 +13,13 @@ Subject: [PATCH] 3005.1 implement zypper removeptf (#573)
* Update Docs
Co-authored-by: Megan Wilhite <mwilhite@vmware.com>
Co-authored-by: Megan Wilhite <mwilhite@vmware.com>
---
changelog/63442.added | 1 +
salt/modules/zypperpkg.py | 38 +++++++-
tests/pytests/unit/modules/test_zypperpkg.py | 92 +++++++++++++++++++-
tests/unit/modules/test_zypperpkg.py | 1 +
4 files changed, 130 insertions(+), 2 deletions(-)
changelog/63442.added | 1 +
salt/modules/zypperpkg.py | 38 +-
tests/pytests/unit/modules/test_zypperpkg.py | 356 ++++++++++++++++++-
tests/unit/modules/test_zypperpkg.py | 1 +
4 files changed, 394 insertions(+), 2 deletions(-)
create mode 100644 changelog/63442.added
diff --git a/changelog/63442.added b/changelog/63442.added
@ -32,10 +30,10 @@ index 0000000000..ad81b2f9d5
@@ -0,0 +1 @@
+implement removal of ptf packages in zypper pkg module
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index 5d745c432d..2888bb219f 100644
index 051f8f72c7..44f2cdbd3a 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -2058,17 +2058,21 @@ def _uninstall(inclusion_detection, name=None, pkgs=None, root=None):
@@ -2073,17 +2073,21 @@ def _uninstall(inclusion_detection, name=None, pkgs=None, root=None):
except MinionError as exc:
raise CommandExecutionError(exc)
@ -58,7 +56,7 @@ index 5d745c432d..2888bb219f 100644
return {}
systemd_scope = _systemd_scope()
@@ -2080,6 +2084,13 @@ def _uninstall(inclusion_detection, name=None, pkgs=None, root=None):
@@ -2095,6 +2099,13 @@ def _uninstall(inclusion_detection, name=None, pkgs=None, root=None):
)
targets = targets[500:]
@ -72,7 +70,7 @@ index 5d745c432d..2888bb219f 100644
_clean_cache()
new = list_pkgs(root=root, includes=includes)
ret = salt.utils.data.compare_dicts(old, new)
@@ -2168,6 +2179,11 @@ def remove(
@@ -2183,6 +2194,11 @@ def remove(
salt '*' pkg.remove <package name>
salt '*' pkg.remove <package1>,<package2>,<package3>
salt '*' pkg.remove pkgs='["foo", "bar"]'
@ -84,7 +82,7 @@ index 5d745c432d..2888bb219f 100644
"""
return _uninstall(inclusion_detection, name=name, pkgs=pkgs, root=root)
@@ -2643,6 +2659,26 @@ def _get_visible_patterns(root=None):
@@ -2658,6 +2674,26 @@ def _get_visible_patterns(root=None):
return patterns
@ -112,10 +110,10 @@ index 5d745c432d..2888bb219f 100644
"""
List all installed patterns.
diff --git a/tests/pytests/unit/modules/test_zypperpkg.py b/tests/pytests/unit/modules/test_zypperpkg.py
index 84dc7a10b4..a0d8e0084e 100644
index 91132b7277..c996662e1c 100644
--- a/tests/pytests/unit/modules/test_zypperpkg.py
+++ b/tests/pytests/unit/modules/test_zypperpkg.py
@@ -10,7 +10,7 @@ import pytest
@@ -11,7 +11,7 @@ import pytest
import salt.modules.pkg_resource as pkg_resource
import salt.modules.zypperpkg as zypper
from salt.exceptions import CommandExecutionError, SaltInvocationError
@ -124,10 +122,281 @@ index 84dc7a10b4..a0d8e0084e 100644
@pytest.fixture
@@ -527,3 +527,93 @@ def test_dist_upgrade_failure():
@@ -27,6 +27,11 @@ def configure_loader_modules():
}
assert exc.exception.info["changes"] == {}
assert exc.exception.info["result"]["stdout"] == zypper_output
+@pytest.fixture(autouse=True)
+def fresh_zypper_instance():
+ zypper.__zypper__ = zypper._Zypper()
+
+
def test_list_pkgs_no_context():
"""
Test packages listing.
@@ -395,3 +400,352 @@ def test_del_repo_key():
with patch.dict(zypper.__salt__, salt_mock):
assert zypper.del_repo_key(keyid="keyid", root="/mnt")
salt_mock["lowpkg.remove_gpg_key"].assert_called_once_with("keyid", "/mnt")
+
+@pytest.mark.parametrize(
+ "zypper_version,lowpkg_version_cmp,expected_inst_avc,expected_dup_avc",
+ [
+ ("0.5", [-1, -1], False, False),
+ ("1.11.34", [0, -1], False, True),
+ ("1.14.8", [0, 0], True, True),
+ ],
+)
+def test_refresh_zypper_flags(
+ zypper_version, lowpkg_version_cmp, expected_inst_avc, expected_dup_avc
+):
+ with patch(
+ "salt.modules.zypperpkg.version", MagicMock(return_value=zypper_version)
+ ), patch.dict(
+ zypper.__salt__,
+ {"lowpkg.version_cmp": MagicMock(side_effect=lowpkg_version_cmp)},
+ ):
+ _zypper = zypper._Zypper()
+ _zypper.refresh_zypper_flags()
+ assert _zypper.inst_avc == expected_inst_avc
+ assert _zypper.dup_avc == expected_dup_avc
+
+
+@pytest.mark.parametrize(
+ "inst_avc,dup_avc,avc,allowvendorchange_param,novendorchange_param,expected",
+ [
+ # inst_avc = True, dup_avc = True
+ (True, True, False, False, False, True),
+ (True, True, False, True, False, True),
+ (True, True, False, False, True, False),
+ (True, True, False, True, True, True),
+ # inst_avc = False, dup_avc = True
+ (False, True, False, False, False, True),
+ (False, True, False, True, False, True),
+ (False, True, False, False, True, False),
+ (False, True, False, True, True, True),
+ # inst_avc = False, dup_avc = False
+ (False, False, False, False, False, False),
+ (False, False, False, True, False, False),
+ (False, False, False, False, True, False),
+ (False, False, False, True, True, False),
+ ],
+)
+@patch("salt.modules.zypperpkg._Zypper.refresh_zypper_flags", MagicMock())
+def test_allow_vendor_change(
+ inst_avc,
+ dup_avc,
+ avc,
+ allowvendorchange_param,
+ novendorchange_param,
+ expected,
+):
+ _zypper = zypper._Zypper()
+ _zypper.inst_avc = inst_avc
+ _zypper.dup_avc = dup_avc
+ _zypper.avc = avc
+ _zypper.allow_vendor_change(allowvendorchange_param, novendorchange_param)
+ assert _zypper.avc == expected
+
+
+@pytest.mark.parametrize(
+ "package,pre_version,post_version,fromrepo_param,name_param,pkgs_param,diff_attr_param",
+ [
+ ("vim", "1.1", "1.2", [], "", [], "all"),
+ ("kernel-default", "1.1", "1.1,1.2", ["dummy", "dummy2"], "", [], None),
+ ("vim", "1.1", "1.2", [], "vim", [], None),
+ ],
+)
+@patch.object(zypper, "refresh_db", MagicMock(return_value=True))
+def test_upgrade(
+ package,
+ pre_version,
+ post_version,
+ fromrepo_param,
+ name_param,
+ pkgs_param,
+ diff_attr_param,
+):
+ with patch(
+ "salt.modules.zypperpkg.__zypper__.noraise.call"
+ ) as zypper_mock, patch.object(
+ zypper,
+ "list_pkgs",
+ MagicMock(side_effect=[{package: pre_version}, {package: post_version}]),
+ ) as list_pkgs_mock:
+ expected_call = ["update", "--auto-agree-with-licenses"]
+ for repo in fromrepo_param:
+ expected_call.extend(["--repo", repo])
+
+ if pkgs_param:
+ expected_call.extend(pkgs_param)
+ elif name_param:
+ expected_call.append(name_param)
+
+ result = zypper.upgrade(
+ name=name_param,
+ pkgs=pkgs_param,
+ fromrepo=fromrepo_param,
+ diff_attr=diff_attr_param,
+ )
+ zypper_mock.assert_any_call(*expected_call)
+ assert result == {package: {"old": pre_version, "new": post_version}}
+ list_pkgs_mock.assert_any_call(root=None, attr=diff_attr_param)
+
+
+@pytest.mark.parametrize(
+ "package,pre_version,post_version,fromrepo_param",
+ [
+ ("vim", "1.1", "1.2", []),
+ ("emacs", "1.1", "1.2", ["Dummy", "Dummy2"]),
+ ],
+)
+@patch.object(zypper, "refresh_db", MagicMock(return_value=True))
+def test_dist_upgrade(package, pre_version, post_version, fromrepo_param):
+ with patch(
+ "salt.modules.zypperpkg.__zypper__.noraise.call"
+ ) as zypper_mock, patch.object(
+ zypper,
+ "list_pkgs",
+ MagicMock(side_effect=[{package: pre_version}, {package: post_version}]),
+ ):
+ expected_call = ["dist-upgrade", "--auto-agree-with-licenses"]
+
+ for repo in fromrepo_param:
+ expected_call.extend(["--from", repo])
+
+ result = zypper.upgrade(dist_upgrade=True, fromrepo=fromrepo_param)
+ zypper_mock.assert_any_call(*expected_call)
+ assert result == {package: {"old": pre_version, "new": post_version}}
+
+
+@pytest.mark.parametrize(
+ "package,pre_version,post_version,dup_avc,novendorchange_param,allowvendorchange_param,vendor_change",
+ [
+ # dup_avc = True, both params = default -> no vendor change
+ ("vim", "1.1", "1.2", True, True, False, False),
+ # dup_avc = True, allowvendorchange = True -> vendor change
+ (
+ "emacs",
+ "1.1",
+ "1.2",
+ True,
+ True,
+ True,
+ True,
+ ),
+ # dup_avc = True, novendorchange = False -> vendor change
+ ("joe", "1.1", "1.2", True, False, False, True),
+ # dup_avc = True, both params = toggled -> vendor change
+ ("kate", "1.1", "1.2", True, False, True, True),
+ # dup_avc = False -> no vendor change
+ (
+ "gedit",
+ "1.1",
+ "1.2",
+ False,
+ False,
+ True,
+ False
+ ),
+ ],
+)
+@patch.object(zypper, "refresh_db", MagicMock(return_value=True))
+def test_dist_upgrade_vendorchange(
+ package,
+ pre_version,
+ post_version,
+ dup_avc,
+ novendorchange_param,
+ allowvendorchange_param,
+ vendor_change
+):
+ cmd_run_mock = MagicMock(return_value={"retcode": 0, "stdout": None})
+ with patch.object(
+ zypper,
+ "list_pkgs",
+ MagicMock(side_effect=[{package: pre_version}, {package: post_version}]),
+ ), patch("salt.modules.zypperpkg.__zypper__.refresh_zypper_flags",), patch.dict(
+ zypper.__salt__, {"cmd.run_all": cmd_run_mock}
+ ):
+ expected_cmd = ["zypper", "--non-interactive", "--no-refresh", "dist-upgrade"]
+ # --allow-vendor-change is injected right after "dist-upgrade"
+ if vendor_change:
+ expected_cmd.append("--allow-vendor-change")
+ expected_cmd.append("--auto-agree-with-licenses")
+
+ zypper.__zypper__.dup_avc = dup_avc
+ zypper.upgrade(
+ dist_upgrade=True,
+ allowvendorchange=allowvendorchange_param,
+ novendorchange=novendorchange_param,
+ )
+ cmd_run_mock.assert_any_call(
+ expected_cmd, output_loglevel="trace", python_shell=False, env={}
+ )
+
+
+@pytest.mark.parametrize(
+ "package,pre_version,post_version,fromrepo_param",
+ [
+ ("vim", "1.1", "1.1", []),
+ ("emacs", "1.1", "1.1", ["Dummy", "Dummy2"]),
+ ],
+)
+@patch.object(zypper, "refresh_db", MagicMock(return_value=True))
+def test_dist_upgrade_dry_run(package, pre_version, post_version, fromrepo_param):
+ with patch(
+ "salt.modules.zypperpkg.__zypper__.noraise.call"
+ ) as zypper_mock, patch.object(
+ zypper,
+ "list_pkgs",
+ MagicMock(side_effect=[{package: pre_version}, {package: post_version}]),
+ ):
+ expected_call = ["dist-upgrade", "--auto-agree-with-licenses", "--dry-run"]
+
+ for repo in fromrepo_param:
+ expected_call.extend(["--from", repo])
+
+ zypper.upgrade(dist_upgrade=True, dryrun=True, fromrepo=fromrepo_param)
+ zypper_mock.assert_any_call(*expected_call)
+ # dryrun=True causes two calls, one with a trailing --debug-solver flag
+ expected_call.append("--debug-solver")
+ zypper_mock.assert_any_call(*expected_call)
+
+
+@patch.object(zypper, "refresh_db", MagicMock(return_value=True))
+def test_dist_upgrade_failure():
+ zypper_output = textwrap.dedent(
+ """\
+ Loading repository data...
+ Reading installed packages...
+ Computing distribution upgrade...
+ Use 'zypper repos' to get the list of defined repositories.
+ Repository 'DUMMY' not found by its alias, number, or URI.
+ """
+ )
+ call_spy = MagicMock()
+ zypper_mock = MagicMock()
+ zypper_mock.stdout = zypper_output
+ zypper_mock.stderr = ""
+ zypper_mock.exit_code = 3
+ zypper_mock.noraise.call = call_spy
+ with patch("salt.modules.zypperpkg.__zypper__", zypper_mock), patch.object(
+ zypper, "list_pkgs", MagicMock(side_effect=[{"vim": 1.1}, {"vim": 1.1}])
+ ):
+ expected_call = [
+ "dist-upgrade",
+ "--auto-agree-with-licenses",
+ "--from",
+ "Dummy",
+ ]
+
+ with pytest.raises(CommandExecutionError) as exc:
+ zypper.upgrade(dist_upgrade=True, fromrepo=["Dummy"])
+ call_spy.assert_called_with(*expected_call)
+
+ assert exc.exception.info["changes"] == {}
+ assert exc.exception.info["result"]["stdout"] == zypper_output
+
+
+def test_remove_multiple_pkgs_with_ptf():
@ -219,10 +488,10 @@ index 84dc7a10b4..a0d8e0084e 100644
+ assert result["ptf-12345"]["new"] == "", result
+ assert result["ptf-12345"]["old"] == "1", result
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
index bcd001cd85..db766363ec 100644
index f5b6d74b6f..6e5ca88895 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -1470,6 +1470,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -1953,6 +1953,7 @@ Repository 'DUMMY' not found by its alias, number, or URI.
# If config.get starts being used elsewhere, we'll need to write a
# side_effect function.
patches = {
@ -231,6 +500,6 @@ index bcd001cd85..db766363ec 100644
"pkg_resource.parse_targets": MagicMock(return_value=parsed_targets),
"pkg_resource.stringify": MagicMock(),
--
2.37.3
2.39.2

View File

@ -1 +1 @@
e66649e03c92d249899960aa629533eaeee31fa1
2c8ae68c3fb161fd84005ed1b58abf7865ba646f

View File

@ -3,7 +3,7 @@
<param name="url">https://github.com/openSUSE/salt-packaging.git</param>
<param name="subdir">salt</param>
<param name="filename">package</param>
<param name="revision">release/3005.1</param>
<param name="revision">release/3006.0</param>
<param name="scm">git</param>
</service>
<service name="extract_file" mode="disabled">
@ -12,8 +12,8 @@
</service>
<service name="download_url" mode="disabled">
<param name="host">codeload.github.com</param>
<param name="path">openSUSE/salt/tar.gz/v3005.1-suse</param>
<param name="filename">v3005.1.tar.gz</param>
<param name="path">openSUSE/salt/tar.gz/v3006.0-suse</param>
<param name="filename">v3006.0.tar.gz</param>
</service>
<service name="update_changelog" mode="disabled"></service>
</services>

View File

@ -1,4 +1,4 @@
From ae426ff5df3ade9ce16672fb20399634a8b777d5 Mon Sep 17 00:00:00 2001
From f2938966bd1fcb46df0f202f5a86729ab190565a Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Tue, 17 Oct 2017 16:52:33 +0200
Subject: [PATCH] Activate all beacons sources: config/pillar/grains
@ -8,7 +8,7 @@ Subject: [PATCH] Activate all beacons sources: config/pillar/grains
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/salt/minion.py b/salt/minion.py
index 544805fc62..16452facf4 100644
index 6237fcc4b7..2f905e4a4f 100644
--- a/salt/minion.py
+++ b/salt/minion.py
@@ -503,9 +503,7 @@ class MinionBase:
@ -23,6 +23,6 @@ index 544805fc62..16452facf4 100644
return self.beacons.process(
b_conf, self.opts["grains"]
--
2.37.3
2.39.2

View File

@ -1,224 +0,0 @@
From 1434a128559df8183c032af722dc3d187bda148a Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <Victor.Zhestkov@suse.com>
Date: Thu, 1 Sep 2022 14:46:24 +0300
Subject: [PATCH] Add Amazon EC2 detection for virtual grains
(bsc#1195624)
* Add ignore_retcode to quiet run functions
* Implement Amazon EC2 detection for virtual grains
* Add test for virtual grain detection of Amazon EC2
* Also detect the product of Amazon EC2 instance
* Add changelog entry
---
changelog/62539.added | 1 +
salt/grains/core.py | 18 ++++
salt/modules/cmdmod.py | 4 +
tests/pytests/unit/grains/test_core.py | 117 +++++++++++++++++++++++++
4 files changed, 140 insertions(+)
create mode 100644 changelog/62539.added
diff --git a/changelog/62539.added b/changelog/62539.added
new file mode 100644
index 0000000000..5f402d61c2
--- /dev/null
+++ b/changelog/62539.added
@@ -0,0 +1 @@
+Implementation of Amazon EC2 instance detection and setting `virtual_subtype` grain accordingly including the product if possible to identify.
diff --git a/salt/grains/core.py b/salt/grains/core.py
index 23d8b8ea42..047c33ffd3 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -1171,6 +1171,24 @@ def _virtual(osdata):
if grains.get("virtual_subtype") and grains["virtual"] == "physical":
grains["virtual"] = "virtual"
+ # Try to detect if the instance is running on Amazon EC2
+ if grains["virtual"] in ("qemu", "kvm", "xen"):
+ dmidecode = salt.utils.path.which("dmidecode")
+ if dmidecode:
+ ret = __salt__["cmd.run_all"](
+ [dmidecode, "-t", "system"], ignore_retcode=True
+ )
+ output = ret["stdout"]
+ if "Manufacturer: Amazon EC2" in output:
+ grains["virtual_subtype"] = "Amazon EC2"
+ product = re.match(
+ r".*Product Name: ([^\r\n]*).*", output, flags=re.DOTALL
+ )
+ if product:
+ grains["virtual_subtype"] = "Amazon EC2 ({})".format(product[1])
+ elif re.match(r".*Version: [^\r\n]+\.amazon.*", output, flags=re.DOTALL):
+ grains["virtual_subtype"] = "Amazon EC2"
+
for command in failed_commands:
log.info(
"Although '%s' was found in path, the current user "
diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py
index a26220718a..07b6e100d2 100644
--- a/salt/modules/cmdmod.py
+++ b/salt/modules/cmdmod.py
@@ -932,6 +932,7 @@ def _run_quiet(
success_retcodes=None,
success_stdout=None,
success_stderr=None,
+ ignore_retcode=None,
):
"""
Helper for running commands quietly for minion startup
@@ -958,6 +959,7 @@ def _run_quiet(
success_retcodes=success_retcodes,
success_stdout=success_stdout,
success_stderr=success_stderr,
+ ignore_retcode=ignore_retcode,
)["stdout"]
@@ -980,6 +982,7 @@ def _run_all_quiet(
success_retcodes=None,
success_stdout=None,
success_stderr=None,
+ ignore_retcode=None,
):
"""
@@ -1012,6 +1015,7 @@ def _run_all_quiet(
success_retcodes=success_retcodes,
success_stdout=success_stdout,
success_stderr=success_stderr,
+ ignore_retcode=ignore_retcode,
)
diff --git a/tests/pytests/unit/grains/test_core.py b/tests/pytests/unit/grains/test_core.py
index 5c43dbdb09..7c4ea1f17f 100644
--- a/tests/pytests/unit/grains/test_core.py
+++ b/tests/pytests/unit/grains/test_core.py
@@ -2823,3 +2823,120 @@ def test_get_server_id():
with patch.dict(core.__opts__, {"id": "otherid"}):
assert core.get_server_id() != expected
+
+
+@pytest.mark.skip_unless_on_linux
+def test_virtual_set_virtual_ec2():
+ osdata = {}
+
+ (
+ osdata["kernel"],
+ osdata["nodename"],
+ osdata["kernelrelease"],
+ osdata["kernelversion"],
+ osdata["cpuarch"],
+ _,
+ ) = platform.uname()
+
+ which_mock = MagicMock(
+ side_effect=[
+ # Check with virt-what
+ "/usr/sbin/virt-what",
+ "/usr/sbin/virt-what",
+ None,
+ "/usr/sbin/dmidecode",
+ # Check with systemd-detect-virt
+ None,
+ "/usr/bin/systemd-detect-virt",
+ None,
+ "/usr/sbin/dmidecode",
+ # Check with systemd-detect-virt when no dmidecode available
+ None,
+ "/usr/bin/systemd-detect-virt",
+ None,
+ None,
+ ]
+ )
+ cmd_run_all_mock = MagicMock(
+ side_effect=[
+ # Check with virt-what
+ {"retcode": 0, "stderr": "", "stdout": "xen"},
+ {
+ "retcode": 0,
+ "stderr": "",
+ "stdout": "\n".join(
+ [
+ "dmidecode 3.2",
+ "Getting SMBIOS data from sysfs.",
+ "SMBIOS 2.7 present.",
+ "",
+ "Handle 0x0100, DMI type 1, 27 bytes",
+ "System Information",
+ " Manufacturer: Xen",
+ " Product Name: HVM domU",
+ " Version: 4.11.amazon",
+ " Serial Number: 12345678-abcd-4321-dcba-0123456789ab",
+ " UUID: 01234567-dcba-1234-abcd-abcdef012345",
+ " Wake-up Type: Power Switch",
+ " SKU Number: Not Specified",
+ " Family: Not Specified",
+ "",
+ "Handle 0x2000, DMI type 32, 11 bytes",
+ "System Boot Information",
+ " Status: No errors detected",
+ ]
+ ),
+ },
+ # Check with systemd-detect-virt
+ {"retcode": 0, "stderr": "", "stdout": "kvm"},
+ {
+ "retcode": 0,
+ "stderr": "",
+ "stdout": "\n".join(
+ [
+ "dmidecode 3.2",
+ "Getting SMBIOS data from sysfs.",
+ "SMBIOS 2.7 present.",
+ "",
+ "Handle 0x0001, DMI type 1, 27 bytes",
+ "System Information",
+ " Manufacturer: Amazon EC2",
+ " Product Name: m5.large",
+ " Version: Not Specified",
+ " Serial Number: 01234567-dcba-1234-abcd-abcdef012345",
+ " UUID: 12345678-abcd-4321-dcba-0123456789ab",
+ " Wake-up Type: Power Switch",
+ " SKU Number: Not Specified",
+ " Family: Not Specified",
+ ]
+ ),
+ },
+ # Check with systemd-detect-virt when no dmidecode available
+ {"retcode": 0, "stderr": "", "stdout": "kvm"},
+ ]
+ )
+
+ with patch("salt.utils.path.which", which_mock), patch.dict(
+ core.__salt__,
+ {
+ "cmd.run": salt.modules.cmdmod.run,
+ "cmd.run_all": cmd_run_all_mock,
+ "cmd.retcode": salt.modules.cmdmod.retcode,
+ "smbios.get": salt.modules.smbios.get,
+ },
+ ):
+
+ virtual_grains = core._virtual(osdata.copy())
+
+ assert virtual_grains["virtual"] == "xen"
+ assert virtual_grains["virtual_subtype"] == "Amazon EC2"
+
+ virtual_grains = core._virtual(osdata.copy())
+
+ assert virtual_grains["virtual"] == "kvm"
+ assert virtual_grains["virtual_subtype"] == "Amazon EC2 (m5.large)"
+
+ virtual_grains = core._virtual(osdata.copy())
+
+ assert virtual_grains["virtual"] == "kvm"
+ assert "virtual_subtype" not in virtual_grains
--
2.37.3

View File

@ -1,4 +1,4 @@
From cb31b475c2ac02e06b167f30fc36fe49f7f5d4f6 Mon Sep 17 00:00:00 2001
From 311d4e320527158b6ff88604b45e15f0dc2bfa62 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 12:59:43 +0100
Subject: [PATCH] Add custom SUSE capabilities as Grains
@ -25,6 +25,6 @@ index 300052f1ee..f2504dbf19 100644
+ '__suse_reserved_saltutil_states_support': True
+ }
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 0cbc4e8f8ed5c8366ed6864216d70d58f5ae0a82 Mon Sep 17 00:00:00 2001
From d7682d1bc67ccdd63022c63b2d3229f8ab40d52b Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 12:57:21 +0100
Subject: [PATCH] Add environment variable to know if yum is invoked from
@ -9,13 +9,13 @@ Subject: [PATCH] Add environment variable to know if yum is invoked from
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
index 3f855d255f..08dccafceb 100644
index 4d0070f21a..b362d30bf4 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -965,7 +965,9 @@ def list_repo_pkgs(*args, **kwargs):
@@ -964,7 +964,9 @@ def list_repo_pkgs(*args, **kwargs):
None
if _yum() != "yum"
else _LooseVersion(
else LooseVersion(
- __salt__["cmd.run"](["yum", "--version"], python_shell=False)
+ __salt__["cmd.run"](
+ ["yum", "--version"], python_shell=False, env={"SALT_RUNNING": "1"}
@ -23,7 +23,7 @@ index 3f855d255f..08dccafceb 100644
.splitlines()[0]
.strip()
)
@@ -2433,7 +2435,9 @@ def list_holds(pattern=__HOLD_PATTERN, full=True):
@@ -2474,7 +2476,9 @@ def list_holds(pattern=__HOLD_PATTERN, full=True):
"""
_check_versionlock()
@ -34,7 +34,7 @@ index 3f855d255f..08dccafceb 100644
ret = []
for line in salt.utils.itertools.split(out, "\n"):
match = _get_hold(line, pattern=pattern, full=full)
@@ -2501,7 +2505,10 @@ def group_list():
@@ -2542,7 +2546,10 @@ def group_list():
}
out = __salt__["cmd.run_stdout"](
@ -46,7 +46,7 @@ index 3f855d255f..08dccafceb 100644
)
key = None
for line in salt.utils.itertools.split(out, "\n"):
@@ -2572,7 +2579,9 @@ def group_info(name, expand=False, ignore_groups=None):
@@ -2613,7 +2620,9 @@ def group_info(name, expand=False, ignore_groups=None):
ret[pkgtype] = set()
cmd = [_yum(), "--quiet", "groupinfo", name]
@ -57,7 +57,7 @@ index 3f855d255f..08dccafceb 100644
g_info = {}
for line in salt.utils.itertools.split(out, "\n"):
@@ -3301,7 +3310,9 @@ def download(*packages, **kwargs):
@@ -3342,7 +3351,9 @@ def download(*packages, **kwargs):
cmd = ["yumdownloader", "-q", "--destdir={}".format(CACHE_DIR)]
cmd.extend(packages)
@ -68,7 +68,7 @@ index 3f855d255f..08dccafceb 100644
ret = {}
for dld_result in os.listdir(CACHE_DIR):
if not dld_result.endswith(".rpm"):
@@ -3377,7 +3388,7 @@ def _get_patches(installed_only=False):
@@ -3418,7 +3429,7 @@ def _get_patches(installed_only=False):
patches = {}
cmd = [_yum(), "--quiet", "updateinfo", "list", "all"]
@ -78,6 +78,6 @@ index 3f855d255f..08dccafceb 100644
for line in salt.utils.itertools.split(ret, os.linesep):
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 97753443c2d782b61fd51457d13309405e8f12d8 Mon Sep 17 00:00:00 2001
From c5236dadcffc24c00181c10ac4cf56020371c538 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 18:40:40 +0100
Subject: [PATCH] Add "migrated" state and GPG key management functions
@ -28,13 +28,13 @@ Convert test to pytests
tests/pytests/unit/modules/test_yumpkg.py | 44 +-
tests/pytests/unit/modules/test_zypperpkg.py | 45 +-
tests/pytests/unit/states/test_pkgrepo.py | 448 +++++++++++++++++++
8 files changed, 1071 insertions(+), 4 deletions(-)
8 files changed, 1070 insertions(+), 5 deletions(-)
diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py
index 544143d286..21ccc2a73c 100644
index 3289f6604d..9885e9fb60 100644
--- a/salt/modules/aptpkg.py
+++ b/salt/modules/aptpkg.py
@@ -2211,7 +2211,7 @@ def _parse_repo_keys_output(cmd_ret):
@@ -2197,7 +2197,7 @@ def _parse_repo_keys_output(cmd_ret):
return ret
@ -43,7 +43,7 @@ index 544143d286..21ccc2a73c 100644
"""
.. versionadded:: 2017.7.0
@@ -2319,6 +2319,7 @@ def add_repo_key(
@@ -2305,6 +2305,7 @@ def add_repo_key(
aptkey=True,
keydir=None,
keyfile=None,
@ -51,7 +51,7 @@ index 544143d286..21ccc2a73c 100644
):
"""
.. versionadded:: 2017.7.0
@@ -2372,7 +2373,6 @@ def add_repo_key(
@@ -2358,7 +2359,6 @@ def add_repo_key(
if not salt.utils.path.which("apt-key"):
aptkey = False
cmd = ["apt-key"]
@ -60,10 +60,10 @@ index 544143d286..21ccc2a73c 100644
# If the keyid is provided or determined, check it against the existing
# repo key ids to determine whether it needs to be imported.
diff --git a/salt/modules/rpm_lowpkg.py b/salt/modules/rpm_lowpkg.py
index d65a46a703..c8e984c021 100644
index 4cd137c258..b360ec8df3 100644
--- a/salt/modules/rpm_lowpkg.py
+++ b/salt/modules/rpm_lowpkg.py
@@ -859,3 +859,154 @@ def checksum(*paths, **kwargs):
@@ -865,3 +865,154 @@ def checksum(*paths, **kwargs):
)
return ret
@ -219,10 +219,10 @@ index d65a46a703..c8e984c021 100644
+ cmd.extend(["-e", key])
+ return __salt__["cmd.retcode"](cmd) == 0
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
index 08dccafceb..46f0b1f613 100644
index b362d30bf4..b2be251a40 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -3494,3 +3494,91 @@ def services_need_restart(**kwargs):
@@ -3535,3 +3535,91 @@ def services_need_restart(**kwargs):
services.add(service)
return list(services)
@ -315,10 +315,10 @@ index 08dccafceb..46f0b1f613 100644
+ """
+ return __salt__["lowpkg.remove_gpg_key"](keyid, root)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index c2452d6dec..4e3006a8cd 100644
index 2da470bea3..318c871b37 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -3142,3 +3142,91 @@ def services_need_restart(root=None, **kwargs):
@@ -3261,3 +3261,91 @@ def services_need_restart(root=None, **kwargs):
services = zypper_output.split()
return services
@ -411,7 +411,7 @@ index c2452d6dec..4e3006a8cd 100644
+ """
+ return __salt__["lowpkg.remove_gpg_key"](keyid, root)
diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py
index 358c927695..a777fe4a96 100644
index 67a50c3ca0..c2d23f95bb 100644
--- a/salt/states/pkgrepo.py
+++ b/salt/states/pkgrepo.py
@@ -118,6 +118,7 @@ Using ``aptkey: False`` with ``keyserver`` and ``keyid``:
@ -422,7 +422,7 @@ index 358c927695..a777fe4a96 100644
import sys
import salt.utils.data
@@ -714,3 +715,209 @@ def absent(name, **kwargs):
@@ -745,3 +746,209 @@ def absent(name, **kwargs):
ret["comment"] = "Failed to remove repo {}".format(name)
return ret
@ -633,19 +633,19 @@ index 358c927695..a777fe4a96 100644
+
+ return ret
diff --git a/tests/pytests/unit/modules/test_yumpkg.py b/tests/pytests/unit/modules/test_yumpkg.py
index 99ec05b990..a495569c5d 100644
index 1354ee5d2d..45c62d793d 100644
--- a/tests/pytests/unit/modules/test_yumpkg.py
+++ b/tests/pytests/unit/modules/test_yumpkg.py
@@ -7,7 +7,7 @@ import salt.modules.rpm_lowpkg as rpm
@@ -9,7 +9,7 @@ import salt.modules.rpm_lowpkg as rpm
import salt.modules.yumpkg as yumpkg
import salt.utils.platform
from salt.exceptions import CommandExecutionError, SaltInvocationError
-from tests.support.mock import MagicMock, Mock, call, patch
+from tests.support.mock import MagicMock, Mock, call, mock_open, patch
try:
import pytest
@@ -1911,6 +1911,48 @@ def test_get_repo_with_non_existent_repo(list_repos_var):
log = logging.getLogger(__name__)
@@ -1908,6 +1908,48 @@ def test_get_repo_with_non_existent_repo(list_repos_var):
assert ret == expected, ret
@ -695,24 +695,24 @@ index 99ec05b990..a495569c5d 100644
"""
Tests that the proper CLI options are added when obsoletes=False
diff --git a/tests/pytests/unit/modules/test_zypperpkg.py b/tests/pytests/unit/modules/test_zypperpkg.py
index 70bd837c5f..351a173b81 100644
index 1e2d6ea443..91132b7277 100644
--- a/tests/pytests/unit/modules/test_zypperpkg.py
+++ b/tests/pytests/unit/modules/test_zypperpkg.py
@@ -8,7 +8,8 @@ import os
import pytest
@@ -10,8 +10,8 @@ import pytest
import salt.modules.pkg_resource as pkg_resource
import salt.modules.zypperpkg as zypper
-from salt.exceptions import CommandExecutionError
-from tests.support.mock import MagicMock, patch
+from salt.exceptions import SaltInvocationError
+from salt.exceptions import CommandExecutionError, SaltInvocationError
+from tests.support.mock import MagicMock, mock_open, patch
@pytest.fixture
@@ -211,3 +212,45 @@ def test_pkg_list_holds():
ret = zypper.list_holds()
assert len(ret) == 1
assert "bar-2:2.3.4-2.1.*" in ret
+
@@ -354,3 +354,44 @@ def test_dist_upgrade_failure():
assert exc.exception.info["changes"] == {}
assert exc.exception.info["result"]["stdout"] == zypper_output
+
+def test_get_repo_keys():
+ salt_mock = {"lowpkg.list_gpg_keys": MagicMock(return_value=True)}
@ -755,13 +755,13 @@ index 70bd837c5f..351a173b81 100644
+ assert zypper.del_repo_key(keyid="keyid", root="/mnt")
+ salt_mock["lowpkg.remove_gpg_key"].assert_called_once_with("keyid", "/mnt")
diff --git a/tests/pytests/unit/states/test_pkgrepo.py b/tests/pytests/unit/states/test_pkgrepo.py
index daa913bcc2..cbb12cfb9b 100644
index c572583d19..5f540bd245 100644
--- a/tests/pytests/unit/states/test_pkgrepo.py
+++ b/tests/pytests/unit/states/test_pkgrepo.py
@@ -51,3 +51,451 @@ def test_update_key_url():
assert ret["changes"] == {
"key_url": {"old": kwargs["key_url"], "new": changed_kwargs["key_url"]}
}
@@ -72,3 +72,451 @@ def test_managed_insecure_key():
ret["comment"]
== "Cannot have 'key_url' using http with 'allow_insecure_key' set to True"
)
+
+
+def test__normalize_repo_suse():
@ -1211,6 +1211,6 @@ index daa913bcc2..cbb12cfb9b 100644
+ "comment": "There are keys or repositories to migrate or drop",
+ }
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From e6f6b011849536c5ff9a9bdef56e900ed5a7fb1d Mon Sep 17 00:00:00 2001
From 3ef2071daf7a415f2c43e1339affe2b7cad93b3e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Thu, 28 May 2020 09:37:08 +0100
@ -9,10 +9,10 @@ Subject: [PATCH] Add publish_batch to ClearFuncs exposed methods
1 file changed, 1 insertion(+)
diff --git a/salt/master.py b/salt/master.py
index 705a1bc2fb..7f41ffe77b 100644
index 2a526b4f21..a0552fa232 100644
--- a/salt/master.py
+++ b/salt/master.py
@@ -1952,6 +1952,7 @@ class ClearFuncs(TransportMethods):
@@ -1960,6 +1960,7 @@ class ClearFuncs(TransportMethods):
expose_methods = (
"ping",
"publish",
@ -21,6 +21,6 @@ index 705a1bc2fb..7f41ffe77b 100644
"mk_token",
"wheel",
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From c683ceaf9321a646d32e3b2b5fca705563fe8e73 Mon Sep 17 00:00:00 2001
From 3fd6c0c6793632c819fb5f8fb3b3538463eaaccc Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Thu, 24 Feb 2022 16:52:24 +0300
Subject: [PATCH] Add salt-ssh support with venv-salt-minion - 3004
@ -146,7 +146,7 @@ index cc18f49a9e..e050f43caf 100644
def makeRecord(
self,
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index ad2796bc87..6db2dfcbb0 100644
index 19089ce8ad..e6837df4e5 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -6,11 +6,13 @@ import base64
@ -732,7 +732,7 @@ index 72a5e54401..32f8a7702c 100644
):
err = (
diff --git a/salt/netapi/__init__.py b/salt/netapi/__init__.py
index 7127dc2b3c..4a80697648 100644
index a89c1a19af..8a28c48460 100644
--- a/salt/netapi/__init__.py
+++ b/salt/netapi/__init__.py
@@ -79,6 +79,7 @@ class NetapiClient:
@ -743,7 +743,7 @@ index 7127dc2b3c..4a80697648 100644
def _is_master_running(self):
"""
@@ -238,7 +239,7 @@ class NetapiClient:
@@ -245,7 +246,7 @@ class NetapiClient:
with salt.client.ssh.client.SSHClient(
mopts=self.opts, disable_custom_roster=True
) as client:
@ -777,10 +777,10 @@ index fc7339d785..ea23d550d7 100644
def _gen_back(self):
"""
diff --git a/tests/unit/test_loader.py b/tests/unit/test_loader.py
index 66ba3d4e05..412d412398 100644
index cf33903320..1b616375b3 100644
--- a/tests/unit/test_loader.py
+++ b/tests/unit/test_loader.py
@@ -1696,7 +1696,7 @@ class LazyLoaderRefreshFileMappingTest(TestCase):
@@ -1697,7 +1697,7 @@ class LazyLoaderRefreshFileMappingTest(TestCase):
cls.funcs = salt.loader.minion_mods(cls.opts, utils=cls.utils, proxy=cls.proxy)
def setUp(self):
@ -790,6 +790,6 @@ index 66ba3d4e05..412d412398 100644
self.LOADER_CLASS = LazyLoaderMock
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From b772fc7540cea4088ecac0bdc0e24d2be84bfcad Mon Sep 17 00:00:00 2001
From bad9e783e1a6923d85bdb1477a2e9766887a511e Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
Date: Thu, 18 Feb 2021 14:49:38 +0300
Subject: [PATCH] Add sleep on exception handling on minion connection
@ -12,7 +12,7 @@ Subject: [PATCH] Add sleep on exception handling on minion connection
1 file changed, 6 insertions(+)
diff --git a/salt/minion.py b/salt/minion.py
index 16452facf4..780b397e83 100644
index 2f905e4a4f..c3b65f16c3 100644
--- a/salt/minion.py
+++ b/salt/minion.py
@@ -1123,6 +1123,9 @@ class MinionManager(MinionBase):
@ -36,6 +36,6 @@ index 16452facf4..780b397e83 100644
# Multi Master Tune In
def tune_in(self):
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 875fb95ae468042005cd0db463f13a9315c1e756 Mon Sep 17 00:00:00 2001
From 94e702e83c05814296ea8987a722b71e99117360 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Wed, 22 May 2019 13:00:46 +0100
@ -21,6 +21,6 @@ index 0000000000..94d05fb2ee
+ - /usr/share/salt-formulas/states
+ - /srv/salt
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From f92891c007ee55d9ccc2d7b3da53e4e0a6fc94c3 Mon Sep 17 00:00:00 2001
From 2e103365c50fe42a72de3e9d57c3fdbee47454aa Mon Sep 17 00:00:00 2001
From: Michael Calmer <mc@suse.de>
Date: Fri, 8 Jul 2022 10:15:37 +0200
Subject: [PATCH] add support for gpgautoimport (#539)
@ -18,10 +18,10 @@ Subject: [PATCH] add support for gpgautoimport (#539)
2 files changed, 140 insertions(+), 31 deletions(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index cbfbc4b78d..2c36e2968a 100644
index 318c871b37..051f8f72c7 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -589,7 +589,7 @@ def list_upgrades(refresh=True, root=None, **kwargs):
@@ -623,7 +623,7 @@ def list_upgrades(refresh=True, root=None, **kwargs):
salt '*' pkg.list_upgrades
"""
if refresh:
@ -30,7 +30,7 @@ index cbfbc4b78d..2c36e2968a 100644
ret = dict()
cmd = ["list-updates"]
@@ -703,7 +703,7 @@ def info_available(*names, **kwargs):
@@ -737,7 +737,7 @@ def info_available(*names, **kwargs):
# Refresh db before extracting the latest package
if kwargs.get("refresh", True):
@ -39,15 +39,15 @@ index cbfbc4b78d..2c36e2968a 100644
pkg_info = []
batch = names[:]
@@ -1393,7 +1393,6 @@ def mod_repo(repo, **kwargs):
cmd_opt.append("--name='{}'".format(kwargs.get("humanname")))
@@ -1439,7 +1439,6 @@ def mod_repo(repo, **kwargs):
cmd_opt.append(kwargs.get("name"))
if kwargs.get("gpgautoimport") is True:
- global_cmd_opt.append("--gpg-auto-import-keys")
call_refresh = True
if cmd_opt:
@@ -1405,8 +1404,8 @@ def mod_repo(repo, **kwargs):
@@ -1451,8 +1450,8 @@ def mod_repo(repo, **kwargs):
# when used with "zypper ar --refresh" or "zypper mr --refresh"
# --gpg-auto-import-keys is not doing anything
# so we need to specifically refresh here with --gpg-auto-import-keys
@ -58,7 +58,7 @@ index cbfbc4b78d..2c36e2968a 100644
elif not added and not cmd_opt:
comment = "Specified arguments did not result in modification of repo"
@@ -1417,7 +1416,7 @@ def mod_repo(repo, **kwargs):
@@ -1463,7 +1462,7 @@ def mod_repo(repo, **kwargs):
return repo
@ -67,7 +67,7 @@ index cbfbc4b78d..2c36e2968a 100644
"""
Trigger a repository refresh by calling ``zypper refresh``. Refresh will run
with ``--force`` if the "force=True" flag is passed on the CLI or
@@ -1428,6 +1427,17 @@ def refresh_db(force=None, root=None):
@@ -1474,6 +1473,17 @@ def refresh_db(force=None, root=None):
{'<database name>': Bool}
@ -85,7 +85,7 @@ index cbfbc4b78d..2c36e2968a 100644
root
operate on a different root directory.
@@ -1448,11 +1458,22 @@ def refresh_db(force=None, root=None):
@@ -1494,11 +1504,22 @@ def refresh_db(force=None, root=None):
salt.utils.pkg.clear_rtag(__opts__)
ret = {}
refresh_opts = ["refresh"]
@ -109,7 +109,7 @@ index cbfbc4b78d..2c36e2968a 100644
for line in out.splitlines():
if not line:
@@ -1637,7 +1658,7 @@ def install(
@@ -1683,7 +1704,7 @@ def install(
'arch': '<new-arch>'}}}
"""
if refresh:
@ -118,7 +118,7 @@ index cbfbc4b78d..2c36e2968a 100644
try:
pkg_params, pkg_type = __salt__["pkg_resource.parse_targets"](
@@ -1932,7 +1953,7 @@ def upgrade(
@@ -1980,7 +2001,7 @@ def upgrade(
cmd_update.insert(0, "--no-gpg-checks")
if refresh:
@ -127,7 +127,7 @@ index cbfbc4b78d..2c36e2968a 100644
if dryrun:
cmd_update.append("--dry-run")
@@ -2759,7 +2780,7 @@ def search(criteria, refresh=False, **kwargs):
@@ -2808,7 +2829,7 @@ def search(criteria, refresh=False, **kwargs):
root = kwargs.get("root", None)
if refresh:
@ -136,7 +136,7 @@ index cbfbc4b78d..2c36e2968a 100644
cmd = ["search"]
if kwargs.get("match") == "exact":
@@ -2910,7 +2931,7 @@ def download(*packages, **kwargs):
@@ -2959,7 +2980,7 @@ def download(*packages, **kwargs):
refresh = kwargs.get("refresh", False)
if refresh:
@ -145,7 +145,7 @@ index cbfbc4b78d..2c36e2968a 100644
pkg_ret = {}
for dld_result in (
@@ -3062,7 +3083,7 @@ def list_patches(refresh=False, root=None, **kwargs):
@@ -3111,7 +3132,7 @@ def list_patches(refresh=False, root=None, **kwargs):
salt '*' pkg.list_patches
"""
if refresh:
@ -154,7 +154,7 @@ index cbfbc4b78d..2c36e2968a 100644
return _get_patches(root=root)
@@ -3156,7 +3177,7 @@ def resolve_capabilities(pkgs, refresh=False, root=None, **kwargs):
@@ -3205,7 +3226,7 @@ def resolve_capabilities(pkgs, refresh=False, root=None, **kwargs):
salt '*' pkg.resolve_capabilities resolve_capabilities=True w3m_ssl
"""
if refresh:
@ -164,10 +164,10 @@ index cbfbc4b78d..2c36e2968a 100644
ret = list()
for pkg in pkgs:
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
index fea6eeb004..3f1560a385 100644
index e85c93da3b..f5b6d74b6f 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -358,7 +358,12 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -377,7 +377,12 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
run_out = {"stderr": "", "stdout": "\n".join(ref_out), "retcode": 0}
zypper_mock = MagicMock(return_value=run_out)
@ -181,7 +181,7 @@ index fea6eeb004..3f1560a385 100644
with patch.dict(zypper.__salt__, {"cmd.run_all": zypper_mock}):
with patch.object(salt.utils.pkg, "clear_rtag", Mock()):
result = zypper.refresh_db()
@@ -376,6 +381,73 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -395,6 +400,73 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
zypper_mock.assert_called_with(
["zypper", "--non-interactive", "refresh", "--force"], **call_kwargs
)
@ -255,7 +255,7 @@ index fea6eeb004..3f1560a385 100644
def test_info_installed(self):
"""
@@ -1555,18 +1627,23 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -2082,18 +2154,23 @@ Repository 'DUMMY' not found by its alias, number, or URI.
url = self.new_repo_config["url"]
name = self.new_repo_config["name"]
@ -281,7 +281,7 @@ index fea6eeb004..3f1560a385 100644
def test_repo_noadd_nomod_ref(self):
"""
@@ -1585,15 +1662,17 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -2112,15 +2189,17 @@ Repository 'DUMMY' not found by its alias, number, or URI.
"salt.modules.zypperpkg", **self.zypper_patcher_config
)
@ -304,7 +304,7 @@ index fea6eeb004..3f1560a385 100644
def test_repo_add_mod_ref(self):
"""
@@ -1606,10 +1685,10 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -2133,10 +2212,10 @@ Repository 'DUMMY' not found by its alias, number, or URI.
zypper_patcher = patch.multiple(
"salt.modules.zypperpkg", **self.zypper_patcher_config
)
@ -317,7 +317,7 @@ index fea6eeb004..3f1560a385 100644
zypper.mod_repo(
name, **{"url": url, "refresh": True, "gpgautoimport": True}
)
@@ -1617,11 +1696,17 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -2144,11 +2223,17 @@ Repository 'DUMMY' not found by its alias, number, or URI.
zypper.__zypper__(root=None).xml.call.call_args_list,
[
call("ar", url, name),
@ -337,7 +337,7 @@ index fea6eeb004..3f1560a385 100644
)
def test_repo_noadd_mod_ref(self):
@@ -1641,16 +1726,19 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -2168,16 +2253,19 @@ Repository 'DUMMY' not found by its alias, number, or URI.
"salt.modules.zypperpkg", **self.zypper_patcher_config
)
@ -364,6 +364,6 @@ index fea6eeb004..3f1560a385 100644
def test_wildcard_to_query_match_all(self):
--
2.37.3
2.39.2

File diff suppressed because it is too large Load Diff

View File

@ -1,124 +0,0 @@
From d1e9af256fa67cd792ce11e6e9c1e24a1fe2054f Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <Victor.Zhestkov@suse.com>
Date: Fri, 28 Oct 2022 13:19:46 +0300
Subject: [PATCH] Align Amazon EC2 (Nitro) grains with upstream PR
(bsc#1203685)
* Set virtual to Nitro for Amazon EC2 kvm instances
* Add few mocks to prevent false failing
possible in some specific environments
* Add one more possible test case returning Nitro
---
salt/grains/core.py | 8 +++++++-
tests/pytests/unit/grains/test_core.py | 27 +++++++++++++++++++++++++-
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/salt/grains/core.py b/salt/grains/core.py
index 76f3767ddf..f359c07432 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -860,6 +860,10 @@ def _virtual(osdata):
grains["virtual"] = "container"
grains["virtual_subtype"] = "LXC"
break
+ elif "amazon" in output:
+ grains["virtual"] = "Nitro"
+ grains["virtual_subtype"] = "Amazon EC2"
+ break
elif command == "virt-what":
for line in output.splitlines():
if line in ("kvm", "qemu", "uml", "xen"):
@@ -1174,7 +1178,7 @@ def _virtual(osdata):
grains["virtual"] = "virtual"
# Try to detect if the instance is running on Amazon EC2
- if grains["virtual"] in ("qemu", "kvm", "xen"):
+ if grains["virtual"] in ("qemu", "kvm", "xen", "amazon"):
dmidecode = salt.utils.path.which("dmidecode")
if dmidecode:
ret = __salt__["cmd.run_all"](
@@ -1182,6 +1186,8 @@ def _virtual(osdata):
)
output = ret["stdout"]
if "Manufacturer: Amazon EC2" in output:
+ if grains["virtual"] != "xen":
+ grains["virtual"] = "Nitro"
grains["virtual_subtype"] = "Amazon EC2"
product = re.match(
r".*Product Name: ([^\r\n]*).*", output, flags=re.DOTALL
diff --git a/tests/pytests/unit/grains/test_core.py b/tests/pytests/unit/grains/test_core.py
index c06cdb2db0..6f3bef69f2 100644
--- a/tests/pytests/unit/grains/test_core.py
+++ b/tests/pytests/unit/grains/test_core.py
@@ -2888,6 +2888,11 @@ def test_virtual_set_virtual_ec2():
"/usr/bin/systemd-detect-virt",
None,
None,
+ # Check with systemd-detect-virt returning amazon and no dmidecode available
+ None,
+ "/usr/bin/systemd-detect-virt",
+ None,
+ None,
]
)
cmd_run_all_mock = MagicMock(
@@ -2946,9 +2951,22 @@ def test_virtual_set_virtual_ec2():
},
# Check with systemd-detect-virt when no dmidecode available
{"retcode": 0, "stderr": "", "stdout": "kvm"},
+ # Check with systemd-detect-virt returning amazon and no dmidecode available
+ {"retcode": 0, "stderr": "", "stdout": "amazon"},
]
)
+ def _mock_is_file(filename):
+ if filename in (
+ "/proc/1/cgroup",
+ "/proc/cpuinfo",
+ "/sys/devices/virtual/dmi/id/product_name",
+ "/proc/xen/xsd_kva",
+ "/proc/xen/capabilities",
+ ):
+ return False
+ return True
+
with patch("salt.utils.path.which", which_mock), patch.dict(
core.__salt__,
{
@@ -2957,6 +2975,8 @@ def test_virtual_set_virtual_ec2():
"cmd.retcode": salt.modules.cmdmod.retcode,
"smbios.get": salt.modules.smbios.get,
},
+ ), patch("os.path.isfile", _mock_is_file), patch(
+ "os.path.isdir", return_value=False
):
virtual_grains = core._virtual(osdata.copy())
@@ -2966,7 +2986,7 @@ def test_virtual_set_virtual_ec2():
virtual_grains = core._virtual(osdata.copy())
- assert virtual_grains["virtual"] == "kvm"
+ assert virtual_grains["virtual"] == "Nitro"
assert virtual_grains["virtual_subtype"] == "Amazon EC2 (m5.large)"
virtual_grains = core._virtual(osdata.copy())
@@ -2974,6 +2994,11 @@ def test_virtual_set_virtual_ec2():
assert virtual_grains["virtual"] == "kvm"
assert "virtual_subtype" not in virtual_grains
+ virtual_grains = core._virtual(osdata.copy())
+
+ assert virtual_grains["virtual"] == "Nitro"
+ assert virtual_grains["virtual_subtype"] == "Amazon EC2"
+
@pytest.mark.skip_on_windows
def test_linux_proc_files_with_non_utf8_chars():
--
2.37.3

View File

@ -1,151 +0,0 @@
From 6dc653b0cf8e6e043e13bea7009ded604ceb7b71 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Thu, 12 Jan 2023 15:43:56 +0000
Subject: [PATCH] Allow entrypoint compatibility for
importlib-metadata>=5.0.0 (#572)
add tests and make sure the compat code is in an else :)
changelog
switch to try/except
Co-authored-by: MKLeb <calebb@vmware.com>
---
changelog/62854.fixed | 1 +
salt/utils/entrypoints.py | 15 +++--
.../pytests/functional/loader/test_loader.py | 67 +++++++++++++++++--
3 files changed, 74 insertions(+), 9 deletions(-)
create mode 100644 changelog/62854.fixed
diff --git a/changelog/62854.fixed b/changelog/62854.fixed
new file mode 100644
index 0000000000..13e6df4fe3
--- /dev/null
+++ b/changelog/62854.fixed
@@ -0,0 +1 @@
+Use select instead of iterating over entrypoints as a dictionary for importlib_metadata>=5.0.0
diff --git a/salt/utils/entrypoints.py b/salt/utils/entrypoints.py
index 3effa0b494..9452878ade 100644
--- a/salt/utils/entrypoints.py
+++ b/salt/utils/entrypoints.py
@@ -38,13 +38,20 @@ def iter_entry_points(group, name=None):
entry_points_listing = []
entry_points = importlib_metadata.entry_points()
- for entry_point_group, entry_points_list in entry_points.items():
- if entry_point_group != group:
- continue
- for entry_point in entry_points_list:
+ try:
+ for entry_point in entry_points.select(group=group):
if name is not None and entry_point.name != name:
continue
entry_points_listing.append(entry_point)
+ except AttributeError:
+ # importlib-metadata<5.0.0
+ for entry_point_group, entry_points_list in entry_points.items():
+ if entry_point_group != group:
+ continue
+ for entry_point in entry_points_list:
+ if name is not None and entry_point.name != name:
+ continue
+ entry_points_listing.append(entry_point)
return entry_points_listing
diff --git a/tests/pytests/functional/loader/test_loader.py b/tests/pytests/functional/loader/test_loader.py
index 6dfd97b0e6..a13d90d5eb 100644
--- a/tests/pytests/functional/loader/test_loader.py
+++ b/tests/pytests/functional/loader/test_loader.py
@@ -1,5 +1,4 @@
import json
-import sys
import pytest
import salt.utils.versions
@@ -143,10 +142,6 @@ def test_utils_loader_does_not_load_extensions(
assert "foobar.echo" not in loader_functions
-@pytest.mark.skipif(
- sys.version_info < (3, 6),
- reason="importlib-metadata>=3.3.0 does not exist for Py3.5",
-)
def test_extension_discovery_without_reload_with_importlib_metadata_installed(
venv, salt_extension, salt_minion_factory
):
@@ -209,6 +204,68 @@ def test_extension_discovery_without_reload_with_importlib_metadata_installed(
assert "foobar.echo2" in loader_functions
+def test_extension_discovery_without_reload_with_importlib_metadata_5_installed(
+ venv, salt_extension, salt_minion_factory
+):
+ # Install our extension into the virtualenv
+ installed_packages = venv.get_installed_packages()
+ assert salt_extension.name not in installed_packages
+ venv.install("importlib-metadata>=3.3.0")
+ code = """
+ import sys
+ import json
+ import subprocess
+ import salt._logging
+ import salt.loader
+
+ extension_path = "{}"
+
+ minion_config = json.loads(sys.stdin.read())
+ salt._logging.set_logging_options_dict(minion_config)
+ salt._logging.setup_logging()
+ loader = salt.loader.minion_mods(minion_config)
+
+ if "foobar.echo1" in loader:
+ sys.exit(1)
+
+ # Install the extension
+ proc = subprocess.run(
+ [sys.executable, "-m", "pip", "install", extension_path],
+ check=False,
+ shell=False,
+ stdout=subprocess.PIPE,
+ )
+ if proc.returncode != 0:
+ sys.exit(2)
+
+ loader = salt.loader.minion_mods(minion_config)
+ if "foobar.echo1" not in loader:
+ sys.exit(3)
+
+ print(json.dumps(list(loader)))
+ """.format(
+ salt_extension.srcdir
+ )
+ ret = venv.run_code(
+ code, input=json.dumps(salt_minion_factory.config.copy()), check=False
+ )
+ # Exitcode 1 - Extension was already installed
+ # Exitcode 2 - Failed to install the extension
+ # Exitcode 3 - Extension was not found within the same python process after being installed
+ assert ret.returncode == 0
+ installed_packages = venv.get_installed_packages()
+ assert salt_extension.name in installed_packages
+
+ loader_functions = json.loads(ret.stdout)
+
+ # A non existing module should not appear in the loader
+ assert "monty.python" not in loader_functions
+
+ # But our extension's modules should appear on the loader
+ assert "foobar.echo1" in loader_functions
+ assert "foobar.echo2" in loader_functions
+
+
def test_extension_discovery_without_reload_with_bundled_importlib_metadata(
venv, salt_extension, salt_minion_factory
):
--
2.37.3

View File

@ -1,4 +1,4 @@
From 51836a4c37f05262e708f058f323c1fbc2123ade Mon Sep 17 00:00:00 2001
From a36d6524e530eca32966f46597c88dbfd4b90e78 Mon Sep 17 00:00:00 2001
From: Martin Seidl <mseidl@suse.de>
Date: Tue, 27 Oct 2020 16:12:29 +0100
Subject: [PATCH] Allow vendor change option with zypper
@ -59,15 +59,15 @@ Co-authored-by: Pablo Suárez Hernández <psuarezhernandez@suse.com>
Co-authored-by: Jochen Breuer <jbreuer@suse.de>
Co-authored-by: Pablo Suárez Hernández <psuarezhernandez@suse.com>
---
salt/modules/zypperpkg.py | 105 +++++--
tests/unit/modules/test_zypperpkg.py | 418 ++++++++++++++++++++++++---
2 files changed, 462 insertions(+), 61 deletions(-)
salt/modules/zypperpkg.py | 105 ++++--
tests/unit/modules/test_zypperpkg.py | 532 ++++++++++++++++++++++++++-
2 files changed, 612 insertions(+), 25 deletions(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index 6b19c65db3..c2452d6dec 100644
index 4bb10f445a..2da470bea3 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -35,6 +35,8 @@ import salt.utils.stringutils
@@ -36,6 +36,8 @@ import salt.utils.stringutils
import salt.utils.systemd
import salt.utils.versions
from salt.exceptions import CommandExecutionError, MinionError, SaltInvocationError
@ -75,8 +75,8 @@ index 6b19c65db3..c2452d6dec 100644
+# pylint: disable=import-error,redefined-builtin,no-name-in-module
from salt.utils.versions import LooseVersion
log = logging.getLogger(__name__)
@@ -135,6 +137,13 @@ class _Zypper:
if salt.utils.files.is_fcntl_available():
@@ -140,6 +142,13 @@ class _Zypper:
self.__systemd_scope = False
self.__root = None
@ -90,7 +90,7 @@ index 6b19c65db3..c2452d6dec 100644
# Call status
self.__called = False
@@ -179,6 +188,8 @@ class _Zypper:
@@ -184,6 +193,8 @@ class _Zypper:
self.__no_raise = True
elif item == "refreshable":
self.__refresh = True
@ -99,7 +99,7 @@ index 6b19c65db3..c2452d6dec 100644
elif item == "call":
return self.__call
else:
@@ -219,6 +230,33 @@ class _Zypper:
@@ -224,6 +235,33 @@ class _Zypper:
def pid(self):
return self.__call_result.get("pid", "")
@ -133,7 +133,7 @@ index 6b19c65db3..c2452d6dec 100644
def _is_error(self):
"""
Is this is an error code?
@@ -335,6 +373,15 @@ class _Zypper:
@@ -362,6 +400,15 @@ class _Zypper:
if self.__systemd_scope:
cmd.extend(["systemd-run", "--scope"])
cmd.extend(self.__cmd)
@ -149,7 +149,7 @@ index 6b19c65db3..c2452d6dec 100644
log.debug("Calling Zypper: %s", " ".join(cmd))
self.__call_result = __salt__["cmd.run_all"](cmd, **kwargs)
if self._check_result():
@@ -1444,6 +1491,8 @@ def install(
@@ -1490,6 +1537,8 @@ def install(
no_recommends=False,
root=None,
inclusion_detection=False,
@ -158,7 +158,7 @@ index 6b19c65db3..c2452d6dec 100644
**kwargs
):
"""
@@ -1491,6 +1540,13 @@ def install(
@@ -1537,6 +1586,13 @@ def install(
skip_verify
Skip the GPG verification check (e.g., ``--no-gpg-checks``)
@ -172,7 +172,7 @@ index 6b19c65db3..c2452d6dec 100644
version
Can be either a version number, or the combination of a comparison
operator (<, >, <=, >=, =) and a version number (ex. '>1.2.3-4').
@@ -1656,6 +1712,7 @@ def install(
@@ -1702,6 +1758,7 @@ def install(
cmd_install.append(
kwargs.get("resolve_capabilities") and "--capability" or "--name"
)
@ -180,7 +180,7 @@ index 6b19c65db3..c2452d6dec 100644
if not refresh:
cmd_install.insert(0, "--no-refresh")
@@ -1692,6 +1749,7 @@ def install(
@@ -1738,6 +1795,7 @@ def install(
systemd_scope=systemd_scope,
root=root,
)
@ -188,7 +188,7 @@ index 6b19c65db3..c2452d6dec 100644
.call(*cmd)
.splitlines()
):
@@ -1704,7 +1762,9 @@ def install(
@@ -1750,7 +1808,9 @@ def install(
while downgrades:
cmd = cmd_install + ["--force"] + downgrades[:500]
downgrades = downgrades[500:]
@ -199,7 +199,7 @@ index 6b19c65db3..c2452d6dec 100644
_clean_cache()
new = (
@@ -1735,7 +1795,8 @@ def upgrade(
@@ -1783,7 +1843,8 @@ def upgrade(
dryrun=False,
dist_upgrade=False,
fromrepo=None,
@ -209,7 +209,7 @@ index 6b19c65db3..c2452d6dec 100644
skip_verify=False,
no_recommends=False,
root=None,
@@ -1774,7 +1835,11 @@ def upgrade(
@@ -1844,7 +1905,11 @@ def upgrade(
Specify a list of package repositories to upgrade from. Default: None
novendorchange
@ -222,7 +222,7 @@ index 6b19c65db3..c2452d6dec 100644
skip_verify
Skip the GPG verification check (e.g., ``--no-gpg-checks``)
@@ -1821,31 +1886,21 @@ def upgrade(
@@ -1927,28 +1992,18 @@ def upgrade(
cmd_update.extend(["--from" if dist_upgrade else "--repo", repo])
log.info("Targeting repos: %s", fromrepo)
@ -236,20 +236,13 @@ index 6b19c65db3..c2452d6dec 100644
- log.warning(
- "Disabling vendor changes is not supported on this Zypper version"
- )
-
- if no_recommends:
- cmd_update.append("--no-recommends")
- log.info("Disabling recommendations")
+ if no_recommends:
+ cmd_update.append("--no-recommends")
+ log.info("Disabling recommendations")
- if dryrun:
- # Creates a solver test case for debugging.
- log.info("Executing debugsolver and performing a dry-run dist-upgrade")
- __zypper__(systemd_scope=_systemd_scope(), root=root).noraise.call(
- *cmd_update + ["--debug-solver"]
- )
- if no_recommends:
- cmd_update.append("--no-recommends")
- log.info("Disabling recommendations")
+ if dryrun:
+ # Creates a solver test case for debugging.
+ log.info("Executing debugsolver and performing a dry-run dist-upgrade")
@ -257,20 +250,33 @@ index 6b19c65db3..c2452d6dec 100644
+ allowvendorchange, novendorchange
+ ).noraise.call(*cmd_update + ["--debug-solver"])
old = list_pkgs(root=root)
-
- if dryrun:
- # Creates a solver test case for debugging.
- log.info("Executing debugsolver and performing a dry-run dist-upgrade")
- __zypper__(systemd_scope=_systemd_scope(), root=root).noraise.call(
- *cmd_update + ["--debug-solver"]
- )
- else:
+ if not dist_upgrade:
if name or pkgs:
try:
(pkg_params, _) = __salt__["pkg_resource.parse_targets"](
@@ -1962,7 +2017,9 @@ def upgrade(
old = list_pkgs(root=root, attr=diff_attr)
- __zypper__(systemd_scope=_systemd_scope(), root=root).noraise.call(*cmd_update)
+ __zypper__(systemd_scope=_systemd_scope(), root=root).allow_vendor_change(
+ allowvendorchange, novendorchange
+ ).noraise.call(*cmd_update)
_clean_cache()
new = list_pkgs(root=root)
new = list_pkgs(root=root, attr=diff_attr)
ret = salt.utils.data.compare_dicts(old, new)
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
index 671adc2779..39f28f2198 100644
index 5e4c967520..e85c93da3b 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -135,6 +135,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -137,6 +137,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
stdout_xml_snippet = '<?xml version="1.0"?><test foo="bar"/>'
sniffer = RunSniffer(stdout=stdout_xml_snippet)
@ -278,7 +284,7 @@ index 671adc2779..39f28f2198 100644
with patch.dict("salt.modules.zypperpkg.__salt__", {"cmd.run_all": sniffer}):
self.assertEqual(zypper.__zypper__.call("foo"), stdout_xml_snippet)
self.assertEqual(len(sniffer.calls), 1)
@@ -609,13 +610,373 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -628,13 +629,495 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
{"vim": "7.4.326-2.62", "fakepkg": ""},
)
@ -642,38 +648,112 @@ index 671adc2779..39f28f2198 100644
+ )
+ zypper.__zypper__.avc = False
+
def test_upgrade_success(self):
"""
Test system upgrade and dist-upgrade success.
:return:
"""
- with patch.dict(zypper.__grains__, {"osrelease_info": [12, 1]}), patch(
+ def test_upgrade_success(self):
+ """
+ Test system upgrade and dist-upgrade success.
+
+ :return:
+ """
+ with patch(
"salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)
), patch(
"salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False)
@@ -654,16 +1015,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.1,1.2"}})
zypper_mock.assert_any_call("update", "--auto-agree-with-licenses")
- with patch(
- "salt.modules.zypperpkg.list_pkgs",
- MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.2"}]),
- ):
- ret = zypper.upgrade(dist_upgrade=True)
- self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}})
- zypper_mock.assert_any_call(
- "dist-upgrade", "--auto-agree-with-licenses"
- )
-
with patch(
"salt.modules.zypperpkg.list_pkgs",
MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
@@ -679,6 +1030,22 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
"--debug-solver",
)
+ "salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)
+ ), patch(
+ "salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False)
+ ):
+ with patch(
+ "salt.modules.zypperpkg.__zypper__.noraise.call", MagicMock()
+ ) as zypper_mock:
+ with patch(
+ "salt.modules.zypperpkg.list_pkgs",
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.2"}]),
+ ):
+ ret = zypper.upgrade()
+ self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}})
+ zypper_mock.assert_any_call("update", "--auto-agree-with-licenses")
+
+ with patch(
+ "salt.modules.zypperpkg.list_pkgs",
+ MagicMock(
+ side_effect=[
+ {"kernel-default": "1.1"},
+ {"kernel-default": "1.1,1.2"},
+ ]
+ ),
+ ):
+ ret = zypper.upgrade()
+ self.assertDictEqual(
+ ret, {"kernel-default": {"old": "1.1", "new": "1.1,1.2"}}
+ )
+ zypper_mock.assert_any_call("update", "--auto-agree-with-licenses")
+
+ with patch(
+ "salt.modules.zypperpkg.list_pkgs",
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1,1.2"}]),
+ ):
+ ret = zypper.upgrade()
+ self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.1,1.2"}})
+ zypper_mock.assert_any_call("update", "--auto-agree-with-licenses")
+
+ with patch(
+ "salt.modules.zypperpkg.list_pkgs",
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
+ ):
+ ret = zypper.upgrade(dist_upgrade=True, dryrun=True)
+ zypper_mock.assert_any_call(
+ "dist-upgrade", "--auto-agree-with-licenses", "--dry-run"
+ )
+ zypper_mock.assert_any_call(
+ "dist-upgrade",
+ "--auto-agree-with-licenses",
+ "--dry-run",
+ "--debug-solver",
+ )
+
+ with patch(
+ "salt.modules.zypperpkg.list_pkgs",
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
+ ):
+ ret = zypper.upgrade(
+ dist_upgrade=False, fromrepo=["Dummy", "Dummy2"], dryrun=False
+ )
+ zypper_mock.assert_any_call(
+ "update",
+ "--auto-agree-with-licenses",
+ "--repo",
+ "Dummy",
+ "--repo",
+ "Dummy2",
+ )
+
+ with patch(
+ "salt.modules.zypperpkg.list_pkgs",
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
+ ):
+ ret = zypper.upgrade(
+ dist_upgrade=True,
+ dryrun=True,
+ fromrepo=["Dummy", "Dummy2"],
+ novendorchange=True,
+ )
+ zypper_mock.assert_any_call(
+ "dist-upgrade",
+ "--auto-agree-with-licenses",
+ "--dry-run",
+ "--from",
+ "Dummy",
+ "--from",
+ "Dummy2",
+ )
+ zypper_mock.assert_any_call(
+ "dist-upgrade",
+ "--auto-agree-with-licenses",
+ "--dry-run",
+ "--from",
+ "Dummy",
+ "--from",
+ "Dummy2",
+ "--debug-solver",
+ )
+
+ with patch(
+ "salt.modules.zypperpkg.list_pkgs",
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
@ -690,49 +770,6 @@ index 671adc2779..39f28f2198 100644
+ "Dummy2",
+ )
+
with patch(
"salt.modules.zypperpkg.list_pkgs",
MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
@@ -697,7 +1064,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
"Dummy",
"--from",
"Dummy2",
- "--no-allow-vendor-change",
)
zypper_mock.assert_any_call(
"dist-upgrade",
@@ -707,7 +1073,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
"Dummy",
"--from",
"Dummy2",
- "--no-allow-vendor-change",
"--debug-solver",
)
@@ -727,33 +1092,13 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
"Dummy2",
)
- with patch(
- "salt.modules.zypperpkg.list_pkgs",
- MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.2"}]),
- ):
- ret = zypper.upgrade(
- dist_upgrade=True,
- fromrepo=["Dummy", "Dummy2"],
- novendorchange=True,
- )
- self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}})
- zypper_mock.assert_any_call(
- "dist-upgrade",
- "--auto-agree-with-licenses",
- "--from",
- "Dummy",
- "--from",
- "Dummy2",
- "--no-allow-vendor-change",
- )
-
def test_upgrade_kernel(self):
"""
Test kernel package upgrade success.
@ -744,31 +781,61 @@ index 671adc2779..39f28f2198 100644
"salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)
), patch(
"salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False)
@@ -812,12 +1157,13 @@ Repository 'DUMMY' not found by its alias, number, or URI.
self.pid = 1234
self.exit_code = 555
self.noraise = MagicMock()
@@ -672,6 +1155,53 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
},
)
+ def test_upgrade_failure(self):
+ """
+ Test system upgrade failure.
+
+ :return:
+ """
+ zypper_out = """
+Loading repository data...
+Reading installed packages...
+Computing distribution upgrade...
+Use 'zypper repos' to get the list of defined repositories.
+Repository 'DUMMY' not found by its alias, number, or URI.
+"""
+
+ class FailingZypperDummy:
+ def __init__(self):
+ self.stdout = zypper_out
+ self.stderr = ""
+ self.pid = 1234
+ self.exit_code = 555
+ self.noraise = MagicMock()
+ self.allow_vendor_change = self
self.SUCCESS_EXIT_CODES = [0]
def __call__(self, *args, **kwargs):
return self
- with patch.dict(zypper.__grains__, {"osrelease_info": [12, 1]}), patch(
+ self.SUCCESS_EXIT_CODES = [0]
+
+ def __call__(self, *args, **kwargs):
+ return self
+
+ with patch(
"salt.modules.zypperpkg.__zypper__", FailingZypperDummy()
) as zypper_mock, patch(
"salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)
@@ -834,7 +1180,7 @@ Repository 'DUMMY' not found by its alias, number, or URI.
self.assertEqual(cmd_exc.exception.info["changes"], {})
self.assertEqual(cmd_exc.exception.info["result"]["stdout"], zypper_out)
zypper_mock.noraise.call.assert_called_with(
- "dist-upgrade", "--auto-agree-with-licenses", "--from", "DUMMY"
+ "salt.modules.zypperpkg.__zypper__", FailingZypperDummy()
+ ) as zypper_mock, patch(
+ "salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)
+ ), patch(
+ "salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False)
+ ):
+ zypper_mock.noraise.call = MagicMock()
+ with patch(
+ "salt.modules.zypperpkg.list_pkgs",
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
+ ):
+ with self.assertRaises(CommandExecutionError) as cmd_exc:
+ ret = zypper.upgrade(dist_upgrade=True, fromrepo=["DUMMY"])
+ self.assertEqual(cmd_exc.exception.info["changes"], {})
+ self.assertEqual(cmd_exc.exception.info["result"]["stdout"], zypper_out)
+ zypper_mock.noraise.call.assert_called_with(
+ "dist-upgrade", "--auto-agree-with-licenses", "--from", "DUMMY",
)
+ )
+
def test_upgrade_available(self):
"""
Test whether or not an upgrade is available for a given package.
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From f16fb8885eeddad179be9e2290d1523cb8f82641 Mon Sep 17 00:00:00 2001
From 76e69d9ef729365db1b0f1798f5f8a038d2065fc Mon Sep 17 00:00:00 2001
From: Mihai Dinca <mdinca@suse.de>
Date: Fri, 16 Nov 2018 17:05:29 +0100
Subject: [PATCH] Async batch implementation
@ -71,21 +71,21 @@ Async batch implementation fix (#320)
Remove deprecated usage of NO_MOCK and NO_MOCK_REASON
---
salt/auth/__init__.py | 2 +
salt/cli/batch.py | 109 ++++++--
salt/cli/batch_async.py | 315 +++++++++++++++++++++
salt/cli/support/profiles/__init__.py | 5 +-
salt/client/__init__.py | 51 +---
salt/master.py | 20 ++
salt/transport/ipc.py | 9 +-
salt/utils/event.py | 8 +-
tests/unit/cli/test_batch_async.py | 386 ++++++++++++++++++++++++++
9 files changed, 841 insertions(+), 64 deletions(-)
salt/auth/__init__.py | 2 +
salt/cli/batch.py | 109 ++++--
salt/cli/batch_async.py | 315 +++++++++++++++++
salt/cli/support/profiles/__init__.py | 5 +-
salt/client/__init__.py | 45 +--
salt/master.py | 20 ++
salt/transport/ipc.py | 9 +-
salt/utils/event.py | 8 +-
tests/pytests/unit/cli/test_batch_async.py | 386 +++++++++++++++++++++
9 files changed, 841 insertions(+), 58 deletions(-)
create mode 100644 salt/cli/batch_async.py
create mode 100644 tests/unit/cli/test_batch_async.py
create mode 100644 tests/pytests/unit/cli/test_batch_async.py
diff --git a/salt/auth/__init__.py b/salt/auth/__init__.py
index 0c64755235..8dc096d9c5 100644
index 331baab211..b0f0c0ac6c 100644
--- a/salt/auth/__init__.py
+++ b/salt/auth/__init__.py
@@ -49,6 +49,8 @@ AUTH_INTERNAL_KEYWORDS = frozenset(
@ -581,21 +581,12 @@ index b86aef30b8..4ae6d07b13 100644
-'''
+"""
diff --git a/salt/client/__init__.py b/salt/client/__init__.py
index eaf156e060..2427516ca1 100644
index 7ce8963b8f..bcda56c9b4 100644
--- a/salt/client/__init__.py
+++ b/salt/client/__init__.py
@@ -586,47 +586,23 @@ class LocalClient:
{'dave': {...}}
{'stewart': {...}}
"""
- # We need to re-import salt.utils.args here
- # even though it has already been imported.
- # when cmd_batch is called via the NetAPI
- # the module is unavailable.
- import salt.utils.args
-
# Late import - not used anywhere else in this file
@@ -594,38 +594,20 @@ class LocalClient:
import salt.cli.batch
import salt.utils.args
- arg = salt.utils.args.condition_input(arg, kwarg)
- opts = {
@ -645,7 +636,7 @@ index eaf156e060..2427516ca1 100644
batch = salt.cli.batch.Batch(opts, eauth=eauth, quiet=True)
for ret, _ in batch.run():
yield ret
@@ -1819,6 +1795,7 @@ class LocalClient:
@@ -1826,6 +1808,7 @@ class LocalClient:
"key": self.key,
"tgt_type": tgt_type,
"ret": ret,
@ -654,7 +645,7 @@ index eaf156e060..2427516ca1 100644
}
diff --git a/salt/master.py b/salt/master.py
index 9c06a52c1c..705a1bc2fb 100644
index 9d2239bffb..2a526b4f21 100644
--- a/salt/master.py
+++ b/salt/master.py
@@ -19,6 +19,7 @@ import time
@ -665,7 +656,7 @@ index 9c06a52c1c..705a1bc2fb 100644
import salt.client
import salt.client.ssh.client
import salt.crypt
@@ -2145,6 +2146,22 @@ class ClearFuncs(TransportMethods):
@@ -2153,6 +2154,22 @@ class ClearFuncs(TransportMethods):
return False
return self.loadauth.get_tok(clear_load["token"])
@ -688,7 +679,7 @@ index 9c06a52c1c..705a1bc2fb 100644
def publish(self, clear_load):
"""
This method sends out publications to the minions, it can only be used
@@ -2264,6 +2281,9 @@ class ClearFuncs(TransportMethods):
@@ -2297,6 +2314,9 @@ class ClearFuncs(TransportMethods):
),
},
}
@ -734,10 +725,10 @@ index ca13a498e3..3a3f0c7a5f 100644
def close(self):
"""
diff --git a/salt/utils/event.py b/salt/utils/event.py
index d14b9ada40..e8d1aaa5f5 100644
index a07ad513b1..869e12a140 100644
--- a/salt/utils/event.py
+++ b/salt/utils/event.py
@@ -944,6 +944,10 @@ class SaltEvent:
@@ -946,6 +946,10 @@ class SaltEvent:
# Minion fired a bad retcode, fire an event
self._fire_ret_load_specific_fun(load)
@ -748,7 +739,7 @@ index d14b9ada40..e8d1aaa5f5 100644
def set_event_handler(self, event_handler):
"""
Invoke the event_handler callback each time an event arrives.
@@ -952,8 +956,10 @@ class SaltEvent:
@@ -954,8 +958,10 @@ class SaltEvent:
if not self.cpub:
self.connect_pub()
@ -760,11 +751,11 @@ index d14b9ada40..e8d1aaa5f5 100644
# pylint: disable=W1701
def __del__(self):
diff --git a/tests/unit/cli/test_batch_async.py b/tests/unit/cli/test_batch_async.py
diff --git a/tests/pytests/unit/cli/test_batch_async.py b/tests/pytests/unit/cli/test_batch_async.py
new file mode 100644
index 0000000000..c0b708de76
--- /dev/null
+++ b/tests/unit/cli/test_batch_async.py
+++ b/tests/pytests/unit/cli/test_batch_async.py
@@ -0,0 +1,386 @@
+import salt.ext.tornado
+from salt.cli.batch_async import BatchAsync
@ -1153,6 +1144,6 @@ index 0000000000..c0b708de76
+ self.batch.schedule_next()
+ self.assertEqual(len(self.batch.event.io_loop.spawn_callback.mock_calls), 0)
--
2.37.3
2.39.2

View File

@ -1,16 +1,16 @@
From 100bf2d977c15fda21de7d1d5da2f2c61bed2afd Mon Sep 17 00:00:00 2001
From 4d8c88d6e467c22ea74738743de5be6577f81085 Mon Sep 17 00:00:00 2001
From: Hubert Mantel <mantel@suse.de>
Date: Mon, 27 Nov 2017 13:55:13 +0100
Subject: [PATCH] avoid excessive syslogging by watchdog cronjob (#58)
---
pkg/suse/salt-minion | 2 +-
pkg/old/suse/salt-minion | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pkg/suse/salt-minion b/pkg/suse/salt-minion
diff --git a/pkg/old/suse/salt-minion b/pkg/old/suse/salt-minion
index 2e418094ed..73a91ebd62 100755
--- a/pkg/suse/salt-minion
+++ b/pkg/suse/salt-minion
--- a/pkg/old/suse/salt-minion
+++ b/pkg/old/suse/salt-minion
@@ -55,7 +55,7 @@ WATCHDOG_CRON="/etc/cron.d/salt-minion"
set_watchdog() {
@ -21,6 +21,6 @@ index 2e418094ed..73a91ebd62 100755
/usr/bin/salt-daemon-watcher --with-init & disown
fi
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 58329533d8b3239d978c15ecb76934987880897f Mon Sep 17 00:00:00 2001
From 2ca37fe7d2a03ad86ed738f2636fe240b9f4467e Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
Date: Tue, 6 Oct 2020 12:36:41 +0300
Subject: [PATCH] bsc#1176024: Fix file/directory user and group
@ -12,15 +12,15 @@ Subject: [PATCH] bsc#1176024: Fix file/directory user and group
Co-authored-by: Victor Zhestkov <vzhestkov@vz-thinkpad.vzhestkov.net>
---
salt/modules/file.py | 26 +++++++++++++++++---------
salt/modules/file.py | 20 ++++++++++----------
salt/states/file.py | 12 ++++++++++--
2 files changed, 27 insertions(+), 11 deletions(-)
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/salt/modules/file.py b/salt/modules/file.py
index 95bd69a588..d475e3c2e3 100644
index 69d7992f5a..4612d65511 100644
--- a/salt/modules/file.py
+++ b/salt/modules/file.py
@@ -247,7 +247,7 @@ def group_to_gid(group):
@@ -245,7 +245,7 @@ def group_to_gid(group):
try:
if isinstance(group, int):
return group
@ -29,7 +29,7 @@ index 95bd69a588..d475e3c2e3 100644
except KeyError:
return ""
@@ -338,7 +338,7 @@ def user_to_uid(user):
@@ -336,7 +336,7 @@ def user_to_uid(user):
try:
if isinstance(user, int):
return user
@ -38,69 +38,55 @@ index 95bd69a588..d475e3c2e3 100644
except KeyError:
return ""
@@ -5043,7 +5043,10 @@ def check_perms(
if (
salt.utils.platform.is_windows()
and user_to_uid(user) != user_to_uid(perms["luser"])
- ) or (not salt.utils.platform.is_windows() and user != perms["luser"]):
+ ) or (
+ not salt.utils.platform.is_windows()
+ and salt.utils.stringutils.to_str(user) != perms["luser"]
+ ):
@@ -5133,8 +5133,8 @@ def check_perms(
salt.utils.platform.is_windows() and not user_to_uid(user) == cur["uid"]
) or (
not salt.utils.platform.is_windows()
- and not user == cur["user"]
- and not user == cur["uid"]
+ and not salt.utils.stringutils.to_str(user) == cur["user"]
+ and not salt.utils.stringutils.to_str(user) == cur["uid"]
):
perms["cuser"] = user
if group:
@@ -5052,7 +5055,10 @@ def check_perms(
if (
salt.utils.platform.is_windows()
and group_to_gid(group) != group_to_gid(perms["lgroup"])
- ) or (not salt.utils.platform.is_windows() and group != perms["lgroup"]):
+ ) or (
+ not salt.utils.platform.is_windows()
+ and salt.utils.stringutils.to_str(group) != perms["lgroup"]
+ ):
@@ -5143,8 +5143,8 @@ def check_perms(
salt.utils.platform.is_windows() and not group_to_gid(group) == cur["gid"]
) or (
not salt.utils.platform.is_windows()
- and not group == cur["group"]
- and not group == cur["gid"]
+ and not salt.utils.stringutils.to_str(group) == cur["group"]
+ and not salt.utils.stringutils.to_str(group) == cur["gid"]
):
perms["cgroup"] = group
if "cuser" in perms or "cgroup" in perms:
@@ -5083,7 +5089,8 @@ def check_perms(
and user != ""
@@ -5188,8 +5188,8 @@ def check_perms(
salt.utils.platform.is_windows() and not user_to_uid(user) == post["uid"]
) or (
not salt.utils.platform.is_windows()
- and user != get_user(name, follow_symlinks=follow_symlinks)
+ and salt.utils.stringutils.to_str(user)
+ != get_user(name, follow_symlinks=follow_symlinks)
and user != ""
- and not user == post["user"]
- and not user == post["uid"]
+ and not salt.utils.stringutils.to_str(user) == post["user"]
+ and not salt.utils.stringutils.to_str(user) == post["uid"]
):
if __opts__["test"] is True:
@@ -5101,18 +5108,19 @@ def check_perms(
salt.utils.platform.is_windows()
and group_to_gid(group)
!= group_to_gid(get_group(name, follow_symlinks=follow_symlinks))
- and user != ""
+ and group != ""
ret["changes"]["user"] = user
@@ -5204,8 +5204,8 @@ def check_perms(
salt.utils.platform.is_windows() and not group_to_gid(group) == post["gid"]
) or (
not salt.utils.platform.is_windows()
- and group != get_group(name, follow_symlinks=follow_symlinks)
- and user != ""
+ and salt.utils.stringutils.to_str(group)
+ != get_group(name, follow_symlinks=follow_symlinks)
+ and group != ""
- and not group == post["group"]
- and not group == post["gid"]
+ and not salt.utils.stringutils.to_str(group) == post["group"]
+ and not salt.utils.stringutils.to_str(group) == post["gid"]
):
if __opts__["test"] is True:
ret["changes"]["group"] = group
else:
ret["result"] = False
ret["comment"].append("Failed to change group to {}".format(group))
- elif "cgroup" in perms and user != "":
+ elif "cgroup" in perms and group != "":
ret["changes"]["group"] = group
# Mode changes if needed
diff --git a/salt/states/file.py b/salt/states/file.py
index 9f33a8de23..50ceef1158 100644
index 9f32151b8b..024e5e34ce 100644
--- a/salt/states/file.py
+++ b/salt/states/file.py
@@ -863,9 +863,17 @@ def _check_dir_meta(name, user, group, mode, follow_symlinks=False):
@@ -864,9 +864,17 @@ def _check_dir_meta(name, user, group, mode, follow_symlinks=False):
if not stats:
changes["directory"] = "new"
return changes
@ -121,6 +107,6 @@ index 9f33a8de23..50ceef1158 100644
# Normalize the dir mode
smode = salt.utils.files.normalize_mode(stats["mode"])
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From e011015f0eaa8e6453b57c208ab2a43a15824e36 Mon Sep 17 00:00:00 2001
From b7a554e2dec3351c91c237497fe37cbc30d664bd Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <Victor.Zhestkov@suse.com>
Date: Thu, 1 Sep 2022 14:42:24 +0300
Subject: [PATCH] Change the delimeters to prevent possible tracebacks on
@ -8,42 +8,14 @@ Subject: [PATCH] Change the delimeters to prevent possible tracebacks on
* Fix the test test_dpkg_lowpkg::test_info
---
salt/modules/dpkg_lowpkg.py | 13 ++++++++-----
tests/unit/modules/test_dpkg_lowpkg.py | 4 ++--
2 files changed, 10 insertions(+), 7 deletions(-)
salt/modules/dpkg_lowpkg.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/salt/modules/dpkg_lowpkg.py b/salt/modules/dpkg_lowpkg.py
index 2c25b1fb2a..fc93d99549 100644
index 4d716c8772..78990492cf 100644
--- a/salt/modules/dpkg_lowpkg.py
+++ b/salt/modules/dpkg_lowpkg.py
@@ -309,9 +309,8 @@ def _get_pkg_info(*packages, **kwargs):
"origin:${Origin}\\n"
"homepage:${Homepage}\\n"
"status:${db:Status-Abbrev}\\n"
- "======\\n"
"description:${Description}\\n"
- "------\\n'"
+ "\\n*/~^\\\\*\\n'"
)
cmd += " {}".format(" ".join(packages))
cmd = cmd.strip()
@@ -325,9 +324,13 @@ def _get_pkg_info(*packages, **kwargs):
else:
return ret
- for pkg_info in [elm for elm in re.split(r"------", call["stdout"]) if elm.strip()]:
+ for pkg_info in [
+ elm
+ for elm in re.split(r"\r?\n\*/~\^\\\*(\r?\n|)", call["stdout"])
+ if elm.strip()
+ ]:
pkg_data = {}
- pkg_info, pkg_descr = re.split(r"======", pkg_info)
+ pkg_info, pkg_descr = pkg_info.split("\ndescription:", 1)
for pkg_info_line in [
el.strip() for el in pkg_info.split(os.linesep) if el.strip()
]:
@@ -344,7 +347,7 @@ def _get_pkg_info(*packages, **kwargs):
@@ -347,7 +347,7 @@ def _get_pkg_info(*packages, **kwargs):
if build_date:
pkg_data["build_date"] = build_date
pkg_data["build_date_time_t"] = build_date_t
@ -52,29 +24,7 @@ index 2c25b1fb2a..fc93d99549 100644
ret.append(pkg_data)
return ret
diff --git a/tests/unit/modules/test_dpkg_lowpkg.py b/tests/unit/modules/test_dpkg_lowpkg.py
index d00fc46c66..a97519f489 100644
--- a/tests/unit/modules/test_dpkg_lowpkg.py
+++ b/tests/unit/modules/test_dpkg_lowpkg.py
@@ -290,7 +290,6 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin):
"origin:",
"homepage:http://tiswww.case.edu/php/chet/bash/bashtop.html",
"status:ii ",
- "======",
"description:GNU Bourne Again SHell",
" Bash is an sh-compatible command language interpreter that"
" executes",
@@ -307,7 +306,8 @@ class DpkgTestCase(TestCase, LoaderModuleMockMixin):
" The Programmable Completion Code, by Ian Macdonald, is now"
" found in",
" the bash-completion package.",
- "------",
+ "",
+ "*/~^\\*", # pylint: disable=W1401
]
),
}
--
2.37.3
2.39.2

View File

@ -1,51 +0,0 @@
From 5ed2295489fc13e48b981c323c846bde927cb800 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Fri, 21 Oct 2022 14:39:21 +0200
Subject: [PATCH] Clarify pkg.installed pkg_verify documentation
There have been misunderstandings what the pkg_verify parameter does and
bug reports that it does not work, based on the wrong assumption that
this parameter changes the installation of new packages. The docstring
also stated that it was only provided by `yum`, but `zypper` also
provides this feature (actually it is `rpm` itself in both cases that
does the verification check)
Related issue: https://github.com/saltstack/salt/issues/44878
(cherry picked from commit 2ed5f3c29d3b4313d904b7c081e5a29bf5e309c7)
---
salt/states/pkg.py | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/salt/states/pkg.py b/salt/states/pkg.py
index cda966a1e8..13532521d5 100644
--- a/salt/states/pkg.py
+++ b/salt/states/pkg.py
@@ -1277,14 +1277,15 @@ def installed(
.. versionadded:: 2014.7.0
- For requested packages that are already installed and would not be
- targeted for upgrade or downgrade, use pkg.verify to determine if any
- of the files installed by the package have been altered. If files have
- been altered, the reinstall option of pkg.install is used to force a
- reinstall. Types to ignore can be passed to pkg.verify. Additionally,
- ``verify_options`` can be used to modify further the behavior of
- pkg.verify. See examples below. Currently, this option is supported
- for the following pkg providers: :mod:`yumpkg <salt.modules.yumpkg>`.
+ Use pkg.verify to check if already installed packages require
+ reinstallion. Requested packages that are already installed and not
+ targeted for up- or downgrade are verified with pkg.verify to determine
+ if any file installed by the package have been modified or if package
+ dependencies are not fulfilled. ``ignore_types`` and ``verify_options``
+ can be passed to pkg.verify. See examples below. Currently, this option
+ is supported for the following pkg providers:
+ :mod:`yum <salt.modules.yumpkg>`,
+ :mod:`zypperpkg <salt.modules.zypperpkg>`.
Examples:
--
2.37.3

View File

@ -1,4 +1,4 @@
From 0df204fb1ea7135ce0196f99a864d3f94bd6f92e Mon Sep 17 00:00:00 2001
From fcb43735942ca1b796f656d5647e49a93f770bb2 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 10 Jan 2023 15:04:01 +0100
Subject: [PATCH] Control the collection of lvm grains via config
@ -32,6 +32,6 @@ index 586b187ddb..f5c406cb44 100644
"""
Return list of LVM devices
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 8cd50907edeb4a1128681c30e52b2b30cf7f937d Mon Sep 17 00:00:00 2001
From 2fbc5b580661b094cf79cc5da0860745b72088e4 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 25 Jan 2022 17:08:57 +0100
Subject: [PATCH] Debian info_installed compatibility (#50453)
@ -56,15 +56,15 @@ that got partially reverted by this commit:
https://github.com/openSUSE/salt/commit/d0ef24d113bdaaa29f180031b5da384cffe08c64#diff-820e6ce667fe3afddbc1b9cf1682fdef
---
salt/modules/aptpkg.py | 24 ++++-
salt/modules/dpkg_lowpkg.py | 108 ++++++++++++++++++----
tests/pytests/unit/modules/test_aptpkg.py | 52 +++++++++++
3 files changed, 166 insertions(+), 18 deletions(-)
salt/modules/dpkg_lowpkg.py | 110 ++++++++++++++++++----
tests/pytests/unit/modules/test_aptpkg.py | 52 ++++++++++
3 files changed, 167 insertions(+), 19 deletions(-)
diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py
index 0cbd611b71..4a2281c47f 100644
index 8e89744b5e..938e37cc9e 100644
--- a/salt/modules/aptpkg.py
+++ b/salt/modules/aptpkg.py
@@ -3458,6 +3458,15 @@ def info_installed(*names, **kwargs):
@@ -3440,6 +3440,15 @@ def info_installed(*names, **kwargs):
.. versionadded:: 2016.11.3
@ -80,7 +80,7 @@ index 0cbd611b71..4a2281c47f 100644
CLI Example:
.. code-block:: bash
@@ -3468,11 +3477,19 @@ def info_installed(*names, **kwargs):
@@ -3450,11 +3459,19 @@ def info_installed(*names, **kwargs):
"""
kwargs = salt.utils.args.clean_kwargs(**kwargs)
failhard = kwargs.pop("failhard", True)
@ -101,7 +101,7 @@ index 0cbd611b71..4a2281c47f 100644
t_nfo = dict()
if pkg_nfo.get("status", "ii")[1] != "i":
continue # return only packages that are really installed
@@ -3493,7 +3510,10 @@ def info_installed(*names, **kwargs):
@@ -3475,7 +3492,10 @@ def info_installed(*names, **kwargs):
else:
t_nfo[key] = value
@ -114,7 +114,7 @@ index 0cbd611b71..4a2281c47f 100644
return ret
diff --git a/salt/modules/dpkg_lowpkg.py b/salt/modules/dpkg_lowpkg.py
index 6a88573a8f..afbd619490 100644
index eefd852c51..4d716c8772 100644
--- a/salt/modules/dpkg_lowpkg.py
+++ b/salt/modules/dpkg_lowpkg.py
@@ -234,6 +234,44 @@ def file_dict(*packages, **kwargs):
@ -171,13 +171,14 @@ index 6a88573a8f..afbd619490 100644
"maintainer:${Maintainer}\\n"
"summary:${Summary}\\n"
"source:${source:Package}\\n"
@@ -296,9 +334,16 @@ def _get_pkg_info(*packages, **kwargs):
@@ -299,10 +337,17 @@ def _get_pkg_info(*packages, **kwargs):
key, value = pkg_info_line.split(":", 1)
if value:
pkg_data[key] = value
- install_date = _get_pkg_install_time(pkg_data.get("package"))
- if install_date:
- pkg_data["install_date"] = install_date
- pkg_data["description"] = pkg_descr
+ install_date, install_date_t = _get_pkg_install_time(
+ pkg_data.get("package"), pkg_data.get("arch")
+ )
@ -188,10 +189,11 @@ index 6a88573a8f..afbd619490 100644
+ if build_date:
+ pkg_data["build_date"] = build_date
+ pkg_data["build_date_time_t"] = build_date_t
pkg_data["description"] = pkg_descr.split(":", 1)[-1]
+ pkg_data["description"] = pkg_descr.split(":", 1)[-1]
ret.append(pkg_data)
@@ -324,24 +369,34 @@ def _get_pkg_license(pkg):
return ret
@@ -327,24 +372,34 @@ def _get_pkg_license(pkg):
return ", ".join(sorted(licenses))
@ -237,7 +239,7 @@ index 6a88573a8f..afbd619490 100644
def _get_pkg_ds_avail():
@@ -391,6 +446,15 @@ def info(*packages, **kwargs):
@@ -394,6 +449,15 @@ def info(*packages, **kwargs):
.. versionadded:: 2016.11.3
@ -253,7 +255,7 @@ index 6a88573a8f..afbd619490 100644
CLI Example:
.. code-block:: bash
@@ -405,6 +469,10 @@ def info(*packages, **kwargs):
@@ -408,6 +472,10 @@ def info(*packages, **kwargs):
kwargs = salt.utils.args.clean_kwargs(**kwargs)
failhard = kwargs.pop("failhard", True)
@ -264,7 +266,7 @@ index 6a88573a8f..afbd619490 100644
if kwargs:
salt.utils.args.invalid_kwargs(kwargs)
@@ -432,6 +500,14 @@ def info(*packages, **kwargs):
@@ -435,6 +503,14 @@ def info(*packages, **kwargs):
lic = _get_pkg_license(pkg["package"])
if lic:
pkg["license"] = lic
@ -281,10 +283,10 @@ index 6a88573a8f..afbd619490 100644
return ret
diff --git a/tests/pytests/unit/modules/test_aptpkg.py b/tests/pytests/unit/modules/test_aptpkg.py
index 6ef27e2d29..8e404a673c 100644
index b69402578a..4226957eeb 100644
--- a/tests/pytests/unit/modules/test_aptpkg.py
+++ b/tests/pytests/unit/modules/test_aptpkg.py
@@ -359,6 +359,58 @@ def test_info_installed(lowpkg_info_var):
@@ -360,6 +360,58 @@ def test_info_installed(lowpkg_info_var):
assert len(aptpkg.info_installed()) == 1
@ -344,6 +346,6 @@ index 6ef27e2d29..8e404a673c 100644
"""
Test - Return the name of the package that owns the file.
--
2.37.3
2.39.2

View File

@ -1,28 +0,0 @@
From dd147ab110e71ea0f1091923c9230ade01f226d4 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <Victor.Zhestkov@suse.com>
Date: Fri, 28 Oct 2022 13:19:23 +0300
Subject: [PATCH] Detect module.run syntax
* Detect module run syntax version
* Update module.run docs and add changelog
* Add test for module.run without any args
Co-authored-by: Daniel A. Wozniak <dwozniak@saltstack.com>
---
changelog/58763.fixed | 1 +
1 file changed, 1 insertion(+)
create mode 100644 changelog/58763.fixed
diff --git a/changelog/58763.fixed b/changelog/58763.fixed
new file mode 100644
index 0000000000..53ee8304c0
--- /dev/null
+++ b/changelog/58763.fixed
@@ -0,0 +1 @@
+Detect new and legacy styles of calling module.run and support them both.
--
2.37.3

View File

@ -1,4 +1,4 @@
From e7bc5c7fc89877e9cbf203d8fb70855df0b626e1 Mon Sep 17 00:00:00 2001
From c2a35c0c0aac093d0cc35181c1fda0162e22ac4c Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
Date: Mon, 8 Nov 2021 18:09:53 +0300
Subject: [PATCH] dnfnotify pkgset plugin implementation - 3002.2 (#450)
@ -125,6 +125,6 @@ index 0000000000..6e9df85f71
+ digest.update(buff)
+ return digest.hexdigest()
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From d97cbae7eb3cb0030d355a4ae3fb35745fed5da0 Mon Sep 17 00:00:00 2001
From 4060d4cd24ac0fbcf83c1521553921d76c070a57 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Fri, 21 Sep 2018 17:31:39 +0200
Subject: [PATCH] Do not load pip state if there is no 3rd party
@ -10,7 +10,7 @@ Safe import 3rd party dependency
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/salt/modules/pip.py b/salt/modules/pip.py
index 7135a9145f..da26416662 100644
index c4de0c2984..a60bdca0bb 100644
--- a/salt/modules/pip.py
+++ b/salt/modules/pip.py
@@ -96,6 +96,12 @@ import salt.utils.url
@ -41,6 +41,6 @@ index 7135a9145f..da26416662 100644
def _pip_bin_env(cwd, bin_env):
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 009f51315366827653011d2e9b80aa88416a8bf0 Mon Sep 17 00:00:00 2001
From da6adc6984f21c0d93afff0b0ff55d0eb0ee3e9f Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 17 Aug 2021 11:52:00 +0200
Subject: [PATCH] Don't use shell="/sbin/nologin" in requisites
@ -13,13 +13,13 @@ Fixes: bsc#1188259
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/salt/state.py b/salt/state.py
index 2385975b42..db228228a7 100644
index cb434a91e7..cda84a0fcb 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -921,9 +921,14 @@ class State:
cmd_opts[run_cmd_arg] = low_data.get(run_cmd_arg)
@@ -986,9 +986,14 @@ class State:
cmd_opts[run_cmd_arg] = low_data.get(run_cmd_arg)
if "shell" in low_data:
if "shell" in low_data and "shell" not in cmd_opts_exclude:
- cmd_opts["shell"] = low_data["shell"]
+ shell = low_data["shell"]
elif "shell" in self.opts["grains"]:
@ -34,6 +34,6 @@ index 2385975b42..db228228a7 100644
if "onlyif" in low_data:
_ret = self._run_check_onlyif(low_data, cmd_opts)
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From d4c70bdcb8d871bf3a7e15299b69b9687b7d0d94 Mon Sep 17 00:00:00 2001
From e7ef0b5a46cc69a9237033d8dc4dbc60c0802a20 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Mon, 31 Jan 2022 10:24:26 +0100
Subject: [PATCH] Drop serial from event.unpack in cli.batch_async
@ -29,6 +29,6 @@ index 09aa85258b..1012ce37cc 100644
if mtag.startswith(pattern[:-1]):
minion = data["id"]
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 3ccce128163f6cd9a9360d3b28729702a5d260c1 Mon Sep 17 00:00:00 2001
From 7b47e6f19b38d773a6ec744209753f3d29b094ea Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 16:40:45 +0100
Subject: [PATCH] early feature: support-config
@ -537,7 +537,7 @@ Check last function by full name
salt/utils/parsers.py | 114 +++++
scripts/salt-support | 11 +
setup.py | 2 +
tests/unit/cli/test_support.py | 553 +++++++++++++++++++++
tests/pytests/unit/cli/test_support.py | 553 +++++++++++++++++++++
tests/unit/modules/test_saltsupport.py | 496 +++++++++++++++++++
28 files changed, 2958 insertions(+), 7 deletions(-)
create mode 100644 salt/cli/support/__init__.py
@ -557,11 +557,11 @@ Check last function by full name
create mode 100644 salt/modules/saltsupport.py
create mode 100644 salt/states/saltsupport.py
create mode 100755 scripts/salt-support
create mode 100644 tests/unit/cli/test_support.py
create mode 100644 tests/pytests/unit/cli/test_support.py
create mode 100644 tests/unit/modules/test_saltsupport.py
diff --git a/doc/ref/modules/all/index.rst b/doc/ref/modules/all/index.rst
index fef851215a..a36ab6b2e9 100644
index cbd8b0cdc5..abd40e0bc7 100644
--- a/doc/ref/modules/all/index.rst
+++ b/doc/ref/modules/all/index.rst
@@ -416,6 +416,7 @@ execution modules
@ -573,10 +573,10 @@ index fef851215a..a36ab6b2e9 100644
schedule
scp_mod
diff --git a/doc/ref/states/all/index.rst b/doc/ref/states/all/index.rst
index da7be43039..c968315970 100644
index 13ff645b59..7a062c227b 100644
--- a/doc/ref/states/all/index.rst
+++ b/doc/ref/states/all/index.rst
@@ -282,6 +282,7 @@ state modules
@@ -283,6 +283,7 @@ state modules
rvm
salt_proxy
saltmod
@ -1740,10 +1740,10 @@ index 0000000000..391acdb606
+ info: List of all available groups
+ output: table
diff --git a/salt/loader/lazy.py b/salt/loader/lazy.py
index 8a5d0dd267..e7d692859c 100644
index d319fe54b4..5de995d446 100644
--- a/salt/loader/lazy.py
+++ b/salt/loader/lazy.py
@@ -968,8 +968,10 @@ class LazyLoader(salt.utils.lazy.LazyDict):
@@ -972,8 +972,10 @@ class LazyLoader(salt.utils.lazy.LazyDict):
mod_names = [module_name] + list(virtual_aliases)
for attr in funcs_to_load:
@ -2168,13 +2168,13 @@ index 0000000000..e800e3bf1f
+
+ return __virtualname__
diff --git a/salt/scripts.py b/salt/scripts.py
index 7f6d80de59..1276d2c8b2 100644
index 07393373c9..16b032af2e 100644
--- a/salt/scripts.py
+++ b/salt/scripts.py
@@ -583,3 +583,18 @@ def salt_unity():
sys.argv.pop(1)
s_fun = getattr(sys.modules[__name__], "salt_{}".format(cmd))
s_fun()
@@ -622,3 +622,18 @@ def salt_pip():
] + _pip_args(sys.argv[1:], extras)
ret = subprocess.run(command, shell=False, check=False, env=env)
sys.exit(ret.returncode)
+
+
+def salt_support():
@ -2191,10 +2191,10 @@ index 7f6d80de59..1276d2c8b2 100644
+ _install_signal_handlers(client)
+ client.run()
diff --git a/salt/state.py b/salt/state.py
index d6d2c90168..3196f3c635 100644
index 868be2749e..8352a8defc 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -1592,7 +1592,9 @@ class State:
@@ -1671,7 +1671,9 @@ class State:
names = []
if state.startswith("__"):
continue
@ -2205,27 +2205,27 @@ index d6d2c90168..3196f3c635 100644
if orchestration_jid is not None:
chunk["__orchestration_jid__"] = orchestration_jid
if "__sls__" in body:
@@ -2273,9 +2275,16 @@ class State:
ret = self.call_parallel(cdata, low)
@@ -2382,9 +2384,16 @@ class State:
else:
self.format_slots(cdata)
- ret = self.states[cdata["full"]](
- *cdata["args"], **cdata["kwargs"]
- )
+ if cdata["full"].split(".")[-1] == "__call__":
+ # __call__ requires OrderedDict to preserve state order
+ # kwargs are also invalid overall
+ ret = self.states[cdata["full"]](
+ cdata["args"], module=None, state=cdata["kwargs"]
+ )
+ else:
+ ret = self.states[cdata["full"]](
+ *cdata["args"], **cdata["kwargs"]
+ )
with salt.utils.files.set_umask(low.get("__umask__")):
- ret = self.states[cdata["full"]](
- *cdata["args"], **cdata["kwargs"]
- )
+ if cdata["full"].split(".")[-1] == "__call__":
+ # __call__ requires OrderedDict to preserve state order
+ # kwargs are also invalid overall
+ ret = self.states[cdata["full"]](
+ cdata["args"], module=None, state=cdata["kwargs"]
+ )
+ else:
+ ret = self.states[cdata["full"]](
+ *cdata["args"], **cdata["kwargs"]
+ )
self.states.inject_globals = {}
if (
"check_cmd" in low
@@ -3362,10 +3371,31 @@ class State:
if "check_cmd" in low:
state_check_cmd = "{0[state]}.mod_run_check_cmd".format(low)
@@ -3489,10 +3498,31 @@ class State:
running.update(errors)
return running
@ -2698,30 +2698,30 @@ index 0000000000..4e0e79f3ea
+if __name__ == "__main__":
+ salt_support()
diff --git a/setup.py b/setup.py
index bd11ff95f7..d633af35ec 100755
index 931ed40a51..e60f1b7085 100755
--- a/setup.py
+++ b/setup.py
@@ -1165,6 +1165,7 @@ class SaltDistribution(distutils.dist.Distribution):
"scripts/salt-master",
@@ -1061,6 +1061,7 @@ class SaltDistribution(distutils.dist.Distribution):
"scripts/salt-minion",
"scripts/salt-proxy",
"scripts/salt-run",
+ "scripts/salt-support",
"scripts/salt-ssh",
"scripts/salt-syndic",
"scripts/spm",
@@ -1216,6 +1217,7 @@ class SaltDistribution(distutils.dist.Distribution):
"salt-key = salt.scripts:salt_key",
@@ -1109,6 +1110,7 @@ class SaltDistribution(distutils.dist.Distribution):
"salt-master = salt.scripts:salt_master",
"salt-minion = salt.scripts:salt_minion",
"salt-run = salt.scripts:salt_run",
+ "salt-support = salt.scripts:salt_support",
"salt-ssh = salt.scripts:salt_ssh",
"salt-syndic = salt.scripts:salt_syndic",
"spm = salt.scripts:salt_spm",
diff --git a/tests/unit/cli/test_support.py b/tests/unit/cli/test_support.py
diff --git a/tests/pytests/unit/cli/test_support.py b/tests/pytests/unit/cli/test_support.py
new file mode 100644
index 0000000000..dc0e99bb3d
--- /dev/null
+++ b/tests/unit/cli/test_support.py
+++ b/tests/pytests/unit/cli/test_support.py
@@ -0,0 +1,553 @@
+"""
+ :codeauthor: Bo Maryniuk <bo@suse.de>
@ -3779,6 +3779,6 @@ index 0000000000..f9ce7be29a
+ "00:00:00.000 - The real TTYs became " "pseudo TTYs and vice versa"
+ ]
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 465ea094039e771ea2b4ccda012d0dc12f7aa022 Mon Sep 17 00:00:00 2001
From e9d52cb97d619a76355c5aa1d03b733c125c0f22 Mon Sep 17 00:00:00 2001
From: Maximilian Meister <mmeister@suse.de>
Date: Thu, 3 May 2018 15:52:23 +0200
Subject: [PATCH] enable passing a unix_socket for mysql returners
@ -19,7 +19,7 @@ Signed-off-by: Maximilian Meister <mmeister@suse.de>
1 file changed, 5 insertions(+)
diff --git a/salt/returners/mysql.py b/salt/returners/mysql.py
index 6fd4fdef2c..7a7e9a3284 100644
index 67b44004ac..a220f11465 100644
--- a/salt/returners/mysql.py
+++ b/salt/returners/mysql.py
@@ -17,6 +17,7 @@ config. These are the defaults:
@ -37,8 +37,8 @@ index 6fd4fdef2c..7a7e9a3284 100644
+ alternative.mysql.unix_socket: '/tmp/mysql.sock'
Should you wish the returner data to be cleaned out every so often, set
`keep_jobs` to the number of hours for the jobs to live in the tables.
@@ -196,6 +198,7 @@ def _get_options(ret=None):
`keep_jobs_seconds` to the number of hours for the jobs to live in the
@@ -197,6 +199,7 @@ def _get_options(ret=None):
"ssl_ca": None,
"ssl_cert": None,
"ssl_key": None,
@ -46,7 +46,7 @@ index 6fd4fdef2c..7a7e9a3284 100644
}
attrs = {
@@ -207,6 +210,7 @@ def _get_options(ret=None):
@@ -208,6 +211,7 @@ def _get_options(ret=None):
"ssl_ca": "ssl_ca",
"ssl_cert": "ssl_cert",
"ssl_key": "ssl_key",
@ -54,7 +54,7 @@ index 6fd4fdef2c..7a7e9a3284 100644
}
_options = salt.returners.get_returner_options(
@@ -265,6 +269,7 @@ def _get_serv(ret=None, commit=False):
@@ -266,6 +270,7 @@ def _get_serv(ret=None, commit=False):
db=_options.get("db"),
port=_options.get("port"),
ssl=ssl_options,
@ -63,6 +63,6 @@ index 6fd4fdef2c..7a7e9a3284 100644
try:
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 93d7bdab18bdc657c8103a7b5f569458a97c8ca0 Mon Sep 17 00:00:00 2001
From 17452801e950b3f49a9ec7ef444e3d57862cd9bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Wed, 7 Jul 2021 15:41:48 +0100
@ -420,6 +420,6 @@ index 045c37f7c9..301c1869ec 100644
+ },
+ )
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 559920223a010b70a4e469143b3390d8d3a7a4e2 Mon Sep 17 00:00:00 2001
From 42a5e5d1a898d7b8bdb56a94decf525204ebccb8 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Thu, 14 Dec 2017 16:21:40 +0100
Subject: [PATCH] Fix bsc#1065792
@ -20,6 +20,6 @@ index 93c7c4fb07..0d8a4efa03 100644
return __virtualname__
else:
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 51bcdcfdec73368d1517150eafda21e4af51dd7a Mon Sep 17 00:00:00 2001
From 7be26299bc7b6ec2065ab13857f088dc500ee882 Mon Sep 17 00:00:00 2001
From: Jochen Breuer <jbreuer@suse.de>
Date: Thu, 6 Sep 2018 17:15:18 +0200
Subject: [PATCH] Fix for SUSE Expanded Support detection
@ -14,26 +14,26 @@ This change also adds a check for redhat-release and then marks the
1 file changed, 9 insertions(+)
diff --git a/salt/grains/core.py b/salt/grains/core.py
index debbeb257d..b55ab4e472 100644
index 710c57f28f..1199ad274f 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -2058,6 +2058,15 @@ def os_data():
log.trace("Parsing distrib info from /etc/centos-release")
# CentOS Linux
grains["lsb_distrib_id"] = "CentOS"
+ # Maybe CentOS Linux; could also be SUSE Expanded Support.
+ # SUSE ES has both, centos-release and redhat-release.
+ if os.path.isfile("/etc/redhat-release"):
+ with salt.utils.files.fopen("/etc/redhat-release") as ifile:
+ for line in ifile:
+ if "red hat enterprise linux server" in line.lower():
+ # This is a SUSE Expanded Support Rhel installation
+ grains["lsb_distrib_id"] = "RedHat"
+ break
with salt.utils.files.fopen("/etc/centos-release") as ifile:
for line in ifile:
# Need to pull out the version and codename
@@ -2279,6 +2279,15 @@ def _legacy_linux_distribution_data(grains, os_release, lsb_has_error):
log.trace("Parsing distrib info from /etc/centos-release")
# CentOS Linux
grains["lsb_distrib_id"] = "CentOS"
+ # Maybe CentOS Linux; could also be SUSE Expanded Support.
+ # SUSE ES has both, centos-release and redhat-release.
+ if os.path.isfile("/etc/redhat-release"):
+ with salt.utils.files.fopen("/etc/redhat-release") as ifile:
+ for line in ifile:
+ if "red hat enterprise linux server" in line.lower():
+ # This is a SUSE Expanded Support Rhel installation
+ grains["lsb_distrib_id"] = "RedHat"
+ break
with salt.utils.files.fopen("/etc/centos-release") as ifile:
for line in ifile:
# Need to pull out the version and codename
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From f87d92122cb141e8f6f4d1c5a6ed5685e1b3900c Mon Sep 17 00:00:00 2001
From b0e713d6946526b894837406c0760c262e4312a1 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Wed, 9 Jan 2019 16:08:19 +0100
Subject: [PATCH] Fix issue #2068 test
@ -13,7 +13,7 @@ Minor update: more correct is-dict check.
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/salt/state.py b/salt/state.py
index 3196f3c635..2385975b42 100644
index 8352a8defc..cb434a91e7 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -12,6 +12,7 @@ The data sent to the state calls is as follows:
@ -24,7 +24,7 @@ index 3196f3c635..2385975b42 100644
import copy
import datetime
import fnmatch
@@ -3380,16 +3381,18 @@ class State:
@@ -3507,16 +3508,18 @@ class State:
"""
for chunk in high:
state = high[chunk]
@ -47,6 +47,6 @@ index 3196f3c635..2385975b42 100644
def call_high(self, high, orchestration_jid=None):
"""
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 3ed9869ee6847472846072d62cbc57dcb9104c90 Mon Sep 17 00:00:00 2001
From 5158ebce305d961a2d2e3cb3f889b0cde593c4a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Hole=C4=8Dek?= <oholecek@aaannz.eu>
Date: Mon, 10 May 2021 16:23:19 +0200
Subject: [PATCH] Fix missing minion returns in batch mode (#360)
@ -12,10 +12,10 @@ Co-authored-by: Denis V. Meltsaykin <dmeltsaykin@mirantis.com>
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/salt/client/__init__.py b/salt/client/__init__.py
index 2427516ca1..86888adc19 100644
index bcda56c9b4..b2617e4554 100644
--- a/salt/client/__init__.py
+++ b/salt/client/__init__.py
@@ -972,7 +972,7 @@ class LocalClient:
@@ -976,7 +976,7 @@ class LocalClient:
self._clean_up_subscriptions(pub_data["jid"])
finally:
@ -25,6 +25,6 @@ index 2427516ca1..86888adc19 100644
def cmd_full_return(
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 7ac8c79f38960c787f6b5324e347707325c65e79 Mon Sep 17 00:00:00 2001
From 5f6488ab9211927c421e3d87a4ee84fe659ceb8b Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Mon, 27 Jun 2022 18:03:49 +0300
Subject: [PATCH] Fix ownership of salt thin directory when using the
@ -45,6 +45,6 @@ index 293ea1b7fa..95171f7aea 100644
if venv_salt_call is None:
# Use Salt thin only if Salt Bundle (venv-salt-minion) is not available
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 6e0e6c26f4ec0955b55937ae3b58ca485b99facd Mon Sep 17 00:00:00 2001
From 42cfb51fa01e13fe043a62536ba37fd472bc2688 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Tue, 12 Apr 2022 10:08:17 +0300
Subject: [PATCH] Fix regression with depending client.ssh on psutil
@ -9,7 +9,7 @@ Subject: [PATCH] Fix regression with depending client.ssh on psutil
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index fe1213b723..1b76a38e0b 100644
index d5a679821e..b120e0002e 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -12,7 +12,6 @@ import hashlib
@ -48,6 +48,6 @@ index fe1213b723..1b76a38e0b 100644
if (
pid_running and prev_session_running < self.max_pid_wait
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 59200b4a4578c96dcffc0584725d8cba40c20ff7 Mon Sep 17 00:00:00 2001
From 4dbd5534a39fbfaebad32a00d0e6c512d840b0fd Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Thu, 31 Mar 2022 13:39:57 +0300
Subject: [PATCH] Fix salt-ssh opts poisoning (bsc#1197637) - 3004 (#501)
@ -14,7 +14,7 @@ Subject: [PATCH] Fix salt-ssh opts poisoning (bsc#1197637) - 3004 (#501)
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index 6db2dfcbb0..8ae417f575 100644
index e6837df4e5..a527c03de6 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -338,7 +338,7 @@ class SSH(MultiprocessingStateMixin):
@ -123,6 +123,6 @@ index 32f8a7702c..bbe4269839 100644
loaded_base_name=loaded_base_name,
)
--
2.37.3
2.39.2

View File

@ -1,50 +0,0 @@
From e328d2029c93153c519e10e9596c635f6f3febcf Mon Sep 17 00:00:00 2001
From: Petr Pavlu <31453820+petrpavlu@users.noreply.github.com>
Date: Fri, 8 Jul 2022 10:11:52 +0200
Subject: [PATCH] Fix salt.states.file.managed() for follow_symlinks=True
and test=True (bsc#1199372) (#535)
When managing file /etc/test as follows:
> file /etc/test:
> file.managed:
> - name: /etc/test
> - source: salt://config/test
> - mode: 644
> - follow_symlinks: True
and with /etc/test being a symlink to a different file, an invocation of
"salt-call '*' state.apply test=True" can report that the file should be
updated even when a subsequent run of the same command without the test
parameter makes no changes.
The problem is that the test code path doesn't take correctly into
account the follow_symlinks=True setting and ends up comparing
permissions of the symlink instead of its target file.
The patch addresses the problem by extending functions
salt.modules.file.check_managed(), check_managed_changes() and
check_file_meta() to have the follow_symlinks parameter which gets
propagated to the salt.modules.file.stats() call and by updating
salt.states.file.managed() to forward the same parameter to
salt.modules.file.check_managed_changes().
Fixes #62066.
[Cherry-picked from upstream commit
95bfbe31a2dc54723af3f1783d40de152760fe1a.]
---
changelog/62066.fixed | 1 +
1 file changed, 1 insertion(+)
create mode 100644 changelog/62066.fixed
diff --git a/changelog/62066.fixed b/changelog/62066.fixed
new file mode 100644
index 0000000000..68216a03c1
--- /dev/null
+++ b/changelog/62066.fixed
@@ -0,0 +1 @@
+Fixed salt.states.file.managed() for follow_symlinks=True and test=True
--
2.37.3

View File

@ -1,19 +1,21 @@
From f348f291093ea3f7c841b03a975ae81b40963842 Mon Sep 17 00:00:00 2001
From b4b2c59bfd479d59faeaf0e4d26d672828a519c8 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Wed, 25 Nov 2020 15:09:41 +0300
Subject: [PATCH] Fix salt.utils.stringutils.to_str calls to make it
working with numeric uid/gid
Fix upstream tests to work with 3006.
---
salt/modules/file.py | 16 ++++++++++------
salt/states/file.py | 11 +++++++++--
2 files changed, 19 insertions(+), 8 deletions(-)
salt/modules/file.py | 22 ++++++++++++-------
salt/states/file.py | 11 ++++++++--
.../unit/modules/file/test_file_check.py | 10 ++++-----
3 files changed, 28 insertions(+), 15 deletions(-)
diff --git a/salt/modules/file.py b/salt/modules/file.py
index d475e3c2e3..d3de4da467 100644
index 4612d65511..55b236fe41 100644
--- a/salt/modules/file.py
+++ b/salt/modules/file.py
@@ -5036,6 +5036,12 @@ def check_perms(
@@ -5127,14 +5127,20 @@ def check_perms(
is_dir = os.path.isdir(name)
is_link = os.path.islink(name)
@ -23,52 +25,57 @@ index d475e3c2e3..d3de4da467 100644
+ except:
+ return salt.utils.stringutils.to_str(str(s))
+
# user/group changes if needed, then check if it worked
# Check and make user/group/mode changes, then verify they were successful
if user:
if isinstance(user, int):
@@ -5045,7 +5051,7 @@ def check_perms(
and user_to_uid(user) != user_to_uid(perms["luser"])
if (
salt.utils.platform.is_windows() and not user_to_uid(user) == cur["uid"]
) or (
not salt.utils.platform.is_windows()
- and salt.utils.stringutils.to_str(user) != perms["luser"]
+ and __safe_to_str(user) != perms["luser"]
- and not salt.utils.stringutils.to_str(user) == cur["user"]
- and not salt.utils.stringutils.to_str(user) == cur["uid"]
+ and not __safe_to_str(user) == cur["user"]
+ and not user == cur["uid"]
):
perms["cuser"] = user
@@ -5057,7 +5063,7 @@ def check_perms(
and group_to_gid(group) != group_to_gid(perms["lgroup"])
@@ -5143,8 +5149,8 @@ def check_perms(
salt.utils.platform.is_windows() and not group_to_gid(group) == cur["gid"]
) or (
not salt.utils.platform.is_windows()
- and salt.utils.stringutils.to_str(group) != perms["lgroup"]
+ and __safe_to_str(group) != perms["lgroup"]
- and not salt.utils.stringutils.to_str(group) == cur["group"]
- and not salt.utils.stringutils.to_str(group) == cur["gid"]
+ and not __safe_to_str(group) == cur["group"]
+ and not group == cur["gid"]
):
perms["cgroup"] = group
@@ -5089,8 +5095,7 @@ def check_perms(
and user != ""
@@ -5188,8 +5194,8 @@ def check_perms(
salt.utils.platform.is_windows() and not user_to_uid(user) == post["uid"]
) or (
not salt.utils.platform.is_windows()
- and salt.utils.stringutils.to_str(user)
- != get_user(name, follow_symlinks=follow_symlinks)
+ and __safe_to_str(user) != get_user(name, follow_symlinks=follow_symlinks)
and user != ""
- and not salt.utils.stringutils.to_str(user) == post["user"]
- and not salt.utils.stringutils.to_str(user) == post["uid"]
+ and not __safe_to_str(user) == post["user"]
+ and not user == post["uid"]
):
if __opts__["test"] is True:
@@ -5111,8 +5116,7 @@ def check_perms(
and group != ""
ret["changes"]["user"] = user
@@ -5204,8 +5210,8 @@ def check_perms(
salt.utils.platform.is_windows() and not group_to_gid(group) == post["gid"]
) or (
not salt.utils.platform.is_windows()
- and salt.utils.stringutils.to_str(group)
- != get_group(name, follow_symlinks=follow_symlinks)
+ and __safe_to_str(group) != get_group(name, follow_symlinks=follow_symlinks)
and group != ""
- and not salt.utils.stringutils.to_str(group) == post["group"]
- and not salt.utils.stringutils.to_str(group) == post["gid"]
+ and not __safe_to_str(group) == post["group"]
+ and not group == post["gid"]
):
if __opts__["test"] is True:
ret["changes"]["group"] = group
diff --git a/salt/states/file.py b/salt/states/file.py
index 50ceef1158..1083bb46d6 100644
index 024e5e34ce..9630ff7096 100644
--- a/salt/states/file.py
+++ b/salt/states/file.py
@@ -863,15 +863,22 @@ def _check_dir_meta(name, user, group, mode, follow_symlinks=False):
@@ -864,15 +864,22 @@ def _check_dir_meta(name, user, group, mode, follow_symlinks=False):
if not stats:
changes["directory"] = "new"
return changes
@ -93,7 +100,42 @@ index 50ceef1158..1083bb46d6 100644
and group != stats.get("gid")
):
changes["group"] = group
diff --git a/tests/pytests/unit/modules/file/test_file_check.py b/tests/pytests/unit/modules/file/test_file_check.py
index ce86acd7fc..2294e6760b 100644
--- a/tests/pytests/unit/modules/file/test_file_check.py
+++ b/tests/pytests/unit/modules/file/test_file_check.py
@@ -17,7 +17,7 @@ def configure_loader_modules():
return {
filemod: {
"__context__": {},
- "__opts__": {"test": False},
+ "__opts__": {"test": True},
}
}
@@ -172,7 +172,7 @@ def test_check_managed_changes_follow_symlinks(a_link, tfile):
),
# no user/group changes needed by id
(
- {"user": 3001, "group": 4001},
+ {"user": 2001, "group": 1001},
{},
),
],
@@ -184,9 +184,9 @@ def test_check_perms_user_group_name_and_id(input, expected):
stat_out = {
"user": "luser",
"group": "lgroup",
- "uid": 3001,
- "gid": 4001,
- "mode": "123",
+ "uid": 2001,
+ "gid": 1001,
+ "mode": "0123",
}
patch_stats = patch(
--
2.37.3
2.39.2

View File

@ -1,183 +0,0 @@
From 58317cda7a347581b495ab7fd71ce75f0740d8d6 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <Victor.Zhestkov@suse.com>
Date: Thu, 1 Sep 2022 14:44:26 +0300
Subject: [PATCH] Fix state.apply in test mode with file state module on
user/group checking (bsc#1202167)
* Do not fail on checking user/group in test mode
* fixes saltstack/salt#61846 reporting of errors in test mode
Co-authored-by: nicholasmhughes <nicholasmhughes@gmail.com>
* Add tests for _check_user usage
Co-authored-by: nicholasmhughes <nicholasmhughes@gmail.com>
---
changelog/61846.fixed | 1 +
salt/states/file.py | 5 +++
tests/pytests/unit/states/file/test_copy.py | 35 ++++++++++++++++
.../unit/states/file/test_filestate.py | 42 +++++++++++++++++++
.../pytests/unit/states/file/test_managed.py | 31 ++++++++++++++
5 files changed, 114 insertions(+)
create mode 100644 changelog/61846.fixed
diff --git a/changelog/61846.fixed b/changelog/61846.fixed
new file mode 100644
index 0000000000..c4024efe9f
--- /dev/null
+++ b/changelog/61846.fixed
@@ -0,0 +1 @@
+Fix the reporting of errors for file.directory in test mode
diff --git a/salt/states/file.py b/salt/states/file.py
index 1083bb46d6..5cb58f5454 100644
--- a/salt/states/file.py
+++ b/salt/states/file.py
@@ -379,6 +379,11 @@ def _check_user(user, group):
gid = __salt__["file.group_to_gid"](group)
if gid == "":
err += "Group {} is not available".format(group)
+ if err and __opts__["test"]:
+ # Write the warning with error message, but prevent failing,
+ # in case of applying the state in test mode.
+ log.warning(err)
+ return ""
return err
diff --git a/tests/pytests/unit/states/file/test_copy.py b/tests/pytests/unit/states/file/test_copy.py
index ce7161f02d..a11adf5ae0 100644
--- a/tests/pytests/unit/states/file/test_copy.py
+++ b/tests/pytests/unit/states/file/test_copy.py
@@ -205,3 +205,38 @@ def test_copy(tmp_path):
)
res = filestate.copy_(name, source, group=group, preserve=False)
assert res == ret
+
+
+def test_copy_test_mode_user_group_not_present():
+ """
+ Test file copy in test mode with no user or group existing
+ """
+ source = "/tmp/src_copy_no_user_group_test_mode"
+ filename = "/tmp/copy_no_user_group_test_mode"
+ with patch.dict(
+ filestate.__salt__,
+ {
+ "file.group_to_gid": MagicMock(side_effect=["1234", "", ""]),
+ "file.user_to_uid": MagicMock(side_effect=["", "4321", ""]),
+ "file.get_mode": MagicMock(return_value="0644"),
+ },
+ ), patch.dict(filestate.__opts__, {"test": True}), patch.object(
+ os.path, "exists", return_value=True
+ ):
+ ret = filestate.copy_(
+ source, filename, group="nonexistinggroup", user="nonexistinguser"
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
+
+ ret = filestate.copy_(
+ source, filename, group="nonexistinggroup", user="nonexistinguser"
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
+
+ ret = filestate.copy_(
+ source, filename, group="nonexistinggroup", user="nonexistinguser"
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
diff --git a/tests/pytests/unit/states/file/test_filestate.py b/tests/pytests/unit/states/file/test_filestate.py
index 2f9f369fb2..c373cb3449 100644
--- a/tests/pytests/unit/states/file/test_filestate.py
+++ b/tests/pytests/unit/states/file/test_filestate.py
@@ -577,3 +577,45 @@ def test_mod_run_check_cmd():
assert filestate.mod_run_check_cmd(cmd, filename) == ret
assert filestate.mod_run_check_cmd(cmd, filename)
+
+
+def test_recurse_test_mode_user_group_not_present():
+ """
+ Test file recurse in test mode with no user or group existing
+ """
+ filename = "/tmp/recurse_no_user_group_test_mode"
+ source = "salt://tmp/src_recurse_no_user_group_test_mode"
+ mock_l = MagicMock(return_value=[])
+ mock_emt = MagicMock(return_value=["tmp/src_recurse_no_user_group_test_mode"])
+ with patch.dict(
+ filestate.__salt__,
+ {
+ "file.group_to_gid": MagicMock(side_effect=["1234", "", ""]),
+ "file.user_to_uid": MagicMock(side_effect=["", "4321", ""]),
+ "file.get_mode": MagicMock(return_value="0644"),
+ "file.source_list": MagicMock(return_value=[source, ""]),
+ "cp.list_master_dirs": mock_emt,
+ "cp.list_master": mock_l,
+ },
+ ), patch.dict(filestate.__opts__, {"test": True}), patch.object(
+ os.path, "exists", return_value=True
+ ), patch.object(
+ os.path, "isdir", return_value=True
+ ):
+ ret = filestate.recurse(
+ filename, source, group="nonexistinggroup", user="nonexistinguser"
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
+
+ ret = filestate.recurse(
+ filename, source, group="nonexistinggroup", user="nonexistinguser"
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
+
+ ret = filestate.recurse(
+ filename, source, group="nonexistinggroup", user="nonexistinguser"
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
diff --git a/tests/pytests/unit/states/file/test_managed.py b/tests/pytests/unit/states/file/test_managed.py
index 9d9fb17717..0b341e09a9 100644
--- a/tests/pytests/unit/states/file/test_managed.py
+++ b/tests/pytests/unit/states/file/test_managed.py
@@ -373,3 +373,34 @@ def test_managed():
filestate.managed(name, user=user, group=group)
== ret
)
+
+
+def test_managed_test_mode_user_group_not_present():
+ """
+ Test file managed in test mode with no user or group existing
+ """
+ filename = "/tmp/managed_no_user_group_test_mode"
+ with patch.dict(
+ filestate.__salt__,
+ {
+ "file.group_to_gid": MagicMock(side_effect=["1234", "", ""]),
+ "file.user_to_uid": MagicMock(side_effect=["", "4321", ""]),
+ },
+ ), patch.dict(filestate.__opts__, {"test": True}):
+ ret = filestate.managed(
+ filename, group="nonexistinggroup", user="nonexistinguser"
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
+
+ ret = filestate.managed(
+ filename, group="nonexistinggroup", user="nonexistinguser"
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
+
+ ret = filestate.managed(
+ filename, group="nonexistinggroup", user="nonexistinguser"
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
--
2.37.3

View File

@ -1,37 +0,0 @@
From 4cc528dadfbffdeb90df41bbd848d0c2c7efec78 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 12 Jul 2022 14:02:58 +0200
Subject: [PATCH] Fix test_ipc unit tests
---
tests/unit/transport/test_ipc.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tests/unit/transport/test_ipc.py b/tests/unit/transport/test_ipc.py
index 4a0a7c29e2..af001d9650 100644
--- a/tests/unit/transport/test_ipc.py
+++ b/tests/unit/transport/test_ipc.py
@@ -105,8 +105,8 @@ class IPCMessagePubSubCase(salt.ext.tornado.testing.AsyncTestCase):
self.stop()
# Now let both waiting data at once
- client1.read_async(handler)
- client2.read_async(handler)
+ client1.read_async()
+ client2.read_async()
self.pub_channel.publish("TEST")
self.wait()
self.assertEqual(len(call_cnt), 2)
@@ -148,7 +148,7 @@ class IPCMessagePubSubCase(salt.ext.tornado.testing.AsyncTestCase):
pass
try:
- ret1 = yield client1.read_async(handler)
+ ret1 = yield client1.read_async()
self.wait()
except StreamClosedError as ex:
assert False, "StreamClosedError was raised inside the Future"
--
2.37.3

View File

@ -1,4 +1,4 @@
From 48a924bfad537f236593395a9d4cf108d6e9a03f Mon Sep 17 00:00:00 2001
From b80c0d515e8715c160f94124dff8b5b90e773cd0 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
Date: Tue, 9 Nov 2021 16:19:56 +0300
Subject: [PATCH] Fix the regression for yumnotify plugin (#456)
@ -18,6 +18,6 @@ index 0d117e8946..cec5256d20 100644
- print("Unable to save the cookie file: %s" % (e), file=sys.stderr)
+ sys.stderr.write("Unable to save the cookie file: %s\n" % (e))
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 8b07b529458e1fc007c8ee848d66035b3403a22d Mon Sep 17 00:00:00 2001
From c37992e305978e95da1ac0a40a8142f578271320 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
Date: Mon, 8 Nov 2021 17:43:02 +0300
Subject: [PATCH] Fix traceback.print_exc calls for test_pip_state (#432)
@ -8,10 +8,10 @@ Subject: [PATCH] Fix traceback.print_exc calls for test_pip_state (#432)
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/unit/states/test_pip_state.py b/tests/unit/states/test_pip_state.py
index 93b8b3bd71..9531b6d2be 100644
index 5e4b6e0af1..981ad46a13 100644
--- a/tests/unit/states/test_pip_state.py
+++ b/tests/unit/states/test_pip_state.py
@@ -441,7 +441,7 @@ class PipStateInstallationErrorTest(TestCase):
@@ -442,7 +442,7 @@ class PipStateInstallationErrorTest(TestCase):
sys.stdout.flush()
sys.exit(2)
except Exception as exc:
@ -21,6 +21,6 @@ index 93b8b3bd71..9531b6d2be 100644
sys.exit(3)
sys.exit(0)
--
2.37.3
2.39.2

View File

@ -0,0 +1,58 @@
From c0fae09e5a4f6997a60007d970c7c6a5614d9102 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Wed, 19 Apr 2023 10:41:28 +0100
Subject: [PATCH] Fix version detection and avoid building and testing
failures
---
salt/version.py | 20 ++------------------
1 file changed, 2 insertions(+), 18 deletions(-)
diff --git a/salt/version.py b/salt/version.py
index 43cb5f86f7..67719bd020 100644
--- a/salt/version.py
+++ b/salt/version.py
@@ -1,7 +1,6 @@
"""
Set up the version of Salt
"""
-import argparse
import operator
import os
import platform
@@ -78,7 +77,7 @@ class SaltVersionsInfo(type):
ALUMINIUM = SaltVersion("Aluminium" , info=3003, released=True)
SILICON = SaltVersion("Silicon" , info=3004, released=True)
PHOSPHORUS = SaltVersion("Phosphorus" , info=3005, released=True)
- SULFUR = SaltVersion("Sulfur" , info=(3006, 0), released=True)
+ SULFUR = SaltVersion("Sulfur" , info=(3006, 0))
CHLORINE = SaltVersion("Chlorine" , info=(3007, 0))
ARGON = SaltVersion("Argon" , info=(3008, 0))
POTASSIUM = SaltVersion("Potassium" , info=(3009, 0))
@@ -922,20 +921,5 @@ def versions_report(include_salt_cloud=False, include_extensions=True):
yield from info
-def _parser():
- parser = argparse.ArgumentParser()
- parser.add_argument(
- "--next-release", help="Return the next release", action="store_true"
- )
- # When pip installing we pass in other args to this script.
- # This allows us to catch those args but not use them
- parser.add_argument("unknown", nargs=argparse.REMAINDER)
- return parser.parse_args()
-
-
if __name__ == "__main__":
- args = _parser()
- if args.next_release:
- print(__saltstack_version__.next_release())
- else:
- print(__version__)
+ print(__version__)
--
2.39.2

View File

@ -1,4 +1,4 @@
From d5fae6bd4a4f243115ee220393e05440f0d48b5a Mon Sep 17 00:00:00 2001
From 4996f423f14369fad14a9e6d2d3b8bd750c77fc7 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Tue, 5 Apr 2022 12:04:46 +0300
Subject: [PATCH] Fixes for Python 3.10 (#502)
@ -9,7 +9,7 @@ Subject: [PATCH] Fixes for Python 3.10 (#502)
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/salt/state.py b/salt/state.py
index f5579fbb69..61519d5042 100644
index ab84cb8b4d..489424a083 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -12,7 +12,6 @@ The data sent to the state calls is as follows:
@ -20,7 +20,7 @@ index f5579fbb69..61519d5042 100644
import copy
import datetime
import fnmatch
@@ -26,6 +25,8 @@ import sys
@@ -27,6 +26,8 @@ import sys
import time
import traceback
@ -29,7 +29,7 @@ index f5579fbb69..61519d5042 100644
import salt.channel.client
import salt.fileclient
import salt.loader
@@ -3405,7 +3406,7 @@ class State:
@@ -3513,7 +3514,7 @@ class State:
"""
for chunk in high:
state = high[chunk]
@ -39,6 +39,6 @@ index f5579fbb69..61519d5042 100644
for state_ref in state:
needs_default = True
--
2.37.3
2.39.2

View File

@ -1,103 +0,0 @@
From 62b3e3491f283a5b5ac243e1f5904ad17e0353bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ra=C3=BAl=20Osuna?=
<17827278+raulillo82@users.noreply.github.com>
Date: Tue, 31 Jan 2023 13:13:32 +0100
Subject: [PATCH] Fixes pkg.version_cmp on openEuler systems and a few
other OS flavors (#576)
* Fix bug/issue #540
* Fix bug/issue #540
* Add tests for __virtual__ function
* Minor changes to align with upstream
---
changelog/540.fixed | 1 +
salt/modules/rpm_lowpkg.py | 12 +++++--
tests/pytests/unit/modules/test_rpm_lowpkg.py | 31 +++++++++++++++++++
3 files changed, 42 insertions(+), 2 deletions(-)
create mode 100644 changelog/540.fixed
diff --git a/changelog/540.fixed b/changelog/540.fixed
new file mode 100644
index 0000000000..50cb42bf40
--- /dev/null
+++ b/changelog/540.fixed
@@ -0,0 +1 @@
+Fix pkg.version_cmp on openEuler and a few other os flavors.
diff --git a/salt/modules/rpm_lowpkg.py b/salt/modules/rpm_lowpkg.py
index c8e984c021..01cd575bc7 100644
--- a/salt/modules/rpm_lowpkg.py
+++ b/salt/modules/rpm_lowpkg.py
@@ -62,14 +62,22 @@ def __virtual__():
" grains.",
)
- enabled = ("amazon", "xcp", "xenserver", "virtuozzolinux")
+ enabled = (
+ "amazon",
+ "xcp",
+ "xenserver",
+ "virtuozzolinux",
+ "virtuozzo",
+ "issabel pbx",
+ "openeuler",
+ )
if os_family in ["redhat", "suse"] or os_grain in enabled:
return __virtualname__
return (
False,
"The rpm execution module failed to load: only available on redhat/suse type"
- " systems or amazon, xcp or xenserver.",
+ " systems or amazon, xcp, xenserver, virtuozzolinux, virtuozzo, issabel pbx or openeuler.",
)
diff --git a/tests/pytests/unit/modules/test_rpm_lowpkg.py b/tests/pytests/unit/modules/test_rpm_lowpkg.py
index f19afa854e..e07f71eb61 100644
--- a/tests/pytests/unit/modules/test_rpm_lowpkg.py
+++ b/tests/pytests/unit/modules/test_rpm_lowpkg.py
@@ -35,6 +35,37 @@ def _called_with_root(mock):
def configure_loader_modules():
return {rpm: {"rpm": MagicMock(return_value=MagicMock)}}
+def test___virtual___openeuler():
+ patch_which = patch("salt.utils.path.which", return_value=True)
+ with patch.dict(
+ rpm.__grains__, {"os": "openEuler", "os_family": "openEuler"}
+ ), patch_which:
+ assert rpm.__virtual__() == "lowpkg"
+
+
+def test___virtual___issabel_pbx():
+ patch_which = patch("salt.utils.path.which", return_value=True)
+ with patch.dict(
+ rpm.__grains__, {"os": "Issabel Pbx", "os_family": "IssabeL PBX"}
+ ), patch_which:
+ assert rpm.__virtual__() == "lowpkg"
+
+
+def test___virtual___virtuozzo():
+ patch_which = patch("salt.utils.path.which", return_value=True)
+ with patch.dict(
+ rpm.__grains__, {"os": "virtuozzo", "os_family": "VirtuoZZO"}
+ ), patch_which:
+ assert rpm.__virtual__() == "lowpkg"
+
+
+def test___virtual___with_no_rpm():
+ patch_which = patch("salt.utils.path.which", return_value=False)
+ ret = rpm.__virtual__()
+ assert isinstance(ret, tuple)
+ assert ret[0] is False
+
+
# 'list_pkgs' function tests: 2
--
2.37.3

View File

@ -1,105 +0,0 @@
From 7d5b1d2178d0573f137b9481ded85419a36998ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Thu, 6 Oct 2022 10:55:50 +0100
Subject: [PATCH] fopen: Workaround bad buffering for binary mode (#563)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
A lot of code assumes Python 2.x behavior for buffering, in which 1 is a
special value meaning line buffered.
Python 3 makes this value unusable, so fallback to the default buffering
size, and report these calls to be fixed.
Fixes: https://github.com/saltstack/salt/issues/57584
Do not drop buffering from kwargs to avoid errors
Add unit test around linebuffering in binary mode
Add changelog file
Co-authored-by: Pablo Suárez Hernández <psuarezhernandez@suse.com>
Co-authored-by: Ismael Luceno <iluceno@suse.de>
---
changelog/62817.fixed | 1 +
salt/utils/files.py | 8 ++++++++
tests/pytests/unit/utils/test_files.py | 13 ++++++++++++-
3 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 changelog/62817.fixed
diff --git a/changelog/62817.fixed b/changelog/62817.fixed
new file mode 100644
index 0000000000..ff335f2916
--- /dev/null
+++ b/changelog/62817.fixed
@@ -0,0 +1 @@
+Prevent annoying RuntimeWarning message about line buffering (buffering=1) not being supported in binary mode
diff --git a/salt/utils/files.py b/salt/utils/files.py
index 1cf636a753..3c57cce713 100644
--- a/salt/utils/files.py
+++ b/salt/utils/files.py
@@ -6,6 +6,7 @@ Functions for working with files
import codecs
import contextlib
import errno
+import io
import logging
import os
import re
@@ -382,6 +383,13 @@ def fopen(*args, **kwargs):
if not binary and not kwargs.get("newline", None):
kwargs["newline"] = ""
+ # Workaround callers with bad buffering setting for binary files
+ if kwargs.get("buffering") == 1 and "b" in kwargs.get("mode", ""):
+ log.debug(
+ "Line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used"
+ )
+ kwargs["buffering"] = io.DEFAULT_BUFFER_SIZE
+
f_handle = open(*args, **kwargs) # pylint: disable=resource-leakage
if is_fcntl_available():
diff --git a/tests/pytests/unit/utils/test_files.py b/tests/pytests/unit/utils/test_files.py
index fd88167b16..bd18bc5750 100644
--- a/tests/pytests/unit/utils/test_files.py
+++ b/tests/pytests/unit/utils/test_files.py
@@ -4,11 +4,12 @@ Unit Tests for functions located in salt/utils/files.py
import copy
+import io
import os
import pytest
import salt.utils.files
-from tests.support.mock import patch
+from tests.support.mock import MagicMock, patch
def test_safe_rm():
@@ -74,6 +75,16 @@ def test_fopen_with_disallowed_fds():
)
+def test_fopen_binary_line_buffering(tmp_path):
+ tmp_file = os.path.join(tmp_path, "foobar")
+ with patch("builtins.open") as open_mock, patch(
+ "salt.utils.files.is_fcntl_available", MagicMock(return_value=False)
+ ):
+ salt.utils.files.fopen(os.path.join(tmp_path, "foobar"), mode="b", buffering=1)
+ assert open_mock.called
+ assert open_mock.call_args[1]["buffering"] == io.DEFAULT_BUFFER_SIZE
+
+
def _create_temp_structure(temp_directory, structure):
for folder, files in structure.items():
current_directory = os.path.join(temp_directory, folder)
--
2.37.3

BIN
html.tar.bz2 (Stored with Git LFS)

Binary file not shown.

View File

@ -1,56 +0,0 @@
From 7cac5f67eb0d586314f9e7c987b8a620e28eeac3 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Mon, 27 Jun 2022 17:55:49 +0300
Subject: [PATCH] Ignore erros on reading license files with dpkg_lowpkg
(bsc#1197288)
* Ignore erros on reading license files with dpkg_lowpkg (bsc#1197288)
* Add test for license reading with dpkg_lowpkg
---
salt/modules/dpkg_lowpkg.py | 2 +-
tests/pytests/unit/modules/test_dpkg_lowpkg.py | 18 ++++++++++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)
create mode 100644 tests/pytests/unit/modules/test_dpkg_lowpkg.py
diff --git a/salt/modules/dpkg_lowpkg.py b/salt/modules/dpkg_lowpkg.py
index afbd619490..2c25b1fb2a 100644
--- a/salt/modules/dpkg_lowpkg.py
+++ b/salt/modules/dpkg_lowpkg.py
@@ -361,7 +361,7 @@ def _get_pkg_license(pkg):
licenses = set()
cpr = "/usr/share/doc/{}/copyright".format(pkg)
if os.path.exists(cpr):
- with salt.utils.files.fopen(cpr) as fp_:
+ with salt.utils.files.fopen(cpr, errors="ignore") as fp_:
for line in salt.utils.stringutils.to_unicode(fp_.read()).split(os.linesep):
if line.startswith("License:"):
licenses.add(line.split(":", 1)[1].strip())
diff --git a/tests/pytests/unit/modules/test_dpkg_lowpkg.py b/tests/pytests/unit/modules/test_dpkg_lowpkg.py
new file mode 100644
index 0000000000..1a89660c02
--- /dev/null
+++ b/tests/pytests/unit/modules/test_dpkg_lowpkg.py
@@ -0,0 +1,18 @@
+import os
+
+import salt.modules.dpkg_lowpkg as dpkg
+from tests.support.mock import MagicMock, mock_open, patch
+
+
+def test_get_pkg_license():
+ """
+ Test _get_pkg_license for ignore errors on reading license from copyright files
+ """
+ license_read_mock = mock_open(read_data="")
+ with patch.object(os.path, "exists", MagicMock(return_value=True)), patch(
+ "salt.utils.files.fopen", license_read_mock
+ ):
+ dpkg._get_pkg_license("bash")
+
+ assert license_read_mock.calls[0].args[0] == "/usr/share/doc/bash/copyright"
+ assert license_read_mock.calls[0].kwargs["errors"] == "ignore"
--
2.37.3

View File

@ -1,250 +0,0 @@
From e4aff9ca68ce142c87ec875846d8916b9df8e6c5 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Fri, 21 Oct 2022 14:39:52 +0200
Subject: [PATCH] Ignore extend declarations from excluded sls files
* Use both test sls files
(cherry picked from commit 3cb5f5a14ff68d0bd809a4adba7d820534d0f7c7)
* Test that excluded sls files can't extend others
(cherry picked from commit e91c1a608b3c016b2c30bf324e969cd097ddf776)
* Ignore extend declarations from excluded sls files
sls files that are excluded should not affect other sls files by
extending their states. Exclude statements are processed very late in
the state processing pipeline to ensure they are not overridden. By that
time, extend declarations are already processed.
Luckily, it's not necessary to change much, during the extend
declarations processing it is easy to check if the sls file that
contains a given extend declaration is excluded.
(cherry picked from commit 856b23c45dd3be78d8879a0b0c4aa6356afea3cf)
---
changelog/62082.fixed | 1 +
salt/state.py | 19 +++
.../unit/state/test_state_highstate.py | 152 +++++++++++++++++-
3 files changed, 171 insertions(+), 1 deletion(-)
create mode 100644 changelog/62082.fixed
diff --git a/changelog/62082.fixed b/changelog/62082.fixed
new file mode 100644
index 0000000000..02e5f5ff40
--- /dev/null
+++ b/changelog/62082.fixed
@@ -0,0 +1 @@
+Ignore extend declarations in sls files that are excluded.
diff --git a/salt/state.py b/salt/state.py
index 316dcdec63..f5579fbb69 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -1680,6 +1680,25 @@ class State:
else:
name = ids[0][0]
+ sls_excludes = []
+ # excluded sls are plain list items or dicts with an "sls" key
+ for exclude in high.get("__exclude__", []):
+ if isinstance(exclude, str):
+ sls_excludes.append(exclude)
+ elif exclude.get("sls"):
+ sls_excludes.append(exclude["sls"])
+
+ if body.get("__sls__") in sls_excludes:
+ log.debug(
+ "Cannot extend ID '%s' in '%s:%s' because '%s:%s' is excluded.",
+ name,
+ body.get("__env__", "base"),
+ body.get("__sls__", "base"),
+ body.get("__env__", "base"),
+ body.get("__sls__", "base"),
+ )
+ continue
+
for state, run in body.items():
if state.startswith("__"):
continue
diff --git a/tests/pytests/unit/state/test_state_highstate.py b/tests/pytests/unit/state/test_state_highstate.py
index 059f83fd9f..7c72cc8e09 100644
--- a/tests/pytests/unit/state/test_state_highstate.py
+++ b/tests/pytests/unit/state/test_state_highstate.py
@@ -3,9 +3,11 @@
"""
import logging
+import textwrap
import pytest # pylint: disable=unused-import
import salt.state
+from salt.utils.odict import OrderedDict
log = logging.getLogger(__name__)
@@ -180,7 +182,7 @@ def test_find_sls_ids_with_exclude(highstate, state_tree_dir):
with pytest.helpers.temp_file(
"slsfile1.sls", slsfile1, sls_dir
), pytest.helpers.temp_file(
- "slsfile1.sls", slsfile1, sls_dir
+ "slsfile2.sls", slsfile2, sls_dir
), pytest.helpers.temp_file(
"stateB.sls", stateB, sls_dir
), pytest.helpers.temp_file(
@@ -196,3 +198,151 @@ def test_find_sls_ids_with_exclude(highstate, state_tree_dir):
high, _ = highstate.render_highstate(matches)
ret = salt.state.find_sls_ids("issue-47182.stateA.newer", high)
assert ret == [("somestuff", "cmd")]
+
+
+def test_dont_extend_in_excluded_sls_file(highstate, state_tree_dir):
+ """
+ See https://github.com/saltstack/salt/issues/62082#issuecomment-1245461333
+ """
+ top_sls = textwrap.dedent(
+ """\
+ base:
+ '*':
+ - test1
+ - exclude
+ """
+ )
+ exclude_sls = textwrap.dedent(
+ """\
+ exclude:
+ - sls: test2
+ """
+ )
+ test1_sls = textwrap.dedent(
+ """\
+ include:
+ - test2
+
+ test1:
+ cmd.run:
+ - name: echo test1
+ """
+ )
+ test2_sls = textwrap.dedent(
+ """\
+ extend:
+ test1:
+ cmd.run:
+ - name: echo "override test1 in test2"
+
+ test2-id:
+ cmd.run:
+ - name: echo test2
+ """
+ )
+ sls_dir = str(state_tree_dir)
+ with pytest.helpers.temp_file(
+ "top.sls", top_sls, sls_dir
+ ), pytest.helpers.temp_file(
+ "test1.sls", test1_sls, sls_dir
+ ), pytest.helpers.temp_file(
+ "test2.sls", test2_sls, sls_dir
+ ), pytest.helpers.temp_file(
+ "exclude.sls", exclude_sls, sls_dir
+ ):
+ # manually compile the high data, error checking is not needed in this
+ # test case.
+ top = highstate.get_top()
+ matches = highstate.top_matches(top)
+ high, _ = highstate.render_highstate(matches)
+
+ # high is mutated by call_high and the different "pipeline steps"
+ assert high == OrderedDict(
+ [
+ (
+ "__extend__",
+ [
+ {
+ "test1": OrderedDict(
+ [
+ ("__sls__", "test2"),
+ ("__env__", "base"),
+ (
+ "cmd",
+ [
+ OrderedDict(
+ [
+ (
+ "name",
+ 'echo "override test1 in test2"',
+ )
+ ]
+ ),
+ "run",
+ ],
+ ),
+ ]
+ )
+ }
+ ],
+ ),
+ (
+ "test1",
+ OrderedDict(
+ [
+ (
+ "cmd",
+ [
+ OrderedDict([("name", "echo test1")]),
+ "run",
+ {"order": 10001},
+ ],
+ ),
+ ("__sls__", "test1"),
+ ("__env__", "base"),
+ ]
+ ),
+ ),
+ (
+ "test2-id",
+ OrderedDict(
+ [
+ (
+ "cmd",
+ [
+ OrderedDict([("name", "echo test2")]),
+ "run",
+ {"order": 10000},
+ ],
+ ),
+ ("__sls__", "test2"),
+ ("__env__", "base"),
+ ]
+ ),
+ ),
+ ("__exclude__", [OrderedDict([("sls", "test2")])]),
+ ]
+ )
+ highstate.state.call_high(high)
+ # assert that the extend declaration was not applied
+ assert high == OrderedDict(
+ [
+ (
+ "test1",
+ OrderedDict(
+ [
+ (
+ "cmd",
+ [
+ OrderedDict([("name", "echo test1")]),
+ "run",
+ {"order": 10001},
+ ],
+ ),
+ ("__sls__", "test1"),
+ ("__env__", "base"),
+ ]
+ ),
+ )
+ ]
+ )
--
2.37.3

View File

@ -1,214 +0,0 @@
From 3f1b1180ba34e9ab3a4453248c733f11aa193f1b Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <Victor.Zhestkov@suse.com>
Date: Wed, 14 Sep 2022 14:57:29 +0300
Subject: [PATCH] Ignore non utf8 characters while reading files with
core grains module (bsc#1202165)
* Ignore UnicodeDecodeError on reading files with core grains
* Add tests for non utf8 chars in cmdline
* Blacken modified lines
* Fix the tests
* Add changelog entry
* Change ignore to surrogateescape for kernelparameters
* Turn static test files to dynamic
---
changelog/62633.fixed | 1 +
salt/grains/core.py | 12 ++-
tests/pytests/unit/grains/test_core.py | 118 +++++++++++++++++++++++++
3 files changed, 128 insertions(+), 3 deletions(-)
create mode 100644 changelog/62633.fixed
diff --git a/changelog/62633.fixed b/changelog/62633.fixed
new file mode 100644
index 0000000000..1ab74f9122
--- /dev/null
+++ b/changelog/62633.fixed
@@ -0,0 +1 @@
+Prevent possible tracebacks in core grains module by ignoring non utf8 characters in /proc/1/environ, /proc/1/cmdline, /proc/cmdline
diff --git a/salt/grains/core.py b/salt/grains/core.py
index 047c33ffd3..76f3767ddf 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -1089,7 +1089,9 @@ def _virtual(osdata):
if ("virtual_subtype" not in grains) or (grains["virtual_subtype"] != "LXC"):
if os.path.isfile("/proc/1/environ"):
try:
- with salt.utils.files.fopen("/proc/1/environ", "r") as fhr:
+ with salt.utils.files.fopen(
+ "/proc/1/environ", "r", errors="ignore"
+ ) as fhr:
fhr_contents = fhr.read()
if "container=lxc" in fhr_contents:
grains["virtual"] = "container"
@@ -1909,7 +1911,9 @@ def os_data():
grains["init"] = "systemd"
except OSError:
try:
- with salt.utils.files.fopen("/proc/1/cmdline") as fhr:
+ with salt.utils.files.fopen(
+ "/proc/1/cmdline", "r", errors="ignore"
+ ) as fhr:
init_cmdline = fhr.read().replace("\x00", " ").split()
except OSError:
pass
@@ -3154,7 +3158,9 @@ def kernelparams():
return {}
else:
try:
- with salt.utils.files.fopen("/proc/cmdline", "r") as fhr:
+ with salt.utils.files.fopen(
+ "/proc/cmdline", "r", errors="surrogateescape"
+ ) as fhr:
cmdline = fhr.read()
grains = {"kernelparams": []}
for data in [
diff --git a/tests/pytests/unit/grains/test_core.py b/tests/pytests/unit/grains/test_core.py
index 7c4ea1f17f..c06cdb2db0 100644
--- a/tests/pytests/unit/grains/test_core.py
+++ b/tests/pytests/unit/grains/test_core.py
@@ -11,6 +11,7 @@ import os
import pathlib
import platform
import socket
+import tempfile
import textwrap
from collections import namedtuple
@@ -2738,6 +2739,38 @@ def test_kernelparams_return_linux(cmdline, expectation):
assert core.kernelparams() == expectation
+@pytest.mark.skip_unless_on_linux
+def test_kernelparams_return_linux_non_utf8():
+ _salt_utils_files_fopen = salt.utils.files.fopen
+
+ expected = {
+ "kernelparams": [
+ ("TEST_KEY1", "VAL1"),
+ ("TEST_KEY2", "VAL2"),
+ ("BOOTABLE_FLAG", "\udc80"),
+ ("TEST_KEY_NOVAL", None),
+ ("TEST_KEY3", "3"),
+ ]
+ }
+
+ with tempfile.TemporaryDirectory() as tempdir:
+
+ def _open_mock(file_name, *args, **kwargs):
+ return _salt_utils_files_fopen(
+ os.path.join(tempdir, "cmdline"), *args, **kwargs
+ )
+
+ with salt.utils.files.fopen(
+ os.path.join(tempdir, "cmdline"),
+ "wb",
+ ) as cmdline_fh, patch("salt.utils.files.fopen", _open_mock):
+ cmdline_fh.write(
+ b'TEST_KEY1=VAL1 TEST_KEY2=VAL2 BOOTABLE_FLAG="\x80" TEST_KEY_NOVAL TEST_KEY3=3\n'
+ )
+ cmdline_fh.close()
+ assert core.kernelparams() == expected
+
+
def test_linux_gpus():
"""
Test GPU detection on Linux systems
@@ -2940,3 +2973,88 @@ def test_virtual_set_virtual_ec2():
assert virtual_grains["virtual"] == "kvm"
assert "virtual_subtype" not in virtual_grains
+
+
+@pytest.mark.skip_on_windows
+def test_linux_proc_files_with_non_utf8_chars():
+ _salt_utils_files_fopen = salt.utils.files.fopen
+
+ empty_mock = MagicMock(return_value={})
+
+ with tempfile.TemporaryDirectory() as tempdir:
+
+ def _mock_open(filename, *args, **kwargs):
+ return _salt_utils_files_fopen(
+ os.path.join(tempdir, "cmdline-1"), *args, **kwargs
+ )
+
+ with salt.utils.files.fopen(
+ os.path.join(tempdir, "cmdline-1"),
+ "wb",
+ ) as cmdline_fh, patch("os.path.isfile", return_value=False), patch(
+ "salt.utils.files.fopen", _mock_open
+ ), patch.dict(
+ core.__salt__,
+ {
+ "cmd.retcode": salt.modules.cmdmod.retcode,
+ "cmd.run": MagicMock(return_value=""),
+ },
+ ), patch.object(
+ core, "_linux_bin_exists", return_value=False
+ ), patch.object(
+ core, "_parse_lsb_release", return_value=empty_mock
+ ), patch.object(
+ core, "_parse_os_release", return_value=empty_mock
+ ), patch.object(
+ core, "_hw_data", return_value=empty_mock
+ ), patch.object(
+ core, "_virtual", return_value=empty_mock
+ ), patch.object(
+ core, "_bsd_cpudata", return_value=empty_mock
+ ), patch.object(
+ os, "stat", side_effect=OSError()
+ ):
+ cmdline_fh.write(
+ b"/usr/lib/systemd/systemd\x00--switched-root\x00--system\x00--deserialize\x0028\x80\x00"
+ )
+ cmdline_fh.close()
+ os_grains = core.os_data()
+ assert os_grains != {}
+
+
+@pytest.mark.skip_on_windows
+def test_virtual_linux_proc_files_with_non_utf8_chars():
+ _salt_utils_files_fopen = salt.utils.files.fopen
+
+ def _is_file_mock(filename):
+ if filename == "/proc/1/environ":
+ return True
+ return False
+
+ with tempfile.TemporaryDirectory() as tempdir:
+
+ def _mock_open(filename, *args, **kwargs):
+ return _salt_utils_files_fopen(
+ os.path.join(tempdir, "environ"), *args, **kwargs
+ )
+
+ with salt.utils.files.fopen(
+ os.path.join(tempdir, "environ"),
+ "wb",
+ ) as environ_fh, patch("os.path.isfile", _is_file_mock), patch(
+ "salt.utils.files.fopen", _mock_open
+ ), patch.object(
+ salt.utils.path, "which", MagicMock(return_value=None)
+ ), patch.dict(
+ core.__salt__,
+ {
+ "cmd.run_all": MagicMock(
+ return_value={"retcode": 1, "stderr": "", "stdout": ""}
+ ),
+ "cmd.run": MagicMock(return_value=""),
+ },
+ ):
+ environ_fh.write(b"KEY1=VAL1 KEY2=VAL2\x80 KEY2=VAL2")
+ environ_fh.close()
+ virt_grains = core._virtual({"kernel": "Linux"})
+ assert virt_grains == {"virtual": "physical"}
--
2.37.3

View File

@ -1,4 +1,4 @@
From 797b256548cbcda0f3828c6d182c44a3815dd313 Mon Sep 17 00:00:00 2001
From 4f459d670886a8f4a410fdbd1ec595477d45e4e2 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 17:10:37 +0100
Subject: [PATCH] Include aliases in the fqdns grains
@ -31,10 +31,10 @@ Co-authored-by: Eric Siebigteroth <eric.siebigteroth@suse.de>
4 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/salt/modules/network.py b/salt/modules/network.py
index 1149c96097..8c2d188903 100644
index 524b1b74fa..f959dbf97b 100644
--- a/salt/modules/network.py
+++ b/salt/modules/network.py
@@ -2100,7 +2100,10 @@ def fqdns():
@@ -2096,7 +2096,10 @@ def fqdns():
# https://sourceware.org/bugzilla/show_bug.cgi?id=19329
time.sleep(random.randint(5, 25) / 1000)
try:
@ -47,13 +47,13 @@ index 1149c96097..8c2d188903 100644
if err.errno in (0, HOST_NOT_FOUND, NO_DATA):
# No FQDN for this IP address, so we don't need to know this all the time.
diff --git a/salt/utils/network.py b/salt/utils/network.py
index d042cd177d..bccda01556 100644
index 2bea2cf129..6ec993a678 100644
--- a/salt/utils/network.py
+++ b/salt/utils/network.py
@@ -2332,3 +2332,19 @@ def filter_by_networks(values, networks):
raise ValueError("Do not know how to filter a {}".format(type(values)))
else:
return values
@@ -2372,3 +2372,19 @@ def ip_bracket(addr, strip=False):
addr = addr.rstrip("]")
addr = ipaddress.ip_address(addr)
return ("[{}]" if addr.version == 6 and not strip else "{}").format(addr)
+
+
+def is_fqdn(hostname):
@ -71,10 +71,10 @@ index d042cd177d..bccda01556 100644
+ and all(compliant.match(x) for x in hostname.rstrip(".").split("."))
+ )
diff --git a/tests/pytests/unit/modules/test_network.py b/tests/pytests/unit/modules/test_network.py
index 15fd5545a0..b948e578bb 100644
index 81035434b6..3f31391f44 100644
--- a/tests/pytests/unit/modules/test_network.py
+++ b/tests/pytests/unit/modules/test_network.py
@@ -28,7 +28,7 @@ def fake_fqdn():
@@ -29,7 +29,7 @@ def fake_fqdn():
with patch("socket.getfqdn", autospec=True, return_value=fqdn), patch(
"socket.gethostbyaddr",
autospec=True,
@ -83,7 +83,7 @@ index 15fd5545a0..b948e578bb 100644
):
yield fqdn
@@ -88,7 +88,7 @@ def test_fqdns_should_return_sorted_unique_domains(fake_ips):
@@ -89,7 +89,7 @@ def test_fqdns_should_return_sorted_unique_domains(fake_ips):
with patch("socket.getfqdn", autospec=True, side_effect=fake_domains), patch(
"socket.gethostbyaddr",
autospec=True,
@ -93,13 +93,13 @@ index 15fd5545a0..b948e578bb 100644
actual_fqdns = networkmod.fqdns()
assert actual_fqdns == {
diff --git a/tests/unit/utils/test_network.py b/tests/unit/utils/test_network.py
index 422f85d68c..3060aba0aa 100644
index f7d3972930..cdb1ca19ca 100644
--- a/tests/unit/utils/test_network.py
+++ b/tests/unit/utils/test_network.py
@@ -1269,3 +1269,35 @@ class NetworkTestCase(TestCase):
),
):
self.assertEqual(network.get_fqhostname(), host)
@@ -1311,3 +1311,35 @@ class NetworkTestCase(TestCase):
ip_addr_obj = ipaddress.ip_address(test_ipv4)
self.assertEqual(test_ipv4, network.ip_bracket(ip_addr_obj))
+
+ def test_is_fqdn(self):
+ """
@ -133,6 +133,6 @@ index 422f85d68c..3060aba0aa 100644
+ ]:
+ assert not network.is_fqdn(fqdn)
--
2.37.3
2.39.2

View File

@ -1,63 +0,0 @@
From f9fe9ea009915478ea8f7896dff2c281e68b5d36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Yeray=20Guti=C3=A9rrez=20Cedr=C3=A9s?=
<yeray.gutierrez@suse.com>
Date: Fri, 14 Oct 2022 08:41:40 +0100
Subject: [PATCH] Include stdout in error message for zypperpkg (#559)
---
salt/modules/zypperpkg.py | 5 +++++
tests/unit/modules/test_zypperpkg.py | 17 ++++++++++++++++-
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index c787d4009d..5d745c432d 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -339,6 +339,11 @@ class _Zypper:
and self.__call_result["stderr"].strip()
or ""
)
+ msg += (
+ self.__call_result["stdout"]
+ and self.__call_result["stdout"].strip()
+ or ""
+ )
if msg:
_error_msg.append(msg)
else:
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
index 37d555844c..bcd001cd85 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -207,11 +207,26 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
):
zypper.__zypper__.xml.call("crashme")
+ output_to_user_stdout = "Output to user to stdout"
+ output_to_user_stderr = "Output to user to stderr"
+ sniffer = RunSniffer(
+ stdout=output_to_user_stdout, stderr=output_to_user_stderr, retcode=1
+ )
+ with patch.dict(
+ "salt.modules.zypperpkg.__salt__", {"cmd.run_all": sniffer}
+ ), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
with self.assertRaisesRegex(
- CommandExecutionError, "^Zypper command failure: Check Zypper's logs.$"
+ CommandExecutionError,
+ "^Zypper command failure: {}$".format(
+ output_to_user_stderr + output_to_user_stdout
+ ),
):
zypper.__zypper__.call("crashme again")
+ sniffer = RunSniffer(retcode=1)
+ with patch.dict(
+ "salt.modules.zypperpkg.__salt__", {"cmd.run_all": sniffer}
+ ), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
zypper.__zypper__.noraise.call("stay quiet")
self.assertEqual(zypper.__zypper__.error_msg, "Check Zypper's logs.")
--
2.37.3

View File

@ -1,4 +1,4 @@
From 55fc248aabd486f8ae4ff2bc755d653cdc39a4bb Mon Sep 17 00:00:00 2001
From 01a670dad69e03bd8bf2da76a6a81e847af20aab Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 25 Jan 2022 17:12:47 +0100
Subject: [PATCH] info_installed works without status attr now
@ -12,10 +12,10 @@ detect if a package was installed or not. Now info_installed adds the
2 files changed, 27 insertions(+)
diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py
index 4a2281c47f..544143d286 100644
index 938e37cc9e..3289f6604d 100644
--- a/salt/modules/aptpkg.py
+++ b/salt/modules/aptpkg.py
@@ -3479,6 +3479,15 @@ def info_installed(*names, **kwargs):
@@ -3461,6 +3461,15 @@ def info_installed(*names, **kwargs):
failhard = kwargs.pop("failhard", True)
kwargs.pop("errors", None) # Only for compatibility with RPM
attr = kwargs.pop("attr", None) # Package attributes to return
@ -32,10 +32,10 @@ index 4a2281c47f..544143d286 100644
"all_versions", False
) # This is for backward compatible structure only
diff --git a/tests/pytests/unit/modules/test_aptpkg.py b/tests/pytests/unit/modules/test_aptpkg.py
index 8e404a673c..76b59d8604 100644
index 4226957eeb..eb72447c3a 100644
--- a/tests/pytests/unit/modules/test_aptpkg.py
+++ b/tests/pytests/unit/modules/test_aptpkg.py
@@ -384,6 +384,24 @@ def test_info_installed_attr(lowpkg_info_var):
@@ -385,6 +385,24 @@ def test_info_installed_attr(lowpkg_info_var):
assert ret["wget"] == expected_pkg
@ -61,6 +61,6 @@ index 8e404a673c..76b59d8604 100644
"""
Test info_installed 'all_versions'.
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From c68a988ebcc7bae06231c9a9ebc3d654a7d6ffbc Mon Sep 17 00:00:00 2001
From 1de8313e55317a62c36a1a6262e7b9463544d69c Mon Sep 17 00:00:00 2001
From: Can Bulut Bayburt <1103552+cbbayburt@users.noreply.github.com>
Date: Wed, 4 Dec 2019 15:59:46 +0100
Subject: [PATCH] Let salt-ssh use 'platform-python' binary in RHEL8
@ -14,19 +14,19 @@ creating the sh shim.
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index 5e557c51da..ef162d2270 100644
index 88365a6099..049baff51a 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -146,7 +146,7 @@ if [ "$SUDO" ] && [ "$SUDO_USER" ]
then SUDO="$SUDO -u $SUDO_USER"
fi
EX_PYTHON_INVALID={EX_THIN_PYTHON_INVALID}
-PYTHON_CMDS="python3 python27 python2.7 python26 python2.6 python2 python"
-PYTHON_CMDS="python3 python27 python2.7 python26 python2.6 python2 python /usr/libexec/platform-python"
+PYTHON_CMDS="python3 /usr/libexec/platform-python python27 python2.7 python26 python2.6 python2 python"
for py_cmd in $PYTHON_CMDS
do
if command -v "$py_cmd" >/dev/null 2>&1 && "$py_cmd" -c "import sys; sys.exit(not (sys.version_info >= (2, 6)));"
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From f113f94d40ee37919aa974a4fab95e482c5a0631 Mon Sep 17 00:00:00 2001
From f9731227e7af0b1bf0a54993e0cac890225517f6 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Fri, 16 Nov 2018 10:54:12 +0100
Subject: [PATCH] Make aptpkg.list_repos compatible on enabled/disabled
@ -9,10 +9,10 @@ Subject: [PATCH] Make aptpkg.list_repos compatible on enabled/disabled
1 file changed, 3 insertions(+)
diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py
index 94e97a0b5b..0cbd611b71 100644
index f68b1907e8..8e89744b5e 100644
--- a/salt/modules/aptpkg.py
+++ b/salt/modules/aptpkg.py
@@ -1933,6 +1933,9 @@ def list_repos(**kwargs):
@@ -1919,6 +1919,9 @@ def list_repos(**kwargs):
repo["file"] = source.file
repo["comps"] = getattr(source, "comps", [])
repo["disabled"] = source.disabled
@ -23,6 +23,6 @@ index 94e97a0b5b..0cbd611b71 100644
repo["type"] = source.type
repo["uri"] = source.uri
--
2.37.3
2.39.2

View File

@ -1,414 +0,0 @@
From 030e2cb20af09673d5f38d68bcb257c6c839a2f3 Mon Sep 17 00:00:00 2001
From: Daniel Mach <daniel.mach@gmail.com>
Date: Thu, 6 Oct 2022 11:58:23 +0200
Subject: [PATCH] Make pass renderer configurable & other fixes (#532)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* pass: Use a secure way of handling pass arguments
The original code would fail on pass paths with spaces,
because they would be split into multiple arguments.
* pass: Strip only trailing newline characters from the secret
* pass: Do not modify $HOME env globally
Just set $HOME for calling the pass binary
to avoid affecting anything outside the pass renderer.
* pass: Use pass executable path from _get_pass_exec()
* Make the pass renderer more configurable
1. Allow us to make the pass renderer fail during pillar rendering
when a secret corresponding with a pass path cannot be fetched.
For this we add a master config variable pass_strict_fetch.
2. Allow to have prefix for variables that should be processed
with the pass renderer.
For this we add a master config variable pass_variable_prefix.
3. Allow us to configure pass' GNUPGHOME and PASSWORD_STORE_DIR
environmental variables.
For this we add master config variables pass_gnupghome and pass_dir.
* Add tests for the pass renderer
* pass: Handle FileNotFoundError when pass binary is not available
Co-authored-by: Marcus Rückert <darix@nordisch.org>
---
changelog/62120.added | 4 +
changelog/62120.fixed | 4 +
salt/config/__init__.py | 12 ++
salt/renderers/pass.py | 104 ++++++++++++--
tests/pytests/unit/renderers/test_pass.py | 164 ++++++++++++++++++++++
5 files changed, 274 insertions(+), 14 deletions(-)
create mode 100644 changelog/62120.added
create mode 100644 changelog/62120.fixed
create mode 100644 tests/pytests/unit/renderers/test_pass.py
diff --git a/changelog/62120.added b/changelog/62120.added
new file mode 100644
index 0000000000..4303d124f0
--- /dev/null
+++ b/changelog/62120.added
@@ -0,0 +1,4 @@
+Config option pass_variable_prefix allows to distinguish variables that contain paths to pass secrets.
+Config option pass_strict_fetch allows to error out when a secret cannot be fetched from pass.
+Config option pass_dir allows setting the PASSWORD_STORE_DIR env for pass.
+Config option pass_gnupghome allows setting the $GNUPGHOME env for pass.
diff --git a/changelog/62120.fixed b/changelog/62120.fixed
new file mode 100644
index 0000000000..22a9711383
--- /dev/null
+++ b/changelog/62120.fixed
@@ -0,0 +1,4 @@
+Pass executable path from _get_path_exec() is used when calling the program.
+The $HOME env is no longer modified globally.
+Only trailing newlines are stripped from the fetched secret.
+Pass process arguments are handled in a secure way.
diff --git a/salt/config/__init__.py b/salt/config/__init__.py
index 7cdee12c4d..0cc0deb874 100644
--- a/salt/config/__init__.py
+++ b/salt/config/__init__.py
@@ -967,6 +967,14 @@ VALID_OPTS = immutabletypes.freeze(
# Use Adler32 hashing algorithm for server_id (default False until Sodium, "adler32" after)
# Possible values are: False, adler32, crc32
"server_id_use_crc": (bool, str),
+ # pass renderer: Fetch secrets only for the template variables matching the prefix
+ "pass_variable_prefix": str,
+ # pass renderer: Whether to error out when unable to fetch a secret
+ "pass_strict_fetch": bool,
+ # pass renderer: Set GNUPGHOME env for Pass
+ "pass_gnupghome": str,
+ # pass renderer: Set PASSWORD_STORE_DIR env for Pass
+ "pass_dir": str,
}
)
@@ -1608,6 +1616,10 @@ DEFAULT_MASTER_OPTS = immutabletypes.freeze(
"fips_mode": False,
"detect_remote_minions": False,
"remote_minions_port": 22,
+ "pass_variable_prefix": "",
+ "pass_strict_fetch": False,
+ "pass_gnupghome": "",
+ "pass_dir": "",
}
)
diff --git a/salt/renderers/pass.py b/salt/renderers/pass.py
index 71b1021b96..ba0f152c23 100644
--- a/salt/renderers/pass.py
+++ b/salt/renderers/pass.py
@@ -45,6 +45,34 @@ Install pass binary
pass:
pkg.installed
+
+Salt master configuration options
+
+.. code-block:: yaml
+
+ # If the prefix is *not* set (default behavior), all template variables are
+ # considered for fetching secrets from Pass. Those that cannot be resolved
+ # to a secret are passed through.
+ #
+ # If the prefix is set, only the template variables with matching prefix are
+ # considered for fetching the secrets, other variables are passed through.
+ #
+ # For ease of use it is recommended to set the following options as well:
+ # renderer: 'jinja|yaml|pass'
+ # pass_strict_fetch: true
+ #
+ pass_variable_prefix: 'pass:'
+
+ # If set to 'true', error out when unable to fetch a secret for a template variable.
+ pass_strict_fetch: true
+
+ # Set GNUPGHOME env for Pass.
+ # Defaults to: ~/.gnupg
+ pass_gnupghome: <path>
+
+ # Set PASSWORD_STORE_DIR env for Pass.
+ # Defaults to: ~/.password-store
+ pass_dir: <path>
"""
@@ -54,7 +82,7 @@ from os.path import expanduser
from subprocess import PIPE, Popen
import salt.utils.path
-from salt.exceptions import SaltRenderError
+from salt.exceptions import SaltConfigurationError, SaltRenderError
log = logging.getLogger(__name__)
@@ -75,18 +103,71 @@ def _fetch_secret(pass_path):
Fetch secret from pass based on pass_path. If there is
any error, return back the original pass_path value
"""
- cmd = "pass show {}".format(pass_path.strip())
- log.debug("Fetching secret: %s", cmd)
+ pass_exec = _get_pass_exec()
+
+ # Make a backup in case we want to return the original value without stripped whitespaces
+ original_pass_path = pass_path
+
+ # Remove the optional prefix from pass path
+ pass_prefix = __opts__["pass_variable_prefix"]
+ if pass_prefix:
+ # If we do not see our prefix we do not want to process this variable
+ # and we return the unmodified pass path
+ if not pass_path.startswith(pass_prefix):
+ return pass_path
+
+ # strip the prefix from the start of the string
+ pass_path = pass_path[len(pass_prefix) :]
+
+ # The pass_strict_fetch option must be used with pass_variable_prefix
+ pass_strict_fetch = __opts__["pass_strict_fetch"]
+ if pass_strict_fetch and not pass_prefix:
+ msg = "The 'pass_strict_fetch' option requires 'pass_variable_prefix' option enabled"
+ raise SaltConfigurationError(msg)
+
+ # Remove whitespaces from the pass_path
+ pass_path = pass_path.strip()
- proc = Popen(cmd.split(" "), stdout=PIPE, stderr=PIPE)
- pass_data, pass_error = proc.communicate()
+ cmd = [pass_exec, "show", pass_path]
+ log.debug("Fetching secret: %s", " ".join(cmd))
+
+ # Make sure environment variable HOME is set, since Pass looks for the
+ # password-store under ~/.password-store.
+ env = os.environ.copy()
+ env["HOME"] = expanduser("~")
+
+ pass_dir = __opts__["pass_dir"]
+ if pass_dir:
+ env["PASSWORD_STORE_DIR"] = pass_dir
+
+ pass_gnupghome = __opts__["pass_gnupghome"]
+ if pass_gnupghome:
+ env["GNUPGHOME"] = pass_gnupghome
+
+ try:
+ proc = Popen(cmd, stdout=PIPE, stderr=PIPE, env=env)
+ pass_data, pass_error = proc.communicate()
+ pass_returncode = proc.returncode
+ except OSError as e:
+ pass_data, pass_error = "", str(e)
+ pass_returncode = 1
# The version of pass used during development sent output to
# stdout instead of stderr even though its returncode was non zero.
- if proc.returncode or not pass_data:
- log.warning("Could not fetch secret: %s %s", pass_data, pass_error)
- pass_data = pass_path
- return pass_data.strip()
+ if pass_returncode or not pass_data:
+ try:
+ pass_error = pass_error.decode("utf-8")
+ except (AttributeError, ValueError):
+ pass
+ msg = "Could not fetch secret '{}' from the password store: {}".format(
+ pass_path, pass_error
+ )
+ if pass_strict_fetch:
+ raise SaltRenderError(msg)
+ else:
+ log.warning(msg)
+ return original_pass_path
+ return pass_data.rstrip("\r\n")
def _decrypt_object(obj):
@@ -108,9 +189,4 @@ def render(pass_info, saltenv="base", sls="", argline="", **kwargs):
"""
Fetch secret from pass based on pass_path
"""
- _get_pass_exec()
-
- # Make sure environment variable HOME is set, since Pass looks for the
- # password-store under ~/.password-store.
- os.environ["HOME"] = expanduser("~")
return _decrypt_object(pass_info)
diff --git a/tests/pytests/unit/renderers/test_pass.py b/tests/pytests/unit/renderers/test_pass.py
new file mode 100644
index 0000000000..74e822c7ec
--- /dev/null
+++ b/tests/pytests/unit/renderers/test_pass.py
@@ -0,0 +1,164 @@
+import importlib
+
+import pytest
+
+import salt.config
+import salt.exceptions
+from tests.support.mock import MagicMock, patch
+
+# "pass" is a reserved keyword, we need to import it differently
+pass_ = importlib.import_module("salt.renderers.pass")
+
+
+@pytest.fixture
+def configure_loader_modules():
+ return {
+ pass_: {
+ "__opts__": salt.config.DEFAULT_MASTER_OPTS.copy(),
+ "_get_pass_exec": MagicMock(return_value="/usr/bin/pass"),
+ }
+ }
+
+
+# The default behavior is that if fetching a secret from pass fails,
+# the value is passed through. Even the trailing newlines are preserved.
+def test_passthrough():
+ pass_path = "secret\n"
+ expected = pass_path
+ result = pass_.render(pass_path)
+
+ assert result == expected
+
+
+# Fetch a secret in the strict mode.
+def test_strict_fetch():
+ config = {
+ "pass_variable_prefix": "pass:",
+ "pass_strict_fetch": True,
+ }
+
+ popen_mock = MagicMock(spec=pass_.Popen)
+ popen_mock.return_value.communicate.return_value = ("password123456\n", "")
+ popen_mock.return_value.returncode = 0
+
+ mocks = {
+ "Popen": popen_mock,
+ }
+
+ pass_path = "pass:secret"
+ expected = "password123456"
+ with patch.dict(pass_.__opts__, config), patch.dict(pass_.__dict__, mocks):
+ result = pass_.render(pass_path)
+
+ assert result == expected
+
+
+# Fail to fetch a secret in the strict mode.
+def test_strict_fetch_fail():
+ config = {
+ "pass_variable_prefix": "pass:",
+ "pass_strict_fetch": True,
+ }
+
+ popen_mock = MagicMock(spec=pass_.Popen)
+ popen_mock.return_value.communicate.return_value = ("", "Secret not found")
+ popen_mock.return_value.returncode = 1
+
+ mocks = {
+ "Popen": popen_mock,
+ }
+
+ pass_path = "pass:secret"
+ with patch.dict(pass_.__opts__, config), patch.dict(pass_.__dict__, mocks):
+ with pytest.raises(salt.exceptions.SaltRenderError):
+ pass_.render(pass_path)
+
+
+# Passthrough a value that doesn't have a pass prefix.
+def test_strict_fetch_passthrough():
+ config = {
+ "pass_variable_prefix": "pass:",
+ "pass_strict_fetch": True,
+ }
+
+ pass_path = "variable-without-pass-prefix\n"
+ expected = pass_path
+ with patch.dict(pass_.__opts__, config):
+ result = pass_.render(pass_path)
+
+ assert result == expected
+
+
+# Fetch a secret in the strict mode. The pass path contains spaces.
+def test_strict_fetch_pass_path_with_spaces():
+ config = {
+ "pass_variable_prefix": "pass:",
+ "pass_strict_fetch": True,
+ }
+
+ popen_mock = MagicMock(spec=pass_.Popen)
+ popen_mock.return_value.communicate.return_value = ("password123456\n", "")
+ popen_mock.return_value.returncode = 0
+
+ mocks = {
+ "Popen": popen_mock,
+ }
+
+ pass_path = "pass:se cr et"
+ with patch.dict(pass_.__opts__, config), patch.dict(pass_.__dict__, mocks):
+ pass_.render(pass_path)
+
+ call_args, call_kwargs = popen_mock.call_args_list[0]
+ assert call_args[0] == ["/usr/bin/pass", "show", "se cr et"]
+
+
+# Fetch a secret in the strict mode. The secret contains leading and trailing whitespaces.
+def test_strict_fetch_secret_with_whitespaces():
+ config = {
+ "pass_variable_prefix": "pass:",
+ "pass_strict_fetch": True,
+ }
+
+ popen_mock = MagicMock(spec=pass_.Popen)
+ popen_mock.return_value.communicate.return_value = (" \tpassword123456\t \r\n", "")
+ popen_mock.return_value.returncode = 0
+
+ mocks = {
+ "Popen": popen_mock,
+ }
+
+ pass_path = "pass:secret"
+ expected = " \tpassword123456\t " # only the trailing newlines get striped
+ with patch.dict(pass_.__opts__, config), patch.dict(pass_.__dict__, mocks):
+ result = pass_.render(pass_path)
+
+ assert result == expected
+
+
+# Test setting env variables based on config values:
+# - pass_gnupghome -> GNUPGHOME
+# - pass_dir -> PASSWORD_STORE_DIR
+def test_env():
+ config = {
+ "pass_variable_prefix": "pass:",
+ "pass_strict_fetch": True,
+ "pass_gnupghome": "/path/to/gnupghome",
+ "pass_dir": "/path/to/secretstore",
+ }
+
+ popen_mock = MagicMock(spec=pass_.Popen)
+ popen_mock.return_value.communicate.return_value = ("password123456\n", "")
+ popen_mock.return_value.returncode = 0
+
+ mocks = {
+ "Popen": popen_mock,
+ }
+
+ pass_path = "pass:secret"
+ expected = " \tpassword123456\t " # only the trailing newlines get striped
+ with patch.dict(pass_.__opts__, config), patch.dict(pass_.__dict__, mocks):
+ result = pass_.render(pass_path)
+
+ call_args, call_kwargs = popen_mock.call_args_list[0]
+ assert call_kwargs["env"]["GNUPGHOME"] == config["pass_gnupghome"]
+ assert call_kwargs["env"]["PASSWORD_STORE_DIR"] == config["pass_dir"]
--
2.37.3

View File

@ -1,4 +1,4 @@
From 33e45a7ced8a3cfc0a8c37cdc5d7a29d6f6833c3 Mon Sep 17 00:00:00 2001
From d2b4c8170d7ff30bf33623fcbbb6ebb6d7af934e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Wed, 25 Mar 2020 13:09:52 +0000
@ -9,10 +9,10 @@ Subject: [PATCH] Make setup.py script to not require setuptools > 9.1
1 file changed, 8 deletions(-)
diff --git a/setup.py b/setup.py
index d633af35ec..586842972d 100755
index e60f1b7085..8ca8a66d45 100755
--- a/setup.py
+++ b/setup.py
@@ -718,14 +718,6 @@ class Install(install):
@@ -632,14 +632,6 @@ class Install(install):
install.finalize_options(self)
def run(self):
@ -25,9 +25,9 @@ index d633af35ec..586842972d 100755
- sys.exit(1)
-
# Let's set the running_salt_install attribute so we can add
# _version.py in the build command
# _version.txt in the build command
self.distribution.running_salt_install = True
--
2.37.3
2.39.2

View File

@ -1,30 +0,0 @@
From 03ce925098fb96ad2f2f4b7d4c151ef63aede75f Mon Sep 17 00:00:00 2001
From: Witek Bedyk <wbedyk@suse.com>
Date: Thu, 19 May 2022 12:52:12 +0200
Subject: [PATCH] Make sure SaltCacheLoader use correct fileclient (#519)
Backported from https://github.com/saltstack/salt/pull/61895
Signed-off-by: Witek Bedyk <witold.bedyk@suse.com>
---
salt/state.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/salt/state.py b/salt/state.py
index db228228a7..316dcdec63 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -4170,6 +4170,9 @@ class BaseHighState:
)
else:
try:
+ # Make sure SaltCacheLoader use correct fileclient
+ if context is None:
+ context = {"fileclient": self.client}
state = compile_template(
fn_,
self.state.rend,
--
2.37.3

View File

@ -0,0 +1,850 @@
From a1fc5287d501a1ecdbd259e5bbdd4f7d5d06dd13 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Fri, 28 Apr 2023 09:41:28 +0200
Subject: [PATCH] Make sure the file client is destroyed upon used
Backport of https://github.com/saltstack/salt/pull/64113
---
salt/client/ssh/wrapper/saltcheck.py | 108 +++----
salt/fileclient.py | 11 -
salt/modules/dockermod.py | 17 +-
salt/pillar/__init__.py | 6 +-
salt/states/ansiblegate.py | 11 +-
salt/utils/asynchronous.py | 2 +-
salt/utils/jinja.py | 53 ++-
salt/utils/mako.py | 7 +
salt/utils/templates.py | 303 +++++++++---------
.../integration/states/test_include.py | 40 +++
.../utils/jinja/test_salt_cache_loader.py | 47 ++-
11 files changed, 330 insertions(+), 275 deletions(-)
create mode 100644 tests/pytests/integration/states/test_include.py
diff --git a/salt/client/ssh/wrapper/saltcheck.py b/salt/client/ssh/wrapper/saltcheck.py
index d47b5cf6883..b0b94593809 100644
--- a/salt/client/ssh/wrapper/saltcheck.py
+++ b/salt/client/ssh/wrapper/saltcheck.py
@@ -9,6 +9,7 @@ import tarfile
import tempfile
from contextlib import closing
+import salt.fileclient
import salt.utils.files
import salt.utils.json
import salt.utils.url
@@ -28,65 +29,62 @@ def update_master_cache(states, saltenv="base"):
# Setup for copying states to gendir
gendir = tempfile.mkdtemp()
trans_tar = salt.utils.files.mkstemp()
- if "cp.fileclient_{}".format(id(__opts__)) not in __context__:
- __context__[
- "cp.fileclient_{}".format(id(__opts__))
- ] = salt.fileclient.get_file_client(__opts__)
-
- # generate cp.list_states output and save to gendir
- cp_output = salt.utils.json.dumps(__salt__["cp.list_states"]())
- cp_output_file = os.path.join(gendir, "cp_output.txt")
- with salt.utils.files.fopen(cp_output_file, "w") as fp:
- fp.write(cp_output)
-
- # cp state directories to gendir
- already_processed = []
- sls_list = salt.utils.args.split_input(states)
- for state_name in sls_list:
- # generate low data for each state and save to gendir
- state_low_file = os.path.join(gendir, state_name + ".low")
- state_low_output = salt.utils.json.dumps(
- __salt__["state.show_low_sls"](state_name)
- )
- with salt.utils.files.fopen(state_low_file, "w") as fp:
- fp.write(state_low_output)
-
- state_name = state_name.replace(".", os.sep)
- if state_name in already_processed:
- log.debug("Already cached state for %s", state_name)
- else:
- file_copy_file = os.path.join(gendir, state_name + ".copy")
- log.debug("copying %s to %s", state_name, gendir)
- qualified_name = salt.utils.url.create(state_name, saltenv)
- # Duplicate cp.get_dir to gendir
- copy_result = __context__["cp.fileclient_{}".format(id(__opts__))].get_dir(
- qualified_name, gendir, saltenv
+ with salt.fileclient.get_file_client(__opts__) as cp_fileclient:
+
+ # generate cp.list_states output and save to gendir
+ cp_output = salt.utils.json.dumps(__salt__["cp.list_states"]())
+ cp_output_file = os.path.join(gendir, "cp_output.txt")
+ with salt.utils.files.fopen(cp_output_file, "w") as fp:
+ fp.write(cp_output)
+
+ # cp state directories to gendir
+ already_processed = []
+ sls_list = salt.utils.args.split_input(states)
+ for state_name in sls_list:
+ # generate low data for each state and save to gendir
+ state_low_file = os.path.join(gendir, state_name + ".low")
+ state_low_output = salt.utils.json.dumps(
+ __salt__["state.show_low_sls"](state_name)
)
- if copy_result:
- copy_result = [dir.replace(gendir, state_cache) for dir in copy_result]
- copy_result_output = salt.utils.json.dumps(copy_result)
- with salt.utils.files.fopen(file_copy_file, "w") as fp:
- fp.write(copy_result_output)
- already_processed.append(state_name)
+ with salt.utils.files.fopen(state_low_file, "w") as fp:
+ fp.write(state_low_output)
+
+ state_name = state_name.replace(".", os.sep)
+ if state_name in already_processed:
+ log.debug("Already cached state for %s", state_name)
else:
- # If files were not copied, assume state.file.sls was given and just copy state
- state_name = os.path.dirname(state_name)
file_copy_file = os.path.join(gendir, state_name + ".copy")
- if state_name in already_processed:
- log.debug("Already cached state for %s", state_name)
+ log.debug("copying %s to %s", state_name, gendir)
+ qualified_name = salt.utils.url.create(state_name, saltenv)
+ # Duplicate cp.get_dir to gendir
+ copy_result = cp_fileclient.get_dir(qualified_name, gendir, saltenv)
+ if copy_result:
+ copy_result = [
+ dir.replace(gendir, state_cache) for dir in copy_result
+ ]
+ copy_result_output = salt.utils.json.dumps(copy_result)
+ with salt.utils.files.fopen(file_copy_file, "w") as fp:
+ fp.write(copy_result_output)
+ already_processed.append(state_name)
else:
- qualified_name = salt.utils.url.create(state_name, saltenv)
- copy_result = __context__[
- "cp.fileclient_{}".format(id(__opts__))
- ].get_dir(qualified_name, gendir, saltenv)
- if copy_result:
- copy_result = [
- dir.replace(gendir, state_cache) for dir in copy_result
- ]
- copy_result_output = salt.utils.json.dumps(copy_result)
- with salt.utils.files.fopen(file_copy_file, "w") as fp:
- fp.write(copy_result_output)
- already_processed.append(state_name)
+ # If files were not copied, assume state.file.sls was given and just copy state
+ state_name = os.path.dirname(state_name)
+ file_copy_file = os.path.join(gendir, state_name + ".copy")
+ if state_name in already_processed:
+ log.debug("Already cached state for %s", state_name)
+ else:
+ qualified_name = salt.utils.url.create(state_name, saltenv)
+ copy_result = cp_fileclient.get_dir(
+ qualified_name, gendir, saltenv
+ )
+ if copy_result:
+ copy_result = [
+ dir.replace(gendir, state_cache) for dir in copy_result
+ ]
+ copy_result_output = salt.utils.json.dumps(copy_result)
+ with salt.utils.files.fopen(file_copy_file, "w") as fp:
+ fp.write(copy_result_output)
+ already_processed.append(state_name)
# turn gendir into tarball and remove gendir
try:
diff --git a/salt/fileclient.py b/salt/fileclient.py
index fef5154a0be..f01a86dd0d4 100644
--- a/salt/fileclient.py
+++ b/salt/fileclient.py
@@ -849,7 +849,6 @@ class Client:
kwargs.pop("env")
kwargs["saltenv"] = saltenv
- url_data = urllib.parse.urlparse(url)
sfn = self.cache_file(url, saltenv, cachedir=cachedir)
if not sfn or not os.path.exists(sfn):
return ""
@@ -1165,13 +1164,8 @@ class RemoteClient(Client):
if not salt.utils.platform.is_windows():
hash_server, stat_server = self.hash_and_stat_file(path, saltenv)
- try:
- mode_server = stat_server[0]
- except (IndexError, TypeError):
- mode_server = None
else:
hash_server = self.hash_file(path, saltenv)
- mode_server = None
# Check if file exists on server, before creating files and
# directories
@@ -1214,13 +1208,8 @@ class RemoteClient(Client):
if dest2check and os.path.isfile(dest2check):
if not salt.utils.platform.is_windows():
hash_local, stat_local = self.hash_and_stat_file(dest2check, saltenv)
- try:
- mode_local = stat_local[0]
- except (IndexError, TypeError):
- mode_local = None
else:
hash_local = self.hash_file(dest2check, saltenv)
- mode_local = None
if hash_local == hash_server:
return dest2check
diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py
index f7344b66ac6..69b722f0c95 100644
--- a/salt/modules/dockermod.py
+++ b/salt/modules/dockermod.py
@@ -6667,14 +6667,6 @@ def script_retcode(
)["retcode"]
-def _mk_fileclient():
- """
- Create a file client and add it to the context.
- """
- if "cp.fileclient" not in __context__:
- __context__["cp.fileclient"] = salt.fileclient.get_file_client(__opts__)
-
-
def _generate_tmp_path():
return os.path.join("/tmp", "salt.docker.{}".format(uuid.uuid4().hex[:6]))
@@ -6688,11 +6680,10 @@ def _prepare_trans_tar(name, sls_opts, mods=None, pillar=None, extra_filerefs=""
# reuse it from salt.ssh, however this function should
# be somewhere else
refs = salt.client.ssh.state.lowstate_file_refs(chunks, extra_filerefs)
- _mk_fileclient()
- trans_tar = salt.client.ssh.state.prep_trans_tar(
- __context__["cp.fileclient"], chunks, refs, pillar, name
- )
- return trans_tar
+ with salt.fileclient.get_file_client(__opts__) as fileclient:
+ return salt.client.ssh.state.prep_trans_tar(
+ fileclient, chunks, refs, pillar, name
+ )
def _compile_state(sls_opts, mods=None):
diff --git a/salt/pillar/__init__.py b/salt/pillar/__init__.py
index 0dfab4cc579..26312b3bd53 100644
--- a/salt/pillar/__init__.py
+++ b/salt/pillar/__init__.py
@@ -9,7 +9,6 @@ import logging
import os
import sys
import traceback
-import uuid
import salt.channel.client
import salt.ext.tornado.gen
@@ -1351,6 +1350,11 @@ class Pillar:
if hasattr(self, "_closing") and self._closing:
return
self._closing = True
+ if self.client:
+ try:
+ self.client.destroy()
+ except AttributeError:
+ pass
# pylint: disable=W1701
def __del__(self):
diff --git a/salt/states/ansiblegate.py b/salt/states/ansiblegate.py
index 7fd4deb6c2a..9abd418c42c 100644
--- a/salt/states/ansiblegate.py
+++ b/salt/states/ansiblegate.py
@@ -32,12 +32,10 @@ state:
- state: installed
"""
-
import logging
import os
import sys
-# Import salt modules
import salt.fileclient
import salt.utils.decorators.path
from salt.utils.decorators import depends
@@ -108,13 +106,6 @@ def __virtual__():
return __virtualname__
-def _client():
- """
- Get a fileclient
- """
- return salt.fileclient.get_file_client(__opts__)
-
-
def _changes(plays):
"""
Find changes in ansible return data
@@ -171,7 +162,7 @@ def playbooks(name, rundir=None, git_repo=None, git_kwargs=None, ansible_kwargs=
}
if git_repo:
if not isinstance(rundir, str) or not os.path.isdir(rundir):
- with _client() as client:
+ with salt.fileclient.get_file_client(__opts__) as client:
rundir = client._extrn_path(git_repo, "base")
log.trace("rundir set to %s", rundir)
if not isinstance(git_kwargs, dict):
diff --git a/salt/utils/asynchronous.py b/salt/utils/asynchronous.py
index 2a858feee98..0c645bbc3bb 100644
--- a/salt/utils/asynchronous.py
+++ b/salt/utils/asynchronous.py
@@ -131,7 +131,7 @@ class SyncWrapper:
result = io_loop.run_sync(lambda: getattr(self.obj, key)(*args, **kwargs))
results.append(True)
results.append(result)
- except Exception as exc: # pylint: disable=broad-except
+ except Exception: # pylint: disable=broad-except
results.append(False)
results.append(sys.exc_info())
diff --git a/salt/utils/jinja.py b/salt/utils/jinja.py
index fcc5aec497e..a6a8a279605 100644
--- a/salt/utils/jinja.py
+++ b/salt/utils/jinja.py
@@ -58,19 +58,6 @@ class SaltCacheLoader(BaseLoader):
and only loaded once per loader instance.
"""
- _cached_pillar_client = None
- _cached_client = None
-
- @classmethod
- def shutdown(cls):
- for attr in ("_cached_client", "_cached_pillar_client"):
- client = getattr(cls, attr, None)
- if client is not None:
- # PillarClient and LocalClient objects do not have a destroy method
- if hasattr(client, "destroy"):
- client.destroy()
- setattr(cls, attr, None)
-
def __init__(
self,
opts,
@@ -93,8 +80,7 @@ class SaltCacheLoader(BaseLoader):
log.debug("Jinja search path: %s", self.searchpath)
self.cached = []
self._file_client = _file_client
- # Instantiate the fileclient
- self.file_client()
+ self._close_file_client = _file_client is None
def file_client(self):
"""
@@ -108,18 +94,10 @@ class SaltCacheLoader(BaseLoader):
or not hasattr(self._file_client, "opts")
or self._file_client.opts["file_roots"] != self.opts["file_roots"]
):
- attr = "_cached_pillar_client" if self.pillar_rend else "_cached_client"
- cached_client = getattr(self, attr, None)
- if (
- cached_client is None
- or not hasattr(cached_client, "opts")
- or cached_client.opts["file_roots"] != self.opts["file_roots"]
- ):
- cached_client = salt.fileclient.get_file_client(
- self.opts, self.pillar_rend
- )
- setattr(SaltCacheLoader, attr, cached_client)
- self._file_client = cached_client
+ self._file_client = salt.fileclient.get_file_client(
+ self.opts, self.pillar_rend
+ )
+ self._close_file_client = True
return self._file_client
def cache_file(self, template):
@@ -221,6 +199,27 @@ class SaltCacheLoader(BaseLoader):
# there is no template file within searchpaths
raise TemplateNotFound(template)
+ def destroy(self):
+ if self._close_file_client is False:
+ return
+ if self._file_client is None:
+ return
+ file_client = self._file_client
+ self._file_client = None
+
+ try:
+ file_client.destroy()
+ except AttributeError:
+ # PillarClient and LocalClient objects do not have a destroy method
+ pass
+
+ def __enter__(self):
+ self.file_client()
+ return self
+
+ def __exit__(self, *args):
+ self.destroy()
+
class PrintableDict(OrderedDict):
"""
diff --git a/salt/utils/mako.py b/salt/utils/mako.py
index 69618de9837..037d5d86deb 100644
--- a/salt/utils/mako.py
+++ b/salt/utils/mako.py
@@ -97,3 +97,10 @@ if HAS_MAKO:
self.cache[fpath] = self.file_client().get_file(
fpath, "", True, self.saltenv
)
+
+ def destroy(self):
+ if self.client:
+ try:
+ self.client.destroy()
+ except AttributeError:
+ pass
diff --git a/salt/utils/templates.py b/salt/utils/templates.py
index 4947b820a36..4a8adf2a14f 100644
--- a/salt/utils/templates.py
+++ b/salt/utils/templates.py
@@ -362,163 +362,169 @@ def render_jinja_tmpl(tmplstr, context, tmplpath=None):
elif tmplstr.endswith("\n"):
newline = "\n"
- if not saltenv:
- if tmplpath:
- loader = jinja2.FileSystemLoader(os.path.dirname(tmplpath))
- else:
- loader = salt.utils.jinja.SaltCacheLoader(
- opts,
- saltenv,
- pillar_rend=context.get("_pillar_rend", False),
- _file_client=file_client,
- )
+ try:
+ if not saltenv:
+ if tmplpath:
+ loader = jinja2.FileSystemLoader(os.path.dirname(tmplpath))
+ else:
+ loader = salt.utils.jinja.SaltCacheLoader(
+ opts,
+ saltenv,
+ pillar_rend=context.get("_pillar_rend", False),
+ _file_client=file_client,
+ )
- env_args = {"extensions": [], "loader": loader}
-
- if hasattr(jinja2.ext, "with_"):
- env_args["extensions"].append("jinja2.ext.with_")
- if hasattr(jinja2.ext, "do"):
- env_args["extensions"].append("jinja2.ext.do")
- if hasattr(jinja2.ext, "loopcontrols"):
- env_args["extensions"].append("jinja2.ext.loopcontrols")
- env_args["extensions"].append(salt.utils.jinja.SerializerExtension)
-
- opt_jinja_env = opts.get("jinja_env", {})
- opt_jinja_sls_env = opts.get("jinja_sls_env", {})
-
- opt_jinja_env = opt_jinja_env if isinstance(opt_jinja_env, dict) else {}
- opt_jinja_sls_env = opt_jinja_sls_env if isinstance(opt_jinja_sls_env, dict) else {}
-
- # Pass through trim_blocks and lstrip_blocks Jinja parameters
- # trim_blocks removes newlines around Jinja blocks
- # lstrip_blocks strips tabs and spaces from the beginning of
- # line to the start of a block.
- if opts.get("jinja_trim_blocks", False):
- log.debug("Jinja2 trim_blocks is enabled")
- log.warning(
- "jinja_trim_blocks is deprecated and will be removed in a future release,"
- " please use jinja_env and/or jinja_sls_env instead"
- )
- opt_jinja_env["trim_blocks"] = True
- opt_jinja_sls_env["trim_blocks"] = True
- if opts.get("jinja_lstrip_blocks", False):
- log.debug("Jinja2 lstrip_blocks is enabled")
- log.warning(
- "jinja_lstrip_blocks is deprecated and will be removed in a future release,"
- " please use jinja_env and/or jinja_sls_env instead"
- )
- opt_jinja_env["lstrip_blocks"] = True
- opt_jinja_sls_env["lstrip_blocks"] = True
-
- def opt_jinja_env_helper(opts, optname):
- for k, v in opts.items():
- k = k.lower()
- if hasattr(jinja2.defaults, k.upper()):
- log.debug("Jinja2 environment %s was set to %s by %s", k, v, optname)
- env_args[k] = v
- else:
- log.warning("Jinja2 environment %s is not recognized", k)
+ env_args = {"extensions": [], "loader": loader}
- if "sls" in context and context["sls"] != "":
- opt_jinja_env_helper(opt_jinja_sls_env, "jinja_sls_env")
- else:
- opt_jinja_env_helper(opt_jinja_env, "jinja_env")
+ if hasattr(jinja2.ext, "with_"):
+ env_args["extensions"].append("jinja2.ext.with_")
+ if hasattr(jinja2.ext, "do"):
+ env_args["extensions"].append("jinja2.ext.do")
+ if hasattr(jinja2.ext, "loopcontrols"):
+ env_args["extensions"].append("jinja2.ext.loopcontrols")
+ env_args["extensions"].append(salt.utils.jinja.SerializerExtension)
- if opts.get("allow_undefined", False):
- jinja_env = jinja2.sandbox.SandboxedEnvironment(**env_args)
- else:
- jinja_env = jinja2.sandbox.SandboxedEnvironment(
- undefined=jinja2.StrictUndefined, **env_args
- )
+ opt_jinja_env = opts.get("jinja_env", {})
+ opt_jinja_sls_env = opts.get("jinja_sls_env", {})
- indent_filter = jinja_env.filters.get("indent")
- jinja_env.tests.update(JinjaTest.salt_jinja_tests)
- jinja_env.filters.update(JinjaFilter.salt_jinja_filters)
- if salt.utils.jinja.JINJA_VERSION >= Version("2.11"):
- # Use the existing indent filter on Jinja versions where it's not broken
- jinja_env.filters["indent"] = indent_filter
- jinja_env.globals.update(JinjaGlobal.salt_jinja_globals)
-
- # globals
- jinja_env.globals["odict"] = OrderedDict
- jinja_env.globals["show_full_context"] = salt.utils.jinja.show_full_context
-
- jinja_env.tests["list"] = salt.utils.data.is_list
-
- decoded_context = {}
- for key, value in context.items():
- if not isinstance(value, str):
- if isinstance(value, NamedLoaderContext):
- decoded_context[key] = value.value()
- else:
- decoded_context[key] = value
- continue
+ opt_jinja_env = opt_jinja_env if isinstance(opt_jinja_env, dict) else {}
+ opt_jinja_sls_env = (
+ opt_jinja_sls_env if isinstance(opt_jinja_sls_env, dict) else {}
+ )
- try:
- decoded_context[key] = salt.utils.stringutils.to_unicode(
- value, encoding=SLS_ENCODING
+ # Pass through trim_blocks and lstrip_blocks Jinja parameters
+ # trim_blocks removes newlines around Jinja blocks
+ # lstrip_blocks strips tabs and spaces from the beginning of
+ # line to the start of a block.
+ if opts.get("jinja_trim_blocks", False):
+ log.debug("Jinja2 trim_blocks is enabled")
+ log.warning(
+ "jinja_trim_blocks is deprecated and will be removed in a future release,"
+ " please use jinja_env and/or jinja_sls_env instead"
)
- except UnicodeDecodeError as ex:
- log.debug(
- "Failed to decode using default encoding (%s), trying system encoding",
- SLS_ENCODING,
+ opt_jinja_env["trim_blocks"] = True
+ opt_jinja_sls_env["trim_blocks"] = True
+ if opts.get("jinja_lstrip_blocks", False):
+ log.debug("Jinja2 lstrip_blocks is enabled")
+ log.warning(
+ "jinja_lstrip_blocks is deprecated and will be removed in a future release,"
+ " please use jinja_env and/or jinja_sls_env instead"
)
- decoded_context[key] = salt.utils.data.decode(value)
+ opt_jinja_env["lstrip_blocks"] = True
+ opt_jinja_sls_env["lstrip_blocks"] = True
+
+ def opt_jinja_env_helper(opts, optname):
+ for k, v in opts.items():
+ k = k.lower()
+ if hasattr(jinja2.defaults, k.upper()):
+ log.debug(
+ "Jinja2 environment %s was set to %s by %s", k, v, optname
+ )
+ env_args[k] = v
+ else:
+ log.warning("Jinja2 environment %s is not recognized", k)
- jinja_env.globals.update(decoded_context)
- try:
- template = jinja_env.from_string(tmplstr)
- output = template.render(**decoded_context)
- except jinja2.exceptions.UndefinedError as exc:
- trace = traceback.extract_tb(sys.exc_info()[2])
- line, out = _get_jinja_error(trace, context=decoded_context)
- if not line:
- tmplstr = ""
- raise SaltRenderError("Jinja variable {}{}".format(exc, out), line, tmplstr)
- except (
- jinja2.exceptions.TemplateRuntimeError,
- jinja2.exceptions.TemplateSyntaxError,
- jinja2.exceptions.SecurityError,
- ) as exc:
- trace = traceback.extract_tb(sys.exc_info()[2])
- line, out = _get_jinja_error(trace, context=decoded_context)
- if not line:
- tmplstr = ""
- raise SaltRenderError(
- "Jinja syntax error: {}{}".format(exc, out), line, tmplstr
- )
- except (SaltInvocationError, CommandExecutionError) as exc:
- trace = traceback.extract_tb(sys.exc_info()[2])
- line, out = _get_jinja_error(trace, context=decoded_context)
- if not line:
- tmplstr = ""
- raise SaltRenderError(
- "Problem running salt function in Jinja template: {}{}".format(exc, out),
- line,
- tmplstr,
- )
- except Exception as exc: # pylint: disable=broad-except
- tracestr = traceback.format_exc()
- trace = traceback.extract_tb(sys.exc_info()[2])
- line, out = _get_jinja_error(trace, context=decoded_context)
- if not line:
- tmplstr = ""
+ if "sls" in context and context["sls"] != "":
+ opt_jinja_env_helper(opt_jinja_sls_env, "jinja_sls_env")
else:
- tmplstr += "\n{}".format(tracestr)
- log.debug("Jinja Error")
- log.debug("Exception:", exc_info=True)
- log.debug("Out: %s", out)
- log.debug("Line: %s", line)
- log.debug("TmplStr: %s", tmplstr)
- log.debug("TraceStr: %s", tracestr)
+ opt_jinja_env_helper(opt_jinja_env, "jinja_env")
- raise SaltRenderError(
- "Jinja error: {}{}".format(exc, out), line, tmplstr, trace=tracestr
- )
+ if opts.get("allow_undefined", False):
+ jinja_env = jinja2.sandbox.SandboxedEnvironment(**env_args)
+ else:
+ jinja_env = jinja2.sandbox.SandboxedEnvironment(
+ undefined=jinja2.StrictUndefined, **env_args
+ )
+
+ indent_filter = jinja_env.filters.get("indent")
+ jinja_env.tests.update(JinjaTest.salt_jinja_tests)
+ jinja_env.filters.update(JinjaFilter.salt_jinja_filters)
+ if salt.utils.jinja.JINJA_VERSION >= Version("2.11"):
+ # Use the existing indent filter on Jinja versions where it's not broken
+ jinja_env.filters["indent"] = indent_filter
+ jinja_env.globals.update(JinjaGlobal.salt_jinja_globals)
+
+ # globals
+ jinja_env.globals["odict"] = OrderedDict
+ jinja_env.globals["show_full_context"] = salt.utils.jinja.show_full_context
+
+ jinja_env.tests["list"] = salt.utils.data.is_list
+
+ decoded_context = {}
+ for key, value in context.items():
+ if not isinstance(value, str):
+ if isinstance(value, NamedLoaderContext):
+ decoded_context[key] = value.value()
+ else:
+ decoded_context[key] = value
+ continue
+
+ try:
+ decoded_context[key] = salt.utils.stringutils.to_unicode(
+ value, encoding=SLS_ENCODING
+ )
+ except UnicodeDecodeError:
+ log.debug(
+ "Failed to decode using default encoding (%s), trying system encoding",
+ SLS_ENCODING,
+ )
+ decoded_context[key] = salt.utils.data.decode(value)
+
+ jinja_env.globals.update(decoded_context)
+ try:
+ template = jinja_env.from_string(tmplstr)
+ output = template.render(**decoded_context)
+ except jinja2.exceptions.UndefinedError as exc:
+ trace = traceback.extract_tb(sys.exc_info()[2])
+ line, out = _get_jinja_error(trace, context=decoded_context)
+ if not line:
+ tmplstr = ""
+ raise SaltRenderError("Jinja variable {}{}".format(exc, out), line, tmplstr)
+ except (
+ jinja2.exceptions.TemplateRuntimeError,
+ jinja2.exceptions.TemplateSyntaxError,
+ jinja2.exceptions.SecurityError,
+ ) as exc:
+ trace = traceback.extract_tb(sys.exc_info()[2])
+ line, out = _get_jinja_error(trace, context=decoded_context)
+ if not line:
+ tmplstr = ""
+ raise SaltRenderError(
+ "Jinja syntax error: {}{}".format(exc, out), line, tmplstr
+ )
+ except (SaltInvocationError, CommandExecutionError) as exc:
+ trace = traceback.extract_tb(sys.exc_info()[2])
+ line, out = _get_jinja_error(trace, context=decoded_context)
+ if not line:
+ tmplstr = ""
+ raise SaltRenderError(
+ "Problem running salt function in Jinja template: {}{}".format(
+ exc, out
+ ),
+ line,
+ tmplstr,
+ )
+ except Exception as exc: # pylint: disable=broad-except
+ tracestr = traceback.format_exc()
+ trace = traceback.extract_tb(sys.exc_info()[2])
+ line, out = _get_jinja_error(trace, context=decoded_context)
+ if not line:
+ tmplstr = ""
+ else:
+ tmplstr += "\n{}".format(tracestr)
+ log.debug("Jinja Error")
+ log.debug("Exception:", exc_info=True)
+ log.debug("Out: %s", out)
+ log.debug("Line: %s", line)
+ log.debug("TmplStr: %s", tmplstr)
+ log.debug("TraceStr: %s", tracestr)
+
+ raise SaltRenderError(
+ "Jinja error: {}{}".format(exc, out), line, tmplstr, trace=tracestr
+ )
finally:
- if loader and hasattr(loader, "_file_client"):
- if hasattr(loader._file_client, "destroy"):
- loader._file_client.destroy()
+ if loader and isinstance(loader, salt.utils.jinja.SaltCacheLoader):
+ loader.destroy()
# Workaround a bug in Jinja that removes the final newline
# (https://github.com/mitsuhiko/jinja2/issues/75)
@@ -569,9 +575,8 @@ def render_mako_tmpl(tmplstr, context, tmplpath=None):
except Exception: # pylint: disable=broad-except
raise SaltRenderError(mako.exceptions.text_error_template().render())
finally:
- if lookup and hasattr(lookup, "_file_client"):
- if hasattr(lookup._file_client, "destroy"):
- lookup._file_client.destroy()
+ if lookup and isinstance(lookup, SaltMakoTemplateLookup):
+ lookup.destroy()
def render_wempy_tmpl(tmplstr, context, tmplpath=None):
diff --git a/tests/pytests/integration/states/test_include.py b/tests/pytests/integration/states/test_include.py
new file mode 100644
index 00000000000..f814328c5e4
--- /dev/null
+++ b/tests/pytests/integration/states/test_include.py
@@ -0,0 +1,40 @@
+"""
+Integration tests for the jinja includes in states
+"""
+import logging
+
+import pytest
+
+log = logging.getLogger(__name__)
+
+
+@pytest.mark.slow_test
+def test_issue_64111(salt_master, salt_minion, salt_call_cli):
+ # This needs to be an integration test. A functional test does not trigger
+ # the issue fixed.
+
+ macros_jinja = """
+ {% macro a_jinja_macro(arg) -%}
+ {{ arg }}
+ {%- endmacro %}
+ """
+
+ init_sls = """
+ include:
+ - common.file1
+ """
+
+ file1_sls = """
+ {% from 'common/macros.jinja' import a_jinja_macro with context %}
+
+ a state id:
+ cmd.run:
+ - name: echo {{ a_jinja_macro("hello world") }}
+ """
+ tf = salt_master.state_tree.base.temp_file
+
+ with tf("common/macros.jinja", macros_jinja):
+ with tf("common/init.sls", init_sls):
+ with tf("common/file1.sls", file1_sls):
+ ret = salt_call_cli.run("state.apply", "common")
+ assert ret.returncode == 0
diff --git a/tests/pytests/unit/utils/jinja/test_salt_cache_loader.py b/tests/pytests/unit/utils/jinja/test_salt_cache_loader.py
index 38c5ce5b724..e0f5fa158ff 100644
--- a/tests/pytests/unit/utils/jinja/test_salt_cache_loader.py
+++ b/tests/pytests/unit/utils/jinja/test_salt_cache_loader.py
@@ -15,7 +15,7 @@ import salt.utils.json # pylint: disable=unused-import
import salt.utils.stringutils # pylint: disable=unused-import
import salt.utils.yaml # pylint: disable=unused-import
from salt.utils.jinja import SaltCacheLoader
-from tests.support.mock import Mock, patch
+from tests.support.mock import Mock, call, patch
@pytest.fixture
@@ -224,14 +224,45 @@ def test_file_client_kwarg(minion_opts, mock_file_client):
assert loader._file_client is mock_file_client
-def test_cache_loader_shutdown(minion_opts, mock_file_client):
+def test_cache_loader_passed_file_client(minion_opts, mock_file_client):
"""
The shudown method can be called without raising an exception when the
file_client does not have a destroy method
"""
- assert not hasattr(mock_file_client, "destroy")
- mock_file_client.opts = minion_opts
- loader = SaltCacheLoader(minion_opts, _file_client=mock_file_client)
- assert loader._file_client is mock_file_client
- # Shutdown method should not raise any exceptions
- loader.shutdown()
+ # Test SaltCacheLoader creating and destroying the file client created
+ file_client = Mock()
+ with patch("salt.fileclient.get_file_client", return_value=file_client):
+ loader = SaltCacheLoader(minion_opts)
+ assert loader._file_client is None
+ with loader:
+ assert loader._file_client is file_client
+ assert loader._file_client is None
+ assert file_client.mock_calls == [call.destroy()]
+
+ # Test SaltCacheLoader reusing the file client passed
+ file_client = Mock()
+ file_client.opts = {"file_roots": minion_opts["file_roots"]}
+ with patch("salt.fileclient.get_file_client", return_value=Mock()):
+ loader = SaltCacheLoader(minion_opts, _file_client=file_client)
+ assert loader._file_client is file_client
+ with loader:
+ assert loader._file_client is file_client
+ assert loader._file_client is file_client
+ assert file_client.mock_calls == []
+
+ # Test SaltCacheLoader creating a client even though a file client was
+ # passed because the "file_roots" option is different, and, as such,
+ # the destroy method on the new file client is called, but not on the
+ # file client passed in.
+ file_client = Mock()
+ file_client.opts = {"file_roots": ""}
+ new_file_client = Mock()
+ with patch("salt.fileclient.get_file_client", return_value=new_file_client):
+ loader = SaltCacheLoader(minion_opts, _file_client=file_client)
+ assert loader._file_client is file_client
+ with loader:
+ assert loader._file_client is not file_client
+ assert loader._file_client is new_file_client
+ assert loader._file_client is None
+ assert file_client.mock_calls == []
+ assert new_file_client.mock_calls == [call.destroy()]
--
2.40.0

View File

@ -1,296 +0,0 @@
From f2dc43cf1db3fee41e328c68545ccac2576021ca Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Mon, 27 Jun 2022 18:01:21 +0300
Subject: [PATCH] Normalize package names once with pkg.installed/removed
using yum (bsc#1195895)
* Normalize the package names only once on install/remove
* Add test for checking pkg.installed/removed with only normalisation
* Fix split_arch conditions
* Fix test_pkg
---
salt/modules/yumpkg.py | 18 ++-
salt/states/pkg.py | 3 +-
tests/pytests/unit/states/test_pkg.py | 177 +++++++++++++++++++++++++-
3 files changed, 192 insertions(+), 6 deletions(-)
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
index 46f0b1f613..f52e084346 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -1460,7 +1460,12 @@ def install(
try:
pkg_params, pkg_type = __salt__["pkg_resource.parse_targets"](
- name, pkgs, sources, saltenv=saltenv, normalize=normalize, **kwargs
+ name,
+ pkgs,
+ sources,
+ saltenv=saltenv,
+ normalize=normalize and kwargs.get("split_arch", True),
+ **kwargs
)
except MinionError as exc:
raise CommandExecutionError(exc)
@@ -1612,7 +1617,10 @@ def install(
except ValueError:
pass
else:
- if archpart in salt.utils.pkg.rpm.ARCHES:
+ if archpart in salt.utils.pkg.rpm.ARCHES and (
+ archpart != __grains__["osarch"]
+ or kwargs.get("split_arch", True)
+ ):
arch = "." + archpart
pkgname = namepart
@@ -2143,11 +2151,13 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
arch = ""
pkgname = target
try:
- namepart, archpart = target.rsplit(".", 1)
+ namepart, archpart = pkgname.rsplit(".", 1)
except ValueError:
pass
else:
- if archpart in salt.utils.pkg.rpm.ARCHES:
+ if archpart in salt.utils.pkg.rpm.ARCHES and (
+ archpart != __grains__["osarch"] or kwargs.get("split_arch", True)
+ ):
arch = "." + archpart
pkgname = namepart
# Since we don't always have the arch info, epoch information has to parsed out. But
diff --git a/salt/states/pkg.py b/salt/states/pkg.py
index ef4e062145..cda966a1e8 100644
--- a/salt/states/pkg.py
+++ b/salt/states/pkg.py
@@ -1873,6 +1873,7 @@ def installed(
normalize=normalize,
update_holds=update_holds,
ignore_epoch=ignore_epoch,
+ split_arch=False,
**kwargs
)
except CommandExecutionError as exc:
@@ -2940,7 +2941,7 @@ def _uninstall(
}
changes = __salt__["pkg.{}".format(action)](
- name, pkgs=pkgs, version=version, **kwargs
+ name, pkgs=pkgs, version=version, split_arch=False, **kwargs
)
new = __salt__["pkg.list_pkgs"](versions_as_list=True, **kwargs)
failed = []
diff --git a/tests/pytests/unit/states/test_pkg.py b/tests/pytests/unit/states/test_pkg.py
index cba8201bda..ecb841e8ec 100644
--- a/tests/pytests/unit/states/test_pkg.py
+++ b/tests/pytests/unit/states/test_pkg.py
@@ -2,6 +2,8 @@ import logging
import pytest
import salt.modules.beacons as beaconmod
+import salt.modules.pkg_resource as pkg_resource
+import salt.modules.yumpkg as yumpkg
import salt.states.beacon as beaconstate
import salt.states.pkg as pkg
import salt.utils.state as state_utils
@@ -17,7 +19,7 @@ def configure_loader_modules():
pkg: {
"__env__": "base",
"__salt__": {},
- "__grains__": {"os": "CentOS"},
+ "__grains__": {"os": "CentOS", "os_family": "RedHat"},
"__opts__": {"test": False, "cachedir": ""},
"__instance_id__": "",
"__low__": {},
@@ -25,6 +27,15 @@ def configure_loader_modules():
},
beaconstate: {"__salt__": {}, "__opts__": {}},
beaconmod: {"__salt__": {}, "__opts__": {}},
+ pkg_resource: {
+ "__salt__": {},
+ "__grains__": {"os": "CentOS", "os_family": "RedHat"},
+ },
+ yumpkg: {
+ "__salt__": {},
+ "__grains__": {"osarch": "x86_64", "osmajorrelease": 7},
+ "__opts__": {},
+ },
}
@@ -726,3 +737,167 @@ def test_held_unheld(package_manager):
hold_mock.assert_not_called()
unhold_mock.assert_any_call(name="held-test", pkgs=["baz"])
unhold_mock.assert_any_call(name="held-test", pkgs=["bar"])
+
+
+def test_installed_with_single_normalize():
+ """
+ Test pkg.installed with preventing multiple package name normalisation
+ """
+
+ list_no_weird_installed = {
+ "pkga": "1.0.1",
+ "pkgb": "1.0.2",
+ "pkgc": "1.0.3",
+ }
+ list_no_weird_installed_ver_list = {
+ "pkga": ["1.0.1"],
+ "pkgb": ["1.0.2"],
+ "pkgc": ["1.0.3"],
+ }
+ list_with_weird_installed = {
+ "pkga": "1.0.1",
+ "pkgb": "1.0.2",
+ "pkgc": "1.0.3",
+ "weird-name-1.2.3-1234.5.6.test7tst.x86_64": "20220214-2.1",
+ }
+ list_with_weird_installed_ver_list = {
+ "pkga": ["1.0.1"],
+ "pkgb": ["1.0.2"],
+ "pkgc": ["1.0.3"],
+ "weird-name-1.2.3-1234.5.6.test7tst.x86_64": ["20220214-2.1"],
+ }
+ list_pkgs = MagicMock(
+ side_effect=[
+ # For the package with version specified
+ list_no_weird_installed_ver_list,
+ {},
+ list_no_weird_installed,
+ list_no_weird_installed_ver_list,
+ list_with_weird_installed,
+ list_with_weird_installed_ver_list,
+ # For the package with no version specified
+ list_no_weird_installed_ver_list,
+ {},
+ list_no_weird_installed,
+ list_no_weird_installed_ver_list,
+ list_with_weird_installed,
+ list_with_weird_installed_ver_list,
+ ]
+ )
+
+ salt_dict = {
+ "pkg.install": yumpkg.install,
+ "pkg.list_pkgs": list_pkgs,
+ "pkg.normalize_name": yumpkg.normalize_name,
+ "pkg_resource.version_clean": pkg_resource.version_clean,
+ "pkg_resource.parse_targets": pkg_resource.parse_targets,
+ }
+
+ with patch("salt.modules.yumpkg.list_pkgs", list_pkgs), patch(
+ "salt.modules.yumpkg.version_cmp", MagicMock(return_value=0)
+ ), patch(
+ "salt.modules.yumpkg._call_yum", MagicMock(return_value={"retcode": 0})
+ ) as call_yum_mock, patch.dict(
+ pkg.__salt__, salt_dict
+ ), patch.dict(
+ pkg_resource.__salt__, salt_dict
+ ), patch.dict(
+ yumpkg.__salt__, salt_dict
+ ), patch.dict(
+ yumpkg.__grains__, {"os": "CentOS", "osarch": "x86_64", "osmajorrelease": 7}
+ ), patch.object(
+ yumpkg, "list_holds", MagicMock()
+ ):
+
+ expected = {
+ "weird-name-1.2.3-1234.5.6.test7tst.x86_64": {
+ "old": "",
+ "new": "20220214-2.1",
+ }
+ }
+ ret = pkg.installed(
+ "test_install",
+ pkgs=[{"weird-name-1.2.3-1234.5.6.test7tst.x86_64.noarch": "20220214-2.1"}],
+ )
+ call_yum_mock.assert_called_once()
+ assert (
+ call_yum_mock.mock_calls[0].args[0][2]
+ == "weird-name-1.2.3-1234.5.6.test7tst.x86_64-20220214-2.1"
+ )
+ assert ret["result"]
+ assert ret["changes"] == expected
+
+
+def test_removed_with_single_normalize():
+ """
+ Test pkg.removed with preventing multiple package name normalisation
+ """
+
+ list_no_weird_installed = {
+ "pkga": "1.0.1",
+ "pkgb": "1.0.2",
+ "pkgc": "1.0.3",
+ }
+ list_no_weird_installed_ver_list = {
+ "pkga": ["1.0.1"],
+ "pkgb": ["1.0.2"],
+ "pkgc": ["1.0.3"],
+ }
+ list_with_weird_installed = {
+ "pkga": "1.0.1",
+ "pkgb": "1.0.2",
+ "pkgc": "1.0.3",
+ "weird-name-1.2.3-1234.5.6.test7tst.x86_64": "20220214-2.1",
+ }
+ list_with_weird_installed_ver_list = {
+ "pkga": ["1.0.1"],
+ "pkgb": ["1.0.2"],
+ "pkgc": ["1.0.3"],
+ "weird-name-1.2.3-1234.5.6.test7tst.x86_64": ["20220214-2.1"],
+ }
+ list_pkgs = MagicMock(
+ side_effect=[
+ list_with_weird_installed_ver_list,
+ list_with_weird_installed,
+ list_no_weird_installed,
+ list_no_weird_installed_ver_list,
+ ]
+ )
+
+ salt_dict = {
+ "pkg.remove": yumpkg.remove,
+ "pkg.list_pkgs": list_pkgs,
+ "pkg.normalize_name": yumpkg.normalize_name,
+ "pkg_resource.parse_targets": pkg_resource.parse_targets,
+ "pkg_resource.version_clean": pkg_resource.version_clean,
+ }
+
+ with patch("salt.modules.yumpkg.list_pkgs", list_pkgs), patch(
+ "salt.modules.yumpkg.version_cmp", MagicMock(return_value=0)
+ ), patch(
+ "salt.modules.yumpkg._call_yum", MagicMock(return_value={"retcode": 0})
+ ) as call_yum_mock, patch.dict(
+ pkg.__salt__, salt_dict
+ ), patch.dict(
+ pkg_resource.__salt__, salt_dict
+ ), patch.dict(
+ yumpkg.__salt__, salt_dict
+ ):
+
+ expected = {
+ "weird-name-1.2.3-1234.5.6.test7tst.x86_64": {
+ "old": "20220214-2.1",
+ "new": "",
+ }
+ }
+ ret = pkg.removed(
+ "test_remove",
+ pkgs=[{"weird-name-1.2.3-1234.5.6.test7tst.x86_64.noarch": "20220214-2.1"}],
+ )
+ call_yum_mock.assert_called_once()
+ assert (
+ call_yum_mock.mock_calls[0].args[0][2]
+ == "weird-name-1.2.3-1234.5.6.test7tst.x86_64-20220214-2.1"
+ )
+ assert ret["result"]
+ assert ret["changes"] == expected
--
2.37.3

View File

@ -1,4 +1,4 @@
From 8a584a8546667ab5390e9a2003a8ce3cb3add25c Mon Sep 17 00:00:00 2001
From bd671b53de8933732e2108624d7dfb6f9b183f38 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <Victor.Zhestkov@suse.com>
Date: Fri, 28 Oct 2022 13:20:13 +0300
Subject: [PATCH] Pass the context to pillar ext modules
@ -15,10 +15,10 @@ Subject: [PATCH] Pass the context to pillar ext modules
3 files changed, 108 insertions(+), 6 deletions(-)
diff --git a/salt/master.py b/salt/master.py
index 7f41ffe77b..0110082626 100644
index a0552fa232..da1eb8cef5 100644
--- a/salt/master.py
+++ b/salt/master.py
@@ -951,6 +951,7 @@ class MWorker(salt.utils.process.SignalHandlingProcess):
@@ -964,6 +964,7 @@ class MWorker(salt.utils.process.SignalHandlingProcess):
self.k_mtime = 0
self.stats = collections.defaultdict(lambda: {"mean": 0, "runs": 0})
self.stat_clock = time.time()
@ -26,7 +26,7 @@ index 7f41ffe77b..0110082626 100644
# We need __setstate__ and __getstate__ to also pickle 'SMaster.secrets'.
# Otherwise, 'SMaster.secrets' won't be copied over to the spawned process
@@ -1138,7 +1139,7 @@ class MWorker(salt.utils.process.SignalHandlingProcess):
@@ -1151,7 +1152,7 @@ class MWorker(salt.utils.process.SignalHandlingProcess):
self.key,
)
self.clear_funcs.connect()
@ -35,8 +35,8 @@ index 7f41ffe77b..0110082626 100644
salt.utils.crypt.reinit_crypto()
self.__bind()
@@ -1202,7 +1203,7 @@ class AESFuncs(TransportMethods):
"_ext_nodes", # To be removed in 3006 (Sulfur) #60980
@@ -1214,7 +1215,7 @@ class AESFuncs(TransportMethods):
"_file_envs",
)
- def __init__(self, opts):
@ -44,7 +44,7 @@ index 7f41ffe77b..0110082626 100644
"""
Create a new AESFuncs
@@ -1212,6 +1213,7 @@ class AESFuncs(TransportMethods):
@@ -1224,6 +1225,7 @@ class AESFuncs(TransportMethods):
:returns: Instance for handling AES operations
"""
self.opts = opts
@ -52,7 +52,7 @@ index 7f41ffe77b..0110082626 100644
self.event = salt.utils.event.get_master_event(
self.opts, self.opts["sock_dir"], listen=False
)
@@ -1603,6 +1605,7 @@ class AESFuncs(TransportMethods):
@@ -1611,6 +1613,7 @@ class AESFuncs(TransportMethods):
pillarenv=load.get("pillarenv"),
extra_minion_data=load.get("extra_minion_data"),
clean_cache=load.get("clean_cache"),
@ -61,7 +61,7 @@ index 7f41ffe77b..0110082626 100644
data = pillar.compile_pillar()
self.fs_.update_opts()
diff --git a/salt/pillar/__init__.py b/salt/pillar/__init__.py
index 7be963566a..906bdfe55d 100644
index 5a3f5388b4..0dfab4cc57 100644
--- a/salt/pillar/__init__.py
+++ b/salt/pillar/__init__.py
@@ -46,6 +46,7 @@ def get_pillar(
@ -72,15 +72,15 @@ index 7be963566a..906bdfe55d 100644
):
"""
Return the correct pillar driver based on the file_client option
@@ -81,6 +82,7 @@ def get_pillar(
pillar_override=pillar_override,
@@ -82,6 +83,7 @@ def get_pillar(
pillarenv=pillarenv,
clean_cache=clean_cache,
extra_minion_data=extra_minion_data,
+ context=context,
)
return ptype(
opts,
@@ -92,6 +94,7 @@ def get_pillar(
@@ -93,6 +95,7 @@ def get_pillar(
pillar_override=pillar_override,
pillarenv=pillarenv,
extra_minion_data=extra_minion_data,
@ -88,7 +88,7 @@ index 7be963566a..906bdfe55d 100644
)
@@ -280,7 +283,7 @@ class AsyncRemotePillar(RemotePillarMixin):
@@ -281,7 +284,7 @@ class AsyncRemotePillar(RemotePillarMixin):
raise salt.ext.tornado.gen.Return(ret_pillar)
def destroy(self):
@ -97,7 +97,7 @@ index 7be963566a..906bdfe55d 100644
return
self._closing = True
@@ -309,6 +312,7 @@ class RemotePillar(RemotePillarMixin):
@@ -310,6 +313,7 @@ class RemotePillar(RemotePillarMixin):
pillar_override=None,
pillarenv=None,
extra_minion_data=None,
@ -105,7 +105,7 @@ index 7be963566a..906bdfe55d 100644
):
self.opts = opts
self.opts["saltenv"] = saltenv
@@ -333,6 +337,7 @@ class RemotePillar(RemotePillarMixin):
@@ -334,6 +338,7 @@ class RemotePillar(RemotePillarMixin):
merge_lists=True,
)
self._closing = False
@ -113,7 +113,7 @@ index 7be963566a..906bdfe55d 100644
def compile_pillar(self):
"""
@@ -406,6 +411,7 @@ class PillarCache:
@@ -407,6 +412,7 @@ class PillarCache:
pillarenv=None,
extra_minion_data=None,
clean_cache=False,
@ -121,7 +121,7 @@ index 7be963566a..906bdfe55d 100644
):
# Yes, we need all of these because we need to route to the Pillar object
# if we have no cache. This is another refactor target.
@@ -432,6 +438,8 @@ class PillarCache:
@@ -434,6 +440,8 @@ class PillarCache:
minion_cache_path=self._minion_cache_path(minion_id),
)
@ -130,15 +130,15 @@ index 7be963566a..906bdfe55d 100644
def _minion_cache_path(self, minion_id):
"""
Return the path to the cache file for the minion.
@@ -455,6 +463,7 @@ class PillarCache:
functions=self.functions,
@@ -458,6 +466,7 @@ class PillarCache:
pillar_override=self.pillar_override,
pillarenv=self.pillarenv,
extra_minion_data=self.extra_minion_data,
+ context=self.context,
)
return fresh_pillar.compile_pillar()
@@ -530,6 +539,7 @@ class Pillar:
@@ -533,6 +542,7 @@ class Pillar:
pillar_override=None,
pillarenv=None,
extra_minion_data=None,
@ -146,7 +146,7 @@ index 7be963566a..906bdfe55d 100644
):
self.minion_id = minion_id
self.ext = ext
@@ -568,7 +578,7 @@ class Pillar:
@@ -571,7 +581,7 @@ class Pillar:
if opts.get("pillar_source_merging_strategy"):
self.merge_strategy = opts["pillar_source_merging_strategy"]
@ -155,7 +155,7 @@ index 7be963566a..906bdfe55d 100644
self.ignored_pillars = {}
self.pillar_override = pillar_override or {}
if not isinstance(self.pillar_override, dict):
@@ -1335,7 +1345,7 @@ class Pillar:
@@ -1338,7 +1348,7 @@ class Pillar:
"""
This method exist in order to be API compatible with RemotePillar
"""
@ -165,22 +165,22 @@ index 7be963566a..906bdfe55d 100644
self._closing = True
diff --git a/tests/pytests/unit/test_master.py b/tests/pytests/unit/test_master.py
index a49ecfec3b..ca02c7788d 100644
index cd11d217c7..98c796912a 100644
--- a/tests/pytests/unit/test_master.py
+++ b/tests/pytests/unit/test_master.py
@@ -1,7 +1,7 @@
import time
@@ -4,7 +4,7 @@ import pytest
import salt.master
import salt.utils.platform
-from tests.support.mock import patch
+from tests.support.mock import MagicMock, patch
def test_fileserver_duration():
@@ -14,3 +14,92 @@ def test_fileserver_duration():
update.called_once()
# Timeout is 1 second
assert 2 > end - start > 1
@pytest.fixture
@@ -160,3 +160,92 @@ def test_when_syndic_return_processes_load_then_correct_values_should_be_returne
with patch.object(encrypted_requests, "_return", autospec=True) as fake_return:
encrypted_requests._syndic_return(payload)
fake_return.assert_called_with(expected_return)
+
+
+def test_mworker_pass_context():
@ -271,6 +271,6 @@ index a49ecfec3b..ca02c7788d 100644
+ == test_context
+ )
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From ad3735581379e5d4bbc7baef3eaa4a1b8387ccbf Mon Sep 17 00:00:00 2001
From 90236c844cfce7da8beb7a570be19a8677c60820 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Tue, 12 Apr 2022 10:06:43 +0300
Subject: [PATCH] Prevent affection of SSH.opts with LazyLoader
@ -9,13 +9,17 @@ Subject: [PATCH] Prevent affection of SSH.opts with LazyLoader
* Restore parsed targets
* Fix test_ssh unit tests
Adjust unit tests
---
salt/client/ssh/__init__.py | 19 +++++++++++--------
tests/unit/client/test_ssh.py | 18 +++++++++---------
2 files changed, 20 insertions(+), 17 deletions(-)
salt/client/ssh/__init__.py | 19 +++++++++-------
.../pytests/unit/client/ssh/test_password.py | 4 +++-
.../unit/client/ssh/test_return_events.py | 2 +-
tests/pytests/unit/client/ssh/test_ssh.py | 22 +++++++++----------
4 files changed, 26 insertions(+), 21 deletions(-)
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index 8ae417f575..fe1213b723 100644
index a527c03de6..d5a679821e 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -224,15 +224,16 @@ class SSH(MultiprocessingStateMixin):
@ -92,92 +96,145 @@ index 8ae417f575..fe1213b723 100644
self.targets
) >= len(running):
time.sleep(0.1)
diff --git a/tests/unit/client/test_ssh.py b/tests/unit/client/test_ssh.py
index 00313ed55f..92a9314149 100644
--- a/tests/unit/client/test_ssh.py
+++ b/tests/unit/client/test_ssh.py
@@ -95,7 +95,7 @@ class SSHReturnEventTests(ShellCase):
assert "localhost" in ret
assert "fun" in ret["localhost"]
client.run()
- display_output.assert_called_once_with(expected, "nested", opts)
+ display_output.assert_called_once_with(expected, "nested", client.opts)
self.assertIs(ret, handle_ssh_ret[0])
assert len(client.event.fire_event.call_args_list) == 2
assert "fun" in client.event.fire_event.call_args_list[0][0][0]
@@ -539,7 +539,7 @@ class SSHTests(ShellCase):
MagicMock(return_value=salt.utils.yaml.safe_load(self.roster)),
):
client._expand_target()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
diff --git a/tests/pytests/unit/client/ssh/test_password.py b/tests/pytests/unit/client/ssh/test_password.py
index 8a7794d2f4..0ca28d022e 100644
--- a/tests/pytests/unit/client/ssh/test_password.py
+++ b/tests/pytests/unit/client/ssh/test_password.py
@@ -27,6 +27,8 @@ def test_password_failure(temp_salt_master, tmp_path):
opts["argv"] = ["test.ping"]
opts["selected_target_option"] = "glob"
opts["tgt"] = "localhost"
+ opts["ssh_cli_tgt"] = "localhost"
+ opts["_ssh_version"] = "foobar"
opts["arg"] = []
roster = str(tmp_path / "roster")
handle_ssh_ret = [
@@ -44,7 +46,7 @@ def test_password_failure(temp_salt_master, tmp_path):
"salt.client.ssh.SSH.handle_ssh", MagicMock(return_value=handle_ssh_ret)
), patch("salt.client.ssh.SSH.key_deploy", MagicMock(return_value=expected)), patch(
"salt.output.display_output", display_output
- ):
+ ), patch("salt.client.ssh.ssh_version", MagicMock(return_value="foobar")):
client = ssh.SSH(opts)
ret = next(client.run_iter())
with pytest.raises(SystemExit):
diff --git a/tests/pytests/unit/client/ssh/test_return_events.py b/tests/pytests/unit/client/ssh/test_return_events.py
index 1f0b0dbf33..18714741b9 100644
--- a/tests/pytests/unit/client/ssh/test_return_events.py
+++ b/tests/pytests/unit/client/ssh/test_return_events.py
@@ -43,7 +43,7 @@ def test_not_missing_fun_calling_wfuncs(temp_salt_master, tmp_path):
assert "localhost" in ret
assert "fun" in ret["localhost"]
client.run()
- display_output.assert_called_once_with(expected, "nested", opts)
+ display_output.assert_called_once_with(expected, "nested", client.opts)
assert ret is handle_ssh_ret[0]
assert len(client.event.fire_event.call_args_list) == 2
assert "fun" in client.event.fire_event.call_args_list[0][0][0]
diff --git a/tests/pytests/unit/client/ssh/test_ssh.py b/tests/pytests/unit/client/ssh/test_ssh.py
index 2be96ab195..377aad9998 100644
--- a/tests/pytests/unit/client/ssh/test_ssh.py
+++ b/tests/pytests/unit/client/ssh/test_ssh.py
@@ -148,7 +148,7 @@ def test_expand_target_ip_address(opts, roster):
MagicMock(return_value=salt.utils.yaml.safe_load(roster)),
):
client._expand_target()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
def test_expand_target_no_host(self):
"""
@@ -564,7 +564,7 @@ class SSHTests(ShellCase):
assert opts["tgt"] == user + host
with patch("salt.roster.get_roster_file", MagicMock(return_value=roster_file)):
client._expand_target()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
def test_expand_target_dns(self):
"""
@@ -587,7 +587,7 @@ class SSHTests(ShellCase):
MagicMock(return_value=salt.utils.yaml.safe_load(self.roster)),
):
client._expand_target()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
def test_expand_target_no_host(opts, tmp_path):
@@ -171,7 +171,7 @@ def test_expand_target_no_host(opts, tmp_path):
assert opts["tgt"] == user + host
with patch("salt.roster.get_roster_file", MagicMock(return_value=roster_file)):
client._expand_target()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
def test_expand_target_no_user(self):
"""
@@ -627,7 +627,7 @@ class SSHTests(ShellCase):
client = ssh.SSH(opts)
assert opts["tgt"] == user + host
client._update_targets()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
assert client.targets[host]["user"] == user.split("@")[0]
def test_update_targets_dns(self):
@@ -645,7 +645,7 @@ class SSHTests(ShellCase):
client = ssh.SSH(opts)
assert opts["tgt"] == user + host
client._update_targets()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
assert client.targets[host]["user"] == user.split("@")[0]
def test_expand_target_dns(opts, roster):
@@ -192,7 +192,7 @@ def test_expand_target_dns(opts, roster):
MagicMock(return_value=salt.utils.yaml.safe_load(roster)),
):
client._expand_target()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
def test_update_targets_no_user(self):
@@ -686,7 +686,7 @@ class SSHTests(ShellCase):
):
client._expand_target()
client._update_targets()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
assert client.targets[host]["user"] == user.split("@")[0]
def test_parse_tgt(self):
@@ -706,7 +706,7 @@ class SSHTests(ShellCase):
client = ssh.SSH(opts)
assert client.parse_tgt["hostname"] == host
assert client.parse_tgt["user"] == user.split("@")[0]
- assert self.opts.get("ssh_cli_tgt") == user + host
+ assert client.opts.get("ssh_cli_tgt") == user + host
def test_expand_target_no_user(opts, roster):
@@ -204,7 +204,7 @@ def test_expand_target_no_user(opts, roster):
def test_parse_tgt_no_user(self):
"""
@@ -725,7 +725,7 @@ class SSHTests(ShellCase):
client = ssh.SSH(opts)
assert client.parse_tgt["hostname"] == host
assert client.parse_tgt["user"] == opts["ssh_user"]
- assert self.opts.get("ssh_cli_tgt") == host
+ assert client.opts.get("ssh_cli_tgt") == host
with patch("salt.utils.network.is_reachable_host", MagicMock(return_value=False)):
client = ssh.SSH(opts)
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
def test_extra_filerefs(self):
"""
with patch(
"salt.roster.get_roster_file", MagicMock(return_value="/etc/salt/roster")
@@ -213,7 +213,7 @@ def test_expand_target_no_user(opts, roster):
MagicMock(return_value=salt.utils.yaml.safe_load(roster)),
):
client._expand_target()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
def test_update_targets_ip_address(opts):
@@ -228,7 +228,7 @@ def test_update_targets_ip_address(opts):
client = ssh.SSH(opts)
assert opts["tgt"] == user + host
client._update_targets()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
assert client.targets[host]["user"] == user.split("@")[0]
@@ -244,7 +244,7 @@ def test_update_targets_dns(opts):
client = ssh.SSH(opts)
assert opts["tgt"] == user + host
client._update_targets()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
assert client.targets[host]["user"] == user.split("@")[0]
@@ -259,7 +259,7 @@ def test_update_targets_no_user(opts):
client = ssh.SSH(opts)
assert opts["tgt"] == host
client._update_targets()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
def test_update_expand_target_dns(opts, roster):
@@ -281,7 +281,7 @@ def test_update_expand_target_dns(opts, roster):
):
client._expand_target()
client._update_targets()
- assert opts["tgt"] == host
+ assert client.opts["tgt"] == host
assert client.targets[host]["user"] == user.split("@")[0]
@@ -299,7 +299,7 @@ def test_parse_tgt(opts):
client = ssh.SSH(opts)
assert client.parse_tgt["hostname"] == host
assert client.parse_tgt["user"] == user.split("@")[0]
- assert opts.get("ssh_cli_tgt") == user + host
+ assert client.opts.get("ssh_cli_tgt") == user + host
def test_parse_tgt_no_user(opts):
@@ -316,7 +316,7 @@ def test_parse_tgt_no_user(opts):
client = ssh.SSH(opts)
assert client.parse_tgt["hostname"] == host
assert client.parse_tgt["user"] == opts["ssh_user"]
- assert opts.get("ssh_cli_tgt") == host
+ assert client.opts.get("ssh_cli_tgt") == host
def test_extra_filerefs(tmp_path, opts):
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 6c1878310bf75be467b5ce15e8c89134a6f770cb Mon Sep 17 00:00:00 2001
From 4240f0d5ffbc46c557885c5a28d1f2fd0b4c5e48 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
Date: Mon, 8 Nov 2021 17:42:36 +0300
Subject: [PATCH] Prevent pkg plugins errors on missing cookie path
@ -97,6 +97,6 @@ index bacbc8b97e..e3528e87a9 100755
self.ack()
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 57f2400bfce206e16e7f282cd3b93cd4d7e99dd7 Mon Sep 17 00:00:00 2001
From 1b4e382856e1d5d8ef95890aec5a8e5e07254708 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Mon, 28 Feb 2022 14:25:43 +0000
@ -28,6 +28,6 @@ index e050f43caf..2d1a276cb8 100644
class SaltLogRecord(logging.LogRecord):
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From c27ac9afb6bd13fc26fc440e0a097bbb82cbb640 Mon Sep 17 00:00:00 2001
From ce0fedf25dea7eb63ccff8f9b90a9a35571a5f9d Mon Sep 17 00:00:00 2001
From: Mihai Dinca <mdinca@suse.de>
Date: Thu, 7 Nov 2019 15:11:49 +0100
Subject: [PATCH] Read repo info without using interpolation
@ -9,10 +9,10 @@ Subject: [PATCH] Read repo info without using interpolation
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index dd836b7ad0..32e22ce9a8 100644
index 6adf5f9aa3..d8220a1fdd 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -1121,7 +1121,9 @@ def _get_repo_info(alias, repos_cfg=None, root=None):
@@ -1155,7 +1155,9 @@ def _get_repo_info(alias, repos_cfg=None, root=None):
Get one repo meta-data.
"""
try:
@ -24,6 +24,6 @@ index dd836b7ad0..32e22ce9a8 100644
for key, val in meta.items():
if val in ["0", "1"]:
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 2de635bd9c2f9571092d5904ac8fa971c0140235 Mon Sep 17 00:00:00 2001
From a1a8b5a886705e5f005cb7ab067e42095066ef80 Mon Sep 17 00:00:00 2001
From: Jochen Breuer <jbreuer@suse.de>
Date: Fri, 30 Aug 2019 14:20:06 +0200
Subject: [PATCH] Restore default behaviour of pkg list return
@ -13,10 +13,10 @@ Co-authored-by: Mihai Dinca <mdinca@suse.de>
1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index e52535d428..dd836b7ad0 100644
index 9d16fcb0b1..6adf5f9aa3 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -1410,8 +1410,10 @@ def refresh_db(force=None, root=None):
@@ -1456,8 +1456,10 @@ def refresh_db(force=None, root=None):
return ret
@ -28,7 +28,7 @@ index e52535d428..dd836b7ad0 100644
return sorted({pkg.split(":", 1)[0] for pkg in pkgs if len(pkg.split(":", 1)) == 2})
@@ -1427,6 +1429,7 @@ def install(
@@ -1473,6 +1475,7 @@ def install(
ignore_repo_failure=False,
no_recommends=False,
root=None,
@ -36,7 +36,7 @@ index e52535d428..dd836b7ad0 100644
**kwargs
):
"""
@@ -1542,6 +1545,9 @@ def install(
@@ -1588,6 +1591,9 @@ def install(
.. versionadded:: 2018.3.0
@ -46,7 +46,7 @@ index e52535d428..dd836b7ad0 100644
Returns a dict containing the new package names and versions::
@@ -1617,7 +1623,8 @@ def install(
@@ -1663,7 +1669,8 @@ def install(
diff_attr = kwargs.get("diff_attr")
@ -56,7 +56,7 @@ index e52535d428..dd836b7ad0 100644
old = (
list_pkgs(attr=diff_attr, root=root, includes=includes)
if not downloadonly
@@ -1847,7 +1854,7 @@ def upgrade(
@@ -1964,7 +1971,7 @@ def upgrade(
return ret
@ -65,7 +65,7 @@ index e52535d428..dd836b7ad0 100644
"""
Remove and purge do identical things but with different Zypper commands,
this function performs the common logic.
@@ -1857,7 +1864,7 @@ def _uninstall(name=None, pkgs=None, root=None):
@@ -1974,7 +1981,7 @@ def _uninstall(name=None, pkgs=None, root=None):
except MinionError as exc:
raise CommandExecutionError(exc)
@ -74,7 +74,7 @@ index e52535d428..dd836b7ad0 100644
old = list_pkgs(root=root, includes=includes)
targets = []
for target in pkg_params:
@@ -1920,7 +1927,7 @@ def normalize_name(name):
@@ -2037,7 +2044,7 @@ def normalize_name(name):
def remove(
@ -83,7 +83,7 @@ index e52535d428..dd836b7ad0 100644
): # pylint: disable=unused-argument
"""
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
@@ -1952,8 +1959,11 @@ def remove(
@@ -2069,8 +2076,11 @@ def remove(
root
Operate on a different root directory.
@ -96,7 +96,7 @@ index e52535d428..dd836b7ad0 100644
Returns a dict containing the changes.
@@ -1965,10 +1975,12 @@ def remove(
@@ -2082,10 +2092,12 @@ def remove(
salt '*' pkg.remove <package1>,<package2>,<package3>
salt '*' pkg.remove pkgs='["foo", "bar"]'
"""
@ -111,7 +111,7 @@ index e52535d428..dd836b7ad0 100644
"""
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
On minions running systemd>=205, `systemd-run(1)`_ is now used to
@@ -2000,6 +2012,10 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused-
@@ -2117,6 +2129,10 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused-
root
Operate on a different root directory.
@ -122,7 +122,7 @@ index e52535d428..dd836b7ad0 100644
.. versionadded:: 0.16.0
@@ -2013,7 +2029,7 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused-
@@ -2130,7 +2146,7 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused-
salt '*' pkg.purge <package1>,<package2>,<package3>
salt '*' pkg.purge pkgs='["foo", "bar"]'
"""
@ -132,6 +132,6 @@ index e52535d428..dd836b7ad0 100644
def list_holds(pattern=None, full=True, root=None, **kwargs):
--
2.37.3
2.39.2

View File

@ -1,297 +0,0 @@
From 4a9ec335e7da2f0e3314580e43075bb69fe90c38 Mon Sep 17 00:00:00 2001
From: Witek Bedyk <witold.bedyk@suse.com>
Date: Mon, 29 Aug 2022 14:16:00 +0200
Subject: [PATCH] Retry if RPM lock is temporarily unavailable (#547)
* Retry if RPM lock is temporarily unavailable
Backported from saltstack/salt#62204
Signed-off-by: Witek Bedyk <witold.bedyk@suse.com>
* Sync formating fixes from upstream
Signed-off-by: Witek Bedyk <witold.bedyk@suse.com>
---
changelog/62204.fixed | 1 +
salt/modules/zypperpkg.py | 117 +++++++++++++++++----------
tests/unit/modules/test_zypperpkg.py | 45 ++++++++++-
3 files changed, 115 insertions(+), 48 deletions(-)
create mode 100644 changelog/62204.fixed
diff --git a/changelog/62204.fixed b/changelog/62204.fixed
new file mode 100644
index 0000000000..59f1914593
--- /dev/null
+++ b/changelog/62204.fixed
@@ -0,0 +1 @@
+Fixed Zypper module failing on RPM lock file being temporarily unavailable.
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index 2c36e2968a..c787d4009d 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -14,6 +14,7 @@ Package support for openSUSE via the zypper package manager
import configparser
import datetime
+import errno
import fnmatch
import logging
import os
@@ -39,6 +40,9 @@ from salt.exceptions import CommandExecutionError, MinionError, SaltInvocationEr
# pylint: disable=import-error,redefined-builtin,no-name-in-module
from salt.utils.versions import LooseVersion
+if salt.utils.files.is_fcntl_available():
+ import fcntl
+
log = logging.getLogger(__name__)
HAS_ZYPP = False
@@ -106,6 +110,7 @@ class _Zypper:
XML_DIRECTIVES = ["-x", "--xmlout"]
# ZYPPER_LOCK is not affected by --root
ZYPPER_LOCK = "/var/run/zypp.pid"
+ RPM_LOCK = "/var/lib/rpm/.rpm.lock"
TAG_RELEASED = "zypper/released"
TAG_BLOCKED = "zypper/blocked"
@@ -276,7 +281,7 @@ class _Zypper:
and self.exit_code not in self.WARNING_EXIT_CODES
)
- def _is_lock(self):
+ def _is_zypper_lock(self):
"""
Is this is a lock error code?
@@ -284,6 +289,23 @@ class _Zypper:
"""
return self.exit_code == self.LOCK_EXIT_CODE
+ def _is_rpm_lock(self):
+ """
+ Is this an RPM lock error?
+ """
+ if salt.utils.files.is_fcntl_available():
+ if self.exit_code > 0 and os.path.exists(self.RPM_LOCK):
+ with salt.utils.files.fopen(self.RPM_LOCK, mode="w+") as rfh:
+ try:
+ fcntl.lockf(rfh, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ except OSError as err:
+ if err.errno == errno.EAGAIN:
+ return True
+ else:
+ fcntl.lockf(rfh, fcntl.LOCK_UN)
+
+ return False
+
def _is_xml_mode(self):
"""
Is Zypper's output is in XML format?
@@ -306,7 +328,7 @@ class _Zypper:
raise CommandExecutionError("No output result from Zypper?")
self.exit_code = self.__call_result["retcode"]
- if self._is_lock():
+ if self._is_zypper_lock() or self._is_rpm_lock():
return False
if self._is_error():
@@ -387,48 +409,11 @@ class _Zypper:
if self._check_result():
break
- if os.path.exists(self.ZYPPER_LOCK):
- try:
- with salt.utils.files.fopen(self.ZYPPER_LOCK) as rfh:
- data = __salt__["ps.proc_info"](
- int(rfh.readline()),
- attrs=["pid", "name", "cmdline", "create_time"],
- )
- data["cmdline"] = " ".join(data["cmdline"])
- data["info"] = "Blocking process created at {}.".format(
- datetime.datetime.utcfromtimestamp(
- data["create_time"]
- ).isoformat()
- )
- data["success"] = True
- except Exception as err: # pylint: disable=broad-except
- data = {
- "info": (
- "Unable to retrieve information about blocking process: {}".format(
- err.message
- )
- ),
- "success": False,
- }
- else:
- data = {
- "info": "Zypper is locked, but no Zypper lock has been found.",
- "success": False,
- }
-
- if not data["success"]:
- log.debug("Unable to collect data about blocking process.")
- else:
- log.debug("Collected data about blocking process.")
-
- __salt__["event.fire_master"](data, self.TAG_BLOCKED)
- log.debug(
- "Fired a Zypper blocked event to the master with the data: %s", data
- )
- log.debug("Waiting 5 seconds for Zypper gets released...")
- time.sleep(5)
- if not was_blocked:
- was_blocked = True
+ if self._is_zypper_lock():
+ self._handle_zypper_lock_file()
+ if self._is_rpm_lock():
+ self._handle_rpm_lock_file()
+ was_blocked = True
if was_blocked:
__salt__["event.fire_master"](
@@ -451,6 +436,50 @@ class _Zypper:
or self.__call_result["stdout"]
)
+ def _handle_zypper_lock_file(self):
+ if os.path.exists(self.ZYPPER_LOCK):
+ try:
+ with salt.utils.files.fopen(self.ZYPPER_LOCK) as rfh:
+ data = __salt__["ps.proc_info"](
+ int(rfh.readline()),
+ attrs=["pid", "name", "cmdline", "create_time"],
+ )
+ data["cmdline"] = " ".join(data["cmdline"])
+ data["info"] = "Blocking process created at {}.".format(
+ datetime.datetime.utcfromtimestamp(
+ data["create_time"]
+ ).isoformat()
+ )
+ data["success"] = True
+ except Exception as err: # pylint: disable=broad-except
+ data = {
+ "info": (
+ "Unable to retrieve information about "
+ "blocking process: {}".format(err)
+ ),
+ "success": False,
+ }
+ else:
+ data = {
+ "info": "Zypper is locked, but no Zypper lock has been found.",
+ "success": False,
+ }
+ if not data["success"]:
+ log.debug("Unable to collect data about blocking process.")
+ else:
+ log.debug("Collected data about blocking process.")
+ __salt__["event.fire_master"](data, self.TAG_BLOCKED)
+ log.debug("Fired a Zypper blocked event to the master with the data: %s", data)
+ log.debug("Waiting 5 seconds for Zypper gets released...")
+ time.sleep(5)
+
+ def _handle_rpm_lock_file(self):
+ data = {"info": "RPM is temporarily locked.", "success": True}
+ __salt__["event.fire_master"](data, self.TAG_BLOCKED)
+ log.debug("Fired an RPM blocked event to the master with the data: %s", data)
+ log.debug("Waiting 5 seconds for RPM to get released...")
+ time.sleep(5)
+
__zypper__ = _Zypper()
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
index 3f1560a385..37d555844c 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -4,6 +4,7 @@
import configparser
+import errno
import io
import os
from xml.dom import minidom
@@ -97,7 +98,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
}
with patch.dict(
zypper.__salt__, {"cmd.run_all": MagicMock(return_value=ref_out)}
- ):
+ ), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
upgrades = zypper.list_upgrades(refresh=False)
self.assertEqual(len(upgrades), 3)
for pkg, version in {
@@ -198,7 +199,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
' type="error">Booya!</message></stream>'
)
sniffer = RunSniffer(stdout=stdout_xml_snippet, retcode=1)
- with patch.dict("salt.modules.zypperpkg.__salt__", {"cmd.run_all": sniffer}):
+ with patch.dict(
+ "salt.modules.zypperpkg.__salt__", {"cmd.run_all": sniffer}
+ ), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
with self.assertRaisesRegex(
CommandExecutionError, "^Zypper command failure: Booya!$"
):
@@ -232,7 +235,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
with patch.dict(
"salt.modules.zypperpkg.__salt__",
{"cmd.run_all": MagicMock(return_value=ref_out)},
- ):
+ ), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
with self.assertRaisesRegex(
CommandExecutionError,
"^Zypper command failure: Some handled zypper internal error{}Another"
@@ -245,7 +248,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
with patch.dict(
"salt.modules.zypperpkg.__salt__",
{"cmd.run_all": MagicMock(return_value=ref_out)},
- ):
+ ), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
with self.assertRaisesRegex(
CommandExecutionError, "^Zypper command failure: Check Zypper's logs.$"
):
@@ -2064,3 +2067,37 @@ pattern() = package-c"""
python_shell=False,
env={"ZYPP_READONLY_HACK": "1"},
)
+
+ def test_is_rpm_lock_no_error(self):
+ with patch.object(os.path, "exists", return_value=True):
+ self.assertFalse(zypper.__zypper__._is_rpm_lock())
+
+ def test_rpm_lock_does_not_exist(self):
+ if salt.utils.files.is_fcntl_available():
+ zypper.__zypper__.exit_code = 1
+ with patch.object(
+ os.path, "exists", return_value=False
+ ) as mock_path_exists:
+ self.assertFalse(zypper.__zypper__._is_rpm_lock())
+ mock_path_exists.assert_called_with(zypper.__zypper__.RPM_LOCK)
+ zypper.__zypper__._reset()
+
+ def test_rpm_lock_acquirable(self):
+ if salt.utils.files.is_fcntl_available():
+ zypper.__zypper__.exit_code = 1
+ with patch.object(os.path, "exists", return_value=True), patch(
+ "fcntl.lockf", side_effect=OSError(errno.EAGAIN, "")
+ ) as lockf_mock, patch("salt.utils.files.fopen", mock_open()):
+ self.assertTrue(zypper.__zypper__._is_rpm_lock())
+ lockf_mock.assert_called()
+ zypper.__zypper__._reset()
+
+ def test_rpm_lock_not_acquirable(self):
+ if salt.utils.files.is_fcntl_available():
+ zypper.__zypper__.exit_code = 1
+ with patch.object(os.path, "exists", return_value=True), patch(
+ "fcntl.lockf"
+ ) as lockf_mock, patch("salt.utils.files.fopen", mock_open()):
+ self.assertFalse(zypper.__zypper__._is_rpm_lock())
+ self.assertEqual(lockf_mock.call_count, 2)
+ zypper.__zypper__._reset()
--
2.37.3

View File

@ -1,4 +1,4 @@
From 3ce70f43376dbf62edf2ca2aa8c9f28aa733b3d8 Mon Sep 17 00:00:00 2001
From ceaf42a67d21cb6fa723339559c85be969e67308 Mon Sep 17 00:00:00 2001
From: Mihai Dinca <mdinca@suse.de>
Date: Thu, 13 Dec 2018 12:17:35 +0100
Subject: [PATCH] Return the expected powerpc os arch (bsc#1117995)
@ -8,10 +8,10 @@ Subject: [PATCH] Return the expected powerpc os arch (bsc#1117995)
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/salt/utils/pkg/rpm.py b/salt/utils/pkg/rpm.py
index e80a01f92f..8203d2f989 100644
index f9975f8dff..147447ba75 100644
--- a/salt/utils/pkg/rpm.py
+++ b/salt/utils/pkg/rpm.py
@@ -59,9 +59,10 @@ def get_osarch():
@@ -69,9 +69,10 @@ def get_osarch():
stderr=subprocess.PIPE,
).communicate()[0]
else:
@ -26,6 +26,6 @@ index e80a01f92f..8203d2f989 100644
def check_32(arch, osarch=None):
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From dc849a15ea214170d4de9f54615caa8b3136dc10 Mon Sep 17 00:00:00 2001
From 76f2b98a3a9b9a49903a4d3b47dca0f2311bd7af Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 19:07:34 +0100
Subject: [PATCH] Revert "Fixing a use case when multiple inotify beacons
@ -17,8 +17,8 @@ This reverts commit 66c58dedf8c364eaeb35c5adce8bcc8fe5c1219a.
salt/beacons/napalm_beacon.py | 6 ++----
salt/beacons/status.py | 4 ----
tests/pytests/unit/beacons/test_inotify.py | 5 +----
tests/pytests/unit/test_beacons.py | 16 ---------------
7 files changed, 11 insertions(+), 48 deletions(-)
tests/pytests/unit/test_beacons.py | 17 ---------------
7 files changed, 11 insertions(+), 49 deletions(-)
diff --git a/salt/beacons/__init__.py b/salt/beacons/__init__.py
index b346c2a648..90918cba5b 100644
@ -162,10 +162,10 @@ index aa5aa13b47..e2c3177ea8 100644
config = [
{
diff --git a/tests/pytests/unit/beacons/test_inotify.py b/tests/pytests/unit/beacons/test_inotify.py
index f5befb2756..dfaf1d499a 100644
index 30a9a91db4..678a528529 100644
--- a/tests/pytests/unit/beacons/test_inotify.py
+++ b/tests/pytests/unit/beacons/test_inotify.py
@@ -273,7 +273,6 @@ def test_multi_files_exclude(tmp_path):
@@ -263,7 +263,6 @@ def test_multi_files_exclude(tmp_path):
# Check __get_notifier and ensure that the right bits are in __context__
@ -173,7 +173,7 @@ index f5befb2756..dfaf1d499a 100644
def test__get_notifier():
config = {
"files": {
@@ -303,10 +302,8 @@ def test__get_notifier():
@@ -293,10 +292,8 @@ def test__get_notifier():
},
},
"coalesce": True,
@ -186,13 +186,14 @@ index f5befb2756..dfaf1d499a 100644
- assert "httpd.inotify.notifier" in inotify.__context__
+ assert "inotify.notifier" in inotify.__context__
diff --git a/tests/pytests/unit/test_beacons.py b/tests/pytests/unit/test_beacons.py
index 2ca0b30ea2..841a3b8140 100644
index 217cd5c6a4..855e271d7d 100644
--- a/tests/pytests/unit/test_beacons.py
+++ b/tests/pytests/unit/test_beacons.py
@@ -108,19 +108,3 @@ def test_beacon_module():
@@ -104,20 +104,3 @@ def test_beacon_module(minion_opts):
}
]
assert ret == _expected
-
- # Ensure that "beacon_name" is available in the call to the beacon function
- name = "ps.beacon"
- mocked = {name: MagicMock(return_value=_expected)}
@ -207,9 +208,9 @@ index 2ca0b30ea2..841a3b8140 100644
- )
- ]
- with patch.object(beacon, "beacons", mocked) as patched:
- beacon.process(mock_opts["beacons"], mock_opts["grains"])
- beacon.process(minion_opts["beacons"], minion_opts["grains"])
- patched[name].assert_has_calls(calls)
--
2.37.3
2.39.2

View File

@ -1,16 +1,16 @@
From 0dc36f5d2e8ba94e2a527323b698fd49a98f5246 Mon Sep 17 00:00:00 2001
From a94cfd5dea05c2c4a9d6b8b243048a2ceeb3f208 Mon Sep 17 00:00:00 2001
From: Christian Lanig <clanig@suse.com>
Date: Mon, 27 Nov 2017 13:10:26 +0100
Subject: [PATCH] Run salt-api as user salt (bsc#1064520)
---
pkg/salt-api.service | 1 +
pkg/common/salt-api.service | 1 +
1 file changed, 1 insertion(+)
diff --git a/pkg/salt-api.service b/pkg/salt-api.service
diff --git a/pkg/common/salt-api.service b/pkg/common/salt-api.service
index d0b6d74120..9cdc9c582b 100644
--- a/pkg/salt-api.service
+++ b/pkg/salt-api.service
--- a/pkg/common/salt-api.service
+++ b/pkg/common/salt-api.service
@@ -6,6 +6,7 @@ After=network.target
[Service]
Type=notify
@ -20,6 +20,6 @@ index d0b6d74120..9cdc9c582b 100644
ExecStart=/usr/bin/salt-api
TimeoutStopSec=3
--
2.37.3
2.39.2

View File

@ -1,16 +1,16 @@
From 34d047fa0e2733359501e15ecc282159ddbd29f9 Mon Sep 17 00:00:00 2001
From 6ffbf7fcc178f32c670b177b25ed64658c59f1bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Klaus=20K=C3=A4mpf?= <kkaempf@suse.de>
Date: Wed, 20 Jan 2016 11:01:06 +0100
Subject: [PATCH] Run salt master as dedicated salt user
* Minion runs always as a root
---
conf/master | 3 ++-
pkg/salt-common.logrotate | 2 ++
conf/master | 3 ++-
pkg/common/salt-common.logrotate | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/conf/master b/conf/master
index 17b3768267..95aed0066f 100644
index f542051d76..acff94abec 100644
--- a/conf/master
+++ b/conf/master
@@ -25,7 +25,8 @@
@ -23,10 +23,10 @@ index 17b3768267..95aed0066f 100644
# Tell the master to also use salt-ssh when running commands against minions.
#enable_ssh_minions: False
diff --git a/pkg/salt-common.logrotate b/pkg/salt-common.logrotate
diff --git a/pkg/common/salt-common.logrotate b/pkg/common/salt-common.logrotate
index a0306ff370..97d158db18 100644
--- a/pkg/salt-common.logrotate
+++ b/pkg/salt-common.logrotate
--- a/pkg/common/salt-common.logrotate
+++ b/pkg/common/salt-common.logrotate
@@ -1,4 +1,5 @@
/var/log/salt/master {
+ su salt salt
@ -42,6 +42,6 @@ index a0306ff370..97d158db18 100644
missingok
rotate 7
--
2.37.3
2.39.2

View File

@ -1,3 +1,105 @@
-------------------------------------------------------------------
Fri May 5 08:29:26 UTC 2023 - Alexander Graul <alexander.graul@suse.com>
- Update to Salt release version 3006.0 (jsc#PED-3139)
* See release notes: https://docs.saltproject.io/en/latest/topics/releases/3006.0.html
- Add python3-looseversion as new dependency for salt
- Add python3-packaging as new dependency for salt
- Drop conflictive patch dicarded from upstream
- Fix SLS rendering error when Jinja macros are used
- Fix version detection and avoid building and testing failures
- Added:
* fix-version-detection-and-avoid-building-and-testing.patch
* make-sure-the-file-client-is-destroyed-upon-used.patch
- Modified:
* 3005.1-implement-zypper-removeptf-573.patch
* activate-all-beacons-sources-config-pillar-grains.patch
* add-custom-suse-capabilities-as-grains.patch
* add-environment-variable-to-know-if-yum-is-invoked-f.patch
* add-migrated-state-and-gpg-key-management-functions-.patch
* add-publish_batch-to-clearfuncs-exposed-methods.patch
* add-salt-ssh-support-with-venv-salt-minion-3004-493.patch
* add-sleep-on-exception-handling-on-minion-connection.patch
* add-standalone-configuration-file-for-enabling-packa.patch
* add-support-for-gpgautoimport-539.patch
* allow-vendor-change-option-with-zypper.patch
* async-batch-implementation.patch
* avoid-excessive-syslogging-by-watchdog-cronjob-58.patch
* bsc-1176024-fix-file-directory-user-and-group-owners.patch
* change-the-delimeters-to-prevent-possible-tracebacks.patch
* control-the-collection-of-lvm-grains-via-config.patch
* debian-info_installed-compatibility-50453.patch
* dnfnotify-pkgset-plugin-implementation-3002.2-450.patch
* do-not-load-pip-state-if-there-is-no-3rd-party-depen.patch
* don-t-use-shell-sbin-nologin-in-requisites.patch
* drop-serial-from-event.unpack-in-cli.batch_async.patch
* early-feature-support-config.patch
* enable-passing-a-unix_socket-for-mysql-returners-bsc.patch
* enhance-openscap-module-add-xccdf_eval-call-386.patch
* fix-bsc-1065792.patch
* fix-for-suse-expanded-support-detection.patch
* fix-issue-2068-test.patch
* fix-missing-minion-returns-in-batch-mode-360.patch
* fix-ownership-of-salt-thin-directory-when-using-the-.patch
* fix-regression-with-depending-client.ssh-on-psutil-b.patch
* fix-salt-ssh-opts-poisoning-bsc-1197637-3004-501.patch
* fix-salt.utils.stringutils.to_str-calls-to-make-it-w.patch
* fix-the-regression-for-yumnotify-plugin-456.patch
* fix-traceback.print_exc-calls-for-test_pip_state-432.patch
* fixes-for-python-3.10-502.patch
* include-aliases-in-the-fqdns-grains.patch
* info_installed-works-without-status-attr-now.patch
* let-salt-ssh-use-platform-python-binary-in-rhel8-191.patch
* make-aptpkg.list_repos-compatible-on-enabled-disable.patch
* make-setup.py-script-to-not-require-setuptools-9.1.patch
* pass-the-context-to-pillar-ext-modules.patch
* prevent-affection-of-ssh.opts-with-lazyloader-bsc-11.patch
* prevent-pkg-plugins-errors-on-missing-cookie-path-bs.patch
* prevent-shell-injection-via-pre_flight_script_args-4.patch
* read-repo-info-without-using-interpolation-bsc-11356.patch
* restore-default-behaviour-of-pkg-list-return.patch
* return-the-expected-powerpc-os-arch-bsc-1117995.patch
* revert-fixing-a-use-case-when-multiple-inotify-beaco.patch
* run-salt-api-as-user-salt-bsc-1064520.patch
* run-salt-master-as-dedicated-salt-user.patch
* save-log-to-logfile-with-docker.build.patch
* skip-package-names-without-colon-bsc-1208691-578.patch
* switch-firewalld-state-to-use-change_interface.patch
* temporary-fix-extend-the-whitelist-of-allowed-comman.patch
* update-target-fix-for-salt-ssh-to-process-targets-li.patch
* use-adler32-algorithm-to-compute-string-checksums.patch
* use-rlock-to-avoid-deadlocks-in-salt-ssh.patch
* use-salt-bundle-in-dockermod.patch
* x509-fixes-111.patch
* zypperpkg-ignore-retcode-104-for-search-bsc-1176697-.patch
- Removed:
* add-amazon-ec2-detection-for-virtual-grains-bsc-1195.patch
* add-support-for-name-pkgs-and-diff_attr-parameters-t.patch
* align-amazon-ec2-nitro-grains-with-upstream-pr-bsc-1.patch
* allow-entrypoint-compatibility-for-importlib-metadat.patch
* clarify-pkg.installed-pkg_verify-documentation.patch
* detect-module.run-syntax.patch
* fix-salt.states.file.managed-for-follow_symlinks-tru.patch
* fix-state.apply-in-test-mode-with-file-state-module-.patch
* fix-test_ipc-unit-tests.patch
* fixes-pkg.version_cmp-on-openeuler-systems-and-a-few.patch
* fopen-workaround-bad-buffering-for-binary-mode-563.patch
* ignore-erros-on-reading-license-files-with-dpkg_lowp.patch
* ignore-extend-declarations-from-excluded-sls-files.patch
* ignore-non-utf8-characters-while-reading-files-with-.patch
* include-stdout-in-error-message-for-zypperpkg-559.patch
* make-pass-renderer-configurable-other-fixes-532.patch
* make-sure-saltcacheloader-use-correct-fileclient-519.patch
* normalize-package-names-once-with-pkg.installed-remo.patch
* retry-if-rpm-lock-is-temporarily-unavailable-547.patch
* set-default-target-for-pip-from-venv_pip_target-envi.patch
* state.apply-don-t-check-for-cached-pillar-errors.patch
* state.orchestrate_single-does-not-pass-pillar-none-4.patch
-------------------------------------------------------------------
Fri Mar 17 12:05:55 UTC 2023 - Alexander Graul <alexander.graul@suse.com>

126
salt.spec
View File

@ -36,12 +36,12 @@
%bcond_with builddocs
Name: salt
Version: 3005.1
Version: 3006.0
Release: 0
Summary: A parallel remote execution system
License: Apache-2.0
Group: System/Management
Url: http://saltstack.org/
Url: https://saltproject.io/
Source: v%{version}.tar.gz
Source1: README.SUSE
Source2: salt-tmpfiles.d
@ -219,97 +219,54 @@ Patch41: prevent-pkg-plugins-errors-on-missing-cookie-path-bs.patch
Patch42: dnfnotify-pkgset-plugin-implementation-3002.2-450.patch
# PATCH-FIX_OPENSUSE https://github.com/openSUSE/salt/pull/456 (missing upstream PR)
Patch43: fix-the-regression-for-yumnotify-plugin-456.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/61189
Patch44: state.apply-don-t-check-for-cached-pillar-errors.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/482
Patch45: drop-serial-from-event.unpack-in-cli.batch_async.patch
# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/61093
Patch46: state.orchestrate_single-does-not-pass-pillar-none-4.patch
Patch44: drop-serial-from-event.unpack-in-cli.batch_async.patch
### SALT-SSH WITH SALT BUNDLE ###
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/61715 (ssh_pre_flight_args)
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/493
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/497
Patch47: add-salt-ssh-support-with-venv-salt-minion-3004-493.patch
Patch48: prevent-shell-injection-via-pre_flight_script_args-4.patch
Patch45: add-salt-ssh-support-with-venv-salt-minion-3004-493.patch
Patch46: prevent-shell-injection-via-pre_flight_script_args-4.patch
###############
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/501
Patch49: fix-salt-ssh-opts-poisoning-bsc-1197637-3004-501.patch
Patch47: fix-salt-ssh-opts-poisoning-bsc-1197637-3004-501.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/505
Patch50: prevent-affection-of-ssh.opts-with-lazyloader-bsc-11.patch
Patch48: prevent-affection-of-ssh.opts-with-lazyloader-bsc-11.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/506
Patch51: fix-regression-with-depending-client.ssh-on-psutil-b.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/61895
Patch52: make-sure-saltcacheloader-use-correct-fileclient-519.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/61827
Patch53: ignore-erros-on-reading-license-files-with-dpkg_lowp.patch
Patch49: fix-regression-with-depending-client.ssh-on-psutil-b.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62109
Patch54: use-salt-bundle-in-dockermod.patch
Patch50: use-salt-bundle-in-dockermod.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/61984
Patch55: save-log-to-logfile-with-docker.build.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62029
Patch56: normalize-package-names-once-with-pkg.installed-remo.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62089
Patch57: set-default-target-for-pip-from-venv_pip_target-envi.patch
Patch51: save-log-to-logfile-with-docker.build.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/534
Patch58: fix-ownership-of-salt-thin-directory-when-using-the-.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62033
Patch59: add-support-for-name-pkgs-and-diff_attr-parameters-t.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62067
Patch60: fix-salt.states.file.managed-for-follow_symlinks-tru.patch
Patch52: fix-ownership-of-salt-thin-directory-when-using-the-.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62209
Patch61: add-support-for-gpgautoimport-539.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/2b486d0484c51509e9972e581d97655f4f87852e
Patch62: fix-test_ipc-unit-tests.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62204
Patch63: retry-if-rpm-lock-is-temporarily-unavailable-547.patch
Patch53: add-support-for-gpgautoimport-539.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62519
Patch64: change-the-delimeters-to-prevent-possible-tracebacks.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/61847
Patch65: fix-state.apply-in-test-mode-with-file-state-module-.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62539
Patch66: add-amazon-ec2-detection-for-virtual-grains-bsc-1195.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62633
Patch67: ignore-non-utf8-characters-while-reading-files-with-.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62817
Patch68: fopen-workaround-bad-buffering-for-binary-mode-563.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62120
Patch69: make-pass-renderer-configurable-other-fixes-532.patch
### ENHANCE ZYPPERPKG ERROR MESSAGES ###
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62750
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62346
Patch70: include-stdout-in-error-message-for-zypperpkg-559.patch
###############
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/57426
Patch71: clarify-pkg.installed-pkg_verify-documentation.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62862
Patch72: ignore-extend-declarations-from-excluded-sls-files.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/61772
Patch73: detect-module.run-syntax.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62539
Patch74: align-amazon-ec2-nitro-grains-with-upstream-pr-bsc-1.patch
Patch54: change-the-delimeters-to-prevent-possible-tracebacks.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62898
Patch75: pass-the-context-to-pillar-ext-modules.patch
Patch55: pass-the-context-to-pillar-ext-modules.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/c6be36eeea49ee0d0641da272087305f79c32c99 (not yet upstream)
# Fix problem caused by: https://github.com/openSUSE/salt/pull/493 (Patch47) affecting only 3005.1.
Patch76: use-rlock-to-avoid-deadlocks-in-salt-ssh.patch
Patch56: use-rlock-to-avoid-deadlocks-in-salt-ssh.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/61064
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/5e3ff4d662321c237ddd5b2c5c83f35a84af594c (not PR to master yet)
Patch77: fixes-for-python-3.10-502.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62854
Patch78: allow-entrypoint-compatibility-for-importlib-metadat.patch
Patch57: fixes-for-python-3.10-502.patch
# PATCH-FIX-OPENSUSE: https://github.com/openSUSE/salt/pull/571
Patch79: control-the-collection-of-lvm-grains-via-config.patch
Patch58: control-the-collection-of-lvm-grains-via-config.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/63460
Patch80: 3005.1-implement-zypper-removeptf-573.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/62249
Patch81: fixes-pkg.version_cmp-on-openeuler-systems-and-a-few.patch
Patch59: 3005.1-implement-zypper-removeptf-573.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/63460
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/578
Patch82: skip-package-names-without-colon-bsc-1208691-578.patch
Patch60: skip-package-names-without-colon-bsc-1208691-578.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/commit/c0fae09e5a4f6997a60007d970c7c6a5614d9102
Patch61: fix-version-detection-and-avoid-building-and-testing.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/64113
Patch62: make-sure-the-file-client-is-destroyed-upon-used.patch
### IMPORTANT: The line below is used as a snippet marker. Do not touch it.
### SALT PATCHES LIST END
@ -422,6 +379,8 @@ BuildRequires: python3-PyYAML
BuildRequires: python3-psutil
BuildRequires: python3-requests >= 1.0.0
BuildRequires: python3-distro
BuildRequires: python3-looseversion
BuildRequires: python3-packaging
# requirements/zeromq.txt
%if %{with test}
@ -472,6 +431,8 @@ Requires: python3-PyYAML
Requires: python3-psutil
Requires: python3-requests >= 1.0.0
Requires: python3-distro
Requires: python3-looseversion
Requires: python3-packaging
Requires: python3-contextvars
%if 0%{?suse_version}
# required for zypper.py
@ -750,7 +711,6 @@ cp %{S:6} .
export PATH=/usr/bin:$PATH
%endif
python3 setup.py --with-salt-version=%{version} --salt-transport=both build
cp ./build/lib/salt/_version.py ./salt
mv build _build.python3
%if %{with docs} && %{without builddocs}
@ -849,15 +809,15 @@ install -Dd %{buildroot}%{_sysconfdir}/yum/pluginconf.d
## install init and systemd scripts
%if %{with systemd}
install -Dpm 0644 pkg/suse/salt-master.service %{buildroot}%{_unitdir}/salt-master.service
install -Dpm 0644 pkg/old/suse/salt-master.service %{buildroot}%{_unitdir}/salt-master.service
%if 0%{?suse_version}
install -Dpm 0644 pkg/suse/salt-minion.service %{buildroot}%{_unitdir}/salt-minion.service
install -Dpm 0644 pkg/old/suse/salt-minion.service %{buildroot}%{_unitdir}/salt-minion.service
%else
install -Dpm 0644 pkg/suse/salt-minion.service.rhel7 %{buildroot}%{_unitdir}/salt-minion.service
install -Dpm 0644 pkg/old/suse/salt-minion.service.rhel7 %{buildroot}%{_unitdir}/salt-minion.service
%endif
install -Dpm 0644 pkg/salt-syndic.service %{buildroot}%{_unitdir}/salt-syndic.service
install -Dpm 0644 pkg/suse/salt-api.service %{buildroot}%{_unitdir}/salt-api.service
install -Dpm 0644 pkg/salt-proxy@.service %{buildroot}%{_unitdir}/salt-proxy@.service
install -Dpm 0644 pkg/common/salt-syndic.service %{buildroot}%{_unitdir}/salt-syndic.service
install -Dpm 0644 pkg/old/suse/salt-api.service %{buildroot}%{_unitdir}/salt-api.service
install -Dpm 0644 pkg/common/salt-proxy@.service %{buildroot}%{_unitdir}/salt-proxy@.service
ln -s service %{buildroot}%{_sbindir}/rcsalt-master
ln -s service %{buildroot}%{_sbindir}/rcsalt-syndic
ln -s service %{buildroot}%{_sbindir}/rcsalt-minion
@ -866,10 +826,10 @@ install -Dpm 644 %{S:2} %{buildroot}/usr/lib/tmpfiles.d/salt.c
%else
mkdir -p %{buildroot}%{_initddir}
## install init scripts
install -Dpm 0755 pkg/suse/salt-master %{buildroot}%{_initddir}/salt-master
install -Dpm 0755 pkg/suse/salt-syndic %{buildroot}%{_initddir}/salt-syndic
install -Dpm 0755 pkg/suse/salt-minion %{buildroot}%{_initddir}/salt-minion
install -Dpm 0755 pkg/suse/salt-api %{buildroot}%{_initddir}/salt-api
install -Dpm 0755 pkg/old/suse/salt-master %{buildroot}%{_initddir}/salt-master
install -Dpm 0755 pkg/old/suse/salt-syndic %{buildroot}%{_initddir}/salt-syndic
install -Dpm 0755 pkg/old/suse/salt-minion %{buildroot}%{_initddir}/salt-minion
install -Dpm 0755 pkg/old/suse/salt-api %{buildroot}%{_initddir}/salt-api
ln -sf %{_initddir}/salt-master %{buildroot}%{_sbindir}/rcsalt-master
ln -sf %{_initddir}/salt-syndic %{buildroot}%{_sbindir}/rcsalt-syndic
ln -sf %{_initddir}/salt-minion %{buildroot}%{_sbindir}/rcsalt-minion
@ -894,27 +854,27 @@ install -Dpm 0640 transactional_update.conf %{buildroot}%{_sysconfdir}/salt/mini
#
## install logrotate file (for RHEL6 we use without sudo)
%if 0%{?rhel} > 6 || 0%{?suse_version}
install -Dpm 0644 pkg/suse/salt-common.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/salt
install -Dpm 0644 pkg/old/suse/salt-common.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/salt
%else
install -Dpm 0644 pkg/salt-common.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/salt
install -Dpm 0644 pkg/common/salt-common.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/salt
%endif
#
%if 0%{?suse_version} <= 1500
## install SuSEfirewall2 rules
install -Dpm 0644 pkg/suse/salt.SuSEfirewall2 %{buildroot}%{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/salt
install -Dpm 0644 pkg/old/suse/salt.SuSEfirewall2 %{buildroot}%{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/salt
%endif
#
## install completion scripts
%if %{with bash_completion}
install -Dpm 0644 pkg/salt.bash %{buildroot}%{_sysconfdir}/bash_completion.d/salt
install -Dpm 0644 pkg/common/salt.bash %{buildroot}%{_sysconfdir}/bash_completion.d/salt
%endif
%if %{with zsh_completion}
install -Dpm 0644 pkg/salt.zsh %{buildroot}%{_sysconfdir}/zsh_completion.d/salt
install -Dpm 0644 pkg/common/salt.zsh %{buildroot}%{_sysconfdir}/zsh_completion.d/salt
%endif
%if %{with fish_completion}
mkdir -p %{buildroot}%{fish_completions_dir}
install -Dpm 0644 pkg/fish-completions/* %{buildroot}%{fish_completions_dir}
install -Dpm 0644 pkg/common/fish-completions/* %{buildroot}%{fish_completions_dir}
%endif
# Standalone Salt formulas configuration

View File

@ -1,4 +1,4 @@
From af5eb3f436fa405b76851c6ba0d491559b020974 Mon Sep 17 00:00:00 2001
From 88adb2f59137213119f1da2b6dbf6fce859fc12f Mon Sep 17 00:00:00 2001
From: Vladimir Nadvornik <nadvornik@suse.cz>
Date: Mon, 27 Jun 2022 17:00:58 +0200
Subject: [PATCH] Save log to logfile with docker.build
@ -8,10 +8,10 @@ Subject: [PATCH] Save log to logfile with docker.build
1 file changed, 18 insertions(+)
diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py
index ab5c2ac609..461c89431f 100644
index 8b6ab8058e..f7344b66ac 100644
--- a/salt/modules/dockermod.py
+++ b/salt/modules/dockermod.py
@@ -4001,6 +4001,7 @@ def build(
@@ -4006,6 +4006,7 @@ def build(
fileobj=None,
dockerfile=None,
buildargs=None,
@ -19,7 +19,7 @@ index ab5c2ac609..461c89431f 100644
):
"""
.. versionchanged:: 2018.3.0
@@ -4054,6 +4055,9 @@ def build(
@@ -4059,6 +4060,9 @@ def build(
buildargs
A dictionary of build arguments provided to the docker build process.
@ -29,7 +29,7 @@ index ab5c2ac609..461c89431f 100644
**RETURN DATA**
@@ -4128,6 +4132,20 @@ def build(
@@ -4133,6 +4137,20 @@ def build(
stream_data = []
for line in response:
stream_data.extend(salt.utils.json.loads(line, cls=DockerJSONDecoder))
@ -51,6 +51,6 @@ index ab5c2ac609..461c89431f 100644
# Iterate through API response and collect information
for item in stream_data:
--
2.37.3
2.39.2

View File

@ -1,87 +0,0 @@
From d561491c48ee30472e0d4699ba389648ef0d863a Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Mon, 27 Jun 2022 18:02:31 +0300
Subject: [PATCH] Set default target for pip from VENV_PIP_TARGET
environment variable
* Use VENV_PIP_TARGET as a target for pkg.install
if set and no target specified on the call
* Add test for VENV_PIP_TARGET environment variable
* Changelog entry
---
changelog/62089.changed | 1 +
salt/modules/pip.py | 6 +++++
tests/pytests/unit/modules/test_pip.py | 31 ++++++++++++++++++++++++++
3 files changed, 38 insertions(+)
create mode 100644 changelog/62089.changed
diff --git a/changelog/62089.changed b/changelog/62089.changed
new file mode 100644
index 0000000000..09feb2e922
--- /dev/null
+++ b/changelog/62089.changed
@@ -0,0 +1 @@
+Use VENV_PIP_TARGET environment variable as a default target for pip if present.
diff --git a/salt/modules/pip.py b/salt/modules/pip.py
index da26416662..9410024fd5 100644
--- a/salt/modules/pip.py
+++ b/salt/modules/pip.py
@@ -858,6 +858,12 @@ def install(
if build:
cmd.extend(["--build", build])
+ # Use VENV_PIP_TARGET environment variable value as target
+ # if set and no target specified on the function call
+ target_env = os.environ.get("VENV_PIP_TARGET", None)
+ if target is None and target_env is not None:
+ target = target_env
+
if target:
cmd.extend(["--target", target])
diff --git a/tests/pytests/unit/modules/test_pip.py b/tests/pytests/unit/modules/test_pip.py
index 405ec6c82e..ae9005d806 100644
--- a/tests/pytests/unit/modules/test_pip.py
+++ b/tests/pytests/unit/modules/test_pip.py
@@ -1773,3 +1773,34 @@ def test_when_version_is_called_with_a_user_it_should_be_passed_to_undelying_run
cwd=None,
python_shell=False,
)
+
+
+def test_install_target_from_VENV_PIP_TARGET_in_resulting_command():
+ pkg = "pep8"
+ target = "/tmp/foo"
+ target_env = "/tmp/bar"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ environment = os.environ.copy()
+ environment["VENV_PIP_TARGET"] = target_env
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}), patch.object(
+ os, "environ", environment
+ ):
+ pip.install(pkg)
+ expected = [sys.executable, "-m", "pip", "install", "--target", target_env, pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+ mock.reset_mock()
+ pip.install(pkg, target=target)
+ expected = [sys.executable, "-m", "pip", "install", "--target", target, pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
--
2.37.3

View File

@ -1,4 +1,4 @@
From 6d122245f15a206dbfa92703b954d535c5c34dd4 Mon Sep 17 00:00:00 2001
From c61da0bef8d4d8394592db2f9995cdf4820c02af Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Mon, 27 Feb 2023 11:35:41 +0100
Subject: [PATCH] Skip package names without colon (bsc#1208691) (#578)
@ -9,10 +9,10 @@ Fixes a problem in `_find_ptf_packages()` when passing multiple packages to `zyp
1 file changed, 2 insertions(+)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index cd057ec637..64373e59fb 100644
index 44f2cdbd3a..cdec397d69 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -2758,6 +2758,8 @@ def _find_ptf_packages(pkgs, root=None):
@@ -2688,6 +2688,8 @@ def _find_ptf_packages(pkgs, root=None):
for line in output.splitlines():
if not line.strip():
continue
@ -24,3 +24,4 @@ index cd057ec637..64373e59fb 100644
--
2.39.2

View File

@ -1,362 +0,0 @@
From cba6455bd0480bfb80c466a2b34a702a9afb5bd5 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 25 Jan 2022 17:20:55 +0100
Subject: [PATCH] state.apply: don't check for cached pillar errors
state.apply request new pillar data from the server. This done to always
have the most up-to-date pillar to work with. Previously, checking for
pillar errors looked at both the new pillar and the in-memory pillar.
The latter might contain pillar rendering errors even if the former does
not.
For this reason, only the new pillar should be checked, not both.
---
changelog/52354.fixed | 1 +
changelog/57180.fixed | 1 +
changelog/59339.fixed | 1 +
salt/modules/state.py | 17 ++-
.../modules/state/test_state_pillar_errors.py | 131 ++++++++++++++++++
.../pytests/unit/modules/state/test_state.py | 115 +++++----------
6 files changed, 177 insertions(+), 89 deletions(-)
create mode 100644 changelog/52354.fixed
create mode 100644 changelog/57180.fixed
create mode 100644 changelog/59339.fixed
create mode 100644 tests/pytests/integration/modules/state/test_state_pillar_errors.py
diff --git a/changelog/52354.fixed b/changelog/52354.fixed
new file mode 100644
index 0000000000..af885d77fa
--- /dev/null
+++ b/changelog/52354.fixed
@@ -0,0 +1 @@
+Don't check for cached pillar errors on state.apply
diff --git a/changelog/57180.fixed b/changelog/57180.fixed
new file mode 100644
index 0000000000..af885d77fa
--- /dev/null
+++ b/changelog/57180.fixed
@@ -0,0 +1 @@
+Don't check for cached pillar errors on state.apply
diff --git a/changelog/59339.fixed b/changelog/59339.fixed
new file mode 100644
index 0000000000..af885d77fa
--- /dev/null
+++ b/changelog/59339.fixed
@@ -0,0 +1 @@
+Don't check for cached pillar errors on state.apply
diff --git a/salt/modules/state.py b/salt/modules/state.py
index f214291328..c0feabe842 100644
--- a/salt/modules/state.py
+++ b/salt/modules/state.py
@@ -106,18 +106,17 @@ def _set_retcode(ret, highstate=None):
def _get_pillar_errors(kwargs, pillar=None):
"""
- Checks all pillars (external and internal) for errors.
- Return an error message, if anywhere or None.
+ Check pillar for errors.
+
+ If a pillar is passed, it will be checked. Otherwise, the in-memory pillar
+ will checked instead. Passing kwargs['force'] = True short cuts the check
+ and always returns None, indicating no errors.
:param kwargs: dictionary of options
- :param pillar: external pillar
- :return: None or an error message
+ :param pillar: pillar
+ :return: None or a list of error messages
"""
- return (
- None
- if kwargs.get("force")
- else (pillar or {}).get("_errors", __pillar__.get("_errors")) or None
- )
+ return None if kwargs.get("force") else (pillar or __pillar__).get("_errors")
def _wait(jid):
diff --git a/tests/pytests/integration/modules/state/test_state_pillar_errors.py b/tests/pytests/integration/modules/state/test_state_pillar_errors.py
new file mode 100644
index 0000000000..af65a05945
--- /dev/null
+++ b/tests/pytests/integration/modules/state/test_state_pillar_errors.py
@@ -0,0 +1,131 @@
+#!/usr/bin/python3
+
+import textwrap
+
+import pytest
+from saltfactories.utils.functional import StateResult
+
+pytestmark = [
+ pytest.mark.slow_test,
+]
+
+
+@pytest.fixture(scope="module")
+def reset_pillar(salt_call_cli):
+ try:
+ # Run tests
+ yield
+ finally:
+ # Refresh pillar once all tests are done.
+ ret = salt_call_cli.run("saltutil.refresh_pillar", wait=True)
+ assert ret.exitcode == 0
+ assert ret.json is True
+
+
+@pytest.fixture
+def testfile_path(tmp_path, base_env_state_tree_root_dir):
+ testfile = tmp_path / "testfile"
+ sls_contents = textwrap.dedent(
+ """
+ {}:
+ file:
+ - managed
+ - source: salt://testfile
+ - makedirs: true
+ """.format(testfile)
+ )
+ with pytest.helpers.temp_file(
+ "sls-id-test.sls", sls_contents, base_env_state_tree_root_dir
+ ):
+ yield testfile
+
+
+@pytest.mark.usefixtures("testfile_path", "reset_pillar")
+def test_state_apply_aborts_on_pillar_error(
+ salt_cli,
+ salt_minion,
+ base_env_pillar_tree_root_dir,
+):
+ """
+ Test state.apply with error in pillar.
+ """
+ pillar_top_file = textwrap.dedent(
+ """
+ base:
+ '{}':
+ - basic
+ """
+ ).format(salt_minion.id)
+ basic_pillar_file = textwrap.dedent(
+ """
+ syntax_error
+ """
+ )
+
+ with pytest.helpers.temp_file(
+ "top.sls", pillar_top_file, base_env_pillar_tree_root_dir
+ ), pytest.helpers.temp_file(
+ "basic.sls", basic_pillar_file, base_env_pillar_tree_root_dir
+ ):
+ expected_comment = [
+ "Pillar failed to render with the following messages:",
+ "SLS 'basic' does not render to a dictionary",
+ ]
+ shell_result = salt_cli.run(
+ "state.apply", "sls-id-test", minion_tgt=salt_minion.id
+ )
+ assert shell_result.exitcode == 1
+ assert shell_result.json == expected_comment
+
+
+@pytest.mark.usefixtures("testfile_path", "reset_pillar")
+def test_state_apply_continues_after_pillar_error_is_fixed(
+ salt_cli,
+ salt_minion,
+ base_env_pillar_tree_root_dir,
+):
+ """
+ Test state.apply with error in pillar.
+ """
+ pillar_top_file = textwrap.dedent(
+ """
+ base:
+ '{}':
+ - basic
+ """.format(salt_minion.id)
+ )
+ basic_pillar_file_error = textwrap.dedent(
+ """
+ syntax_error
+ """
+ )
+ basic_pillar_file = textwrap.dedent(
+ """
+ syntax_error: Fixed!
+ """
+ )
+
+ # save pillar render error in minion's in-memory pillar
+ with pytest.helpers.temp_file(
+ "top.sls", pillar_top_file, base_env_pillar_tree_root_dir
+ ), pytest.helpers.temp_file(
+ "basic.sls", basic_pillar_file_error, base_env_pillar_tree_root_dir
+ ):
+ shell_result = salt_cli.run(
+ "saltutil.refresh_pillar", minion_tgt=salt_minion.id
+ )
+ assert shell_result.exitcode == 0
+
+ # run state.apply with fixed pillar render error
+ with pytest.helpers.temp_file(
+ "top.sls", pillar_top_file, base_env_pillar_tree_root_dir
+ ), pytest.helpers.temp_file(
+ "basic.sls", basic_pillar_file, base_env_pillar_tree_root_dir
+ ):
+ shell_result = salt_cli.run(
+ "state.apply", "sls-id-test", minion_tgt=salt_minion.id
+ )
+ assert shell_result.exitcode == 0
+ state_result = StateResult(shell_result.json)
+ assert state_result.result is True
+ assert state_result.changes == {"diff": "New file", "mode": "0644"}
diff --git a/tests/pytests/unit/modules/state/test_state.py b/tests/pytests/unit/modules/state/test_state.py
index 02fd2dd307..30cda303cc 100644
--- a/tests/pytests/unit/modules/state/test_state.py
+++ b/tests/pytests/unit/modules/state/test_state.py
@@ -1,14 +1,16 @@
"""
:codeauthor: Rahul Handay <rahulha@saltstack.com>
"""
-
import datetime
import logging
import os
+from collections import namedtuple
import pytest
+
import salt.config
import salt.loader
+import salt.loader.context
import salt.modules.config as config
import salt.modules.state as state
import salt.state
@@ -1200,85 +1202,6 @@ def test_lock_saltenv():
)
-def test_get_pillar_errors_CC():
- """
- Test _get_pillar_errors function.
- CC: External clean, Internal clean
- :return:
- """
- for int_pillar, ext_pillar in [
- ({"foo": "bar"}, {"fred": "baz"}),
- ({"foo": "bar"}, None),
- ({}, {"fred": "baz"}),
- ]:
- with patch("salt.modules.state.__pillar__", int_pillar):
- for opts, res in [
- ({"force": True}, None),
- ({"force": False}, None),
- ({}, None),
- ]:
- assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar)
-
-
-def test_get_pillar_errors_EC():
- """
- Test _get_pillar_errors function.
- EC: External erroneous, Internal clean
- :return:
- """
- errors = ["failure", "everywhere"]
- for int_pillar, ext_pillar in [
- ({"foo": "bar"}, {"fred": "baz", "_errors": errors}),
- ({}, {"fred": "baz", "_errors": errors}),
- ]:
- with patch("salt.modules.state.__pillar__", int_pillar):
- for opts, res in [
- ({"force": True}, None),
- ({"force": False}, errors),
- ({}, errors),
- ]:
- assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar)
-
-
-def test_get_pillar_errors_EE():
- """
- Test _get_pillar_errors function.
- CC: External erroneous, Internal erroneous
- :return:
- """
- errors = ["failure", "everywhere"]
- for int_pillar, ext_pillar in [
- ({"foo": "bar", "_errors": errors}, {"fred": "baz", "_errors": errors})
- ]:
- with patch("salt.modules.state.__pillar__", int_pillar):
- for opts, res in [
- ({"force": True}, None),
- ({"force": False}, errors),
- ({}, errors),
- ]:
- assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar)
-
-
-def test_get_pillar_errors_CE():
- """
- Test _get_pillar_errors function.
- CC: External clean, Internal erroneous
- :return:
- """
- errors = ["failure", "everywhere"]
- for int_pillar, ext_pillar in [
- ({"foo": "bar", "_errors": errors}, {"fred": "baz"}),
- ({"foo": "bar", "_errors": errors}, None),
- ]:
- with patch("salt.modules.state.__pillar__", int_pillar):
- for opts, res in [
- ({"force": True}, None),
- ({"force": False}, errors),
- ({}, errors),
- ]:
- assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar)
-
-
def test_event():
"""
test state.event runner
@@ -1318,3 +1241,35 @@ def test_event():
if _expected in x.args[0]:
found = True
assert found is True
+
+
+PillarPair = namedtuple("PillarPair", ["in_memory", "fresh"])
+pillar_combinations = [
+ (PillarPair({"foo": "bar"}, {"fred": "baz"}), None),
+ (PillarPair({"foo": "bar"}, {"fred": "baz", "_errors": ["Failure"]}), ["Failure"]),
+ (PillarPair({"foo": "bar"}, None), None),
+ (PillarPair({"foo": "bar", "_errors": ["Failure"]}, None), ["Failure"]),
+ (PillarPair({"foo": "bar", "_errors": ["Failure"]}, {"fred": "baz"}), None),
+]
+
+
+@pytest.mark.parametrize("pillar,expected_errors", pillar_combinations)
+def test_get_pillar_errors(pillar: PillarPair, expected_errors):
+ """
+ test _get_pillar_errors function
+
+ There are three cases to consider:
+ 1. kwargs['force'] is True -> None, no matter what's in pillar/__pillar__
+ 2. pillar kwarg is available -> only check pillar, no matter what's in __pillar__
+ 3. pillar kwarg is not available -> check __pillar__
+ """
+ ctx = salt.loader.context.LoaderContext()
+ named_ctx = ctx.named_context("__pillar__", pillar.in_memory)
+ with patch("salt.modules.state.__pillar__", named_ctx, create=True):
+ assert (
+ state._get_pillar_errors(kwargs={"force": True}, pillar=pillar.fresh)
+ is None
+ )
+ assert (
+ state._get_pillar_errors(kwargs={}, pillar=pillar.fresh) == expected_errors
+ )
--
2.37.3

View File

@ -1,105 +0,0 @@
From 634e82874b17c38bd4d27c0c07a53c9e39e49968 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Wed, 9 Feb 2022 09:01:08 +0000
Subject: [PATCH] state.orchestrate_single does not pass pillar=None
(#488)
Passing a pillar to state.single can results in state functions not
working when they don't accept a pillar keyword argument. One example
where this is the case is salt.wait_for_event. When no pillar is
provided, it does not need to be passed.
Co-authored-by: Alexander Graul <agraul@suse.com>
---
changelog/61092.fixed | 3 ++
salt/runners/state.py | 10 ++++--
tests/pytests/unit/runners/test_state.py | 41 ++++++++++++++++++++++++
3 files changed, 51 insertions(+), 3 deletions(-)
create mode 100644 changelog/61092.fixed
create mode 100644 tests/pytests/unit/runners/test_state.py
diff --git a/changelog/61092.fixed b/changelog/61092.fixed
new file mode 100644
index 0000000000..6ca66839c9
--- /dev/null
+++ b/changelog/61092.fixed
@@ -0,0 +1,3 @@
+state.orchestrate_single only passes a pillar if it is set to the state
+function. This allows it to be used with state functions that don't accept a
+pillar keyword argument.
diff --git a/salt/runners/state.py b/salt/runners/state.py
index f8fc1b0944..5642204ce9 100644
--- a/salt/runners/state.py
+++ b/salt/runners/state.py
@@ -150,12 +150,16 @@ def orchestrate_single(fun, name, test=None, queue=False, pillar=None, **kwargs)
salt-run state.orchestrate_single fun=salt.wheel name=key.list_all
"""
- if pillar is not None and not isinstance(pillar, dict):
- raise SaltInvocationError("Pillar data must be formatted as a dictionary")
+ if pillar is not None:
+ if isinstance(pillar, dict):
+ kwargs["pillar"] = pillar
+ else:
+ raise SaltInvocationError("Pillar data must be formatted as a dictionary")
+
__opts__["file_client"] = "local"
minion = salt.minion.MasterMinion(__opts__)
running = minion.functions["state.single"](
- fun, name, test=None, queue=False, pillar=pillar, **kwargs
+ fun, name, test=None, queue=False, **kwargs
)
ret = {minion.opts["id"]: running}
__jid_event__.fire_event({"data": ret, "outputter": "highstate"}, "progress")
diff --git a/tests/pytests/unit/runners/test_state.py b/tests/pytests/unit/runners/test_state.py
new file mode 100644
index 0000000000..df0a718a41
--- /dev/null
+++ b/tests/pytests/unit/runners/test_state.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python3
+
+import pytest
+from salt.runners import state as state_runner
+from tests.support.mock import Mock, patch
+
+
+@pytest.fixture
+def configure_loader_modules():
+ return {state_runner: {"__opts__": {}, "__jid_event__": Mock()}}
+
+
+def test_orchestrate_single_passes_pillar():
+ """
+ test state.orchestrate_single passes given pillar to state.single
+ """
+ mock_master_minion = Mock()
+ mock_state_single = Mock()
+ mock_master_minion.functions = {"state.single": mock_state_single}
+ mock_master_minion.opts = {"id": "dummy"}
+ test_pillar = {"test_entry": "exists"}
+ with patch("salt.minion.MasterMinion", Mock(return_value=mock_master_minion)):
+ state_runner.orchestrate_single(
+ fun="pillar.get", name="test_entry", pillar=test_pillar
+ )
+ assert mock_state_single.call_args.kwargs["pillar"] == test_pillar
+
+
+def test_orchestrate_single_does_not_pass_none_pillar():
+ """
+ test state.orchestrate_single does not pass pillar=None to state.single
+ """
+ mock_master_minion = Mock()
+ mock_state_single = Mock()
+ mock_master_minion.functions = {"state.single": mock_state_single}
+ mock_master_minion.opts = {"id": "dummy"}
+ with patch("salt.minion.MasterMinion", Mock(return_value=mock_master_minion)):
+ state_runner.orchestrate_single(
+ fun="pillar.get", name="test_entry", pillar=None
+ )
+ assert "pillar" not in mock_state_single.call_args.kwargs
--
2.37.3

View File

@ -1,4 +1,4 @@
From 995f67741e591b60fcecff87d4d97099ca82bafc Mon Sep 17 00:00:00 2001
From 57626d8eb77d2c559365d1df974100e474671fef Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 17:12:04 +0100
Subject: [PATCH] Switch firewalld state to use change_interface
@ -67,6 +67,6 @@ index cc6eaba5c3..534b9dd62d 100644
ret["comment"] = "Error: {}".format(err)
return ret
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From e4374250234ab74bce0ef86d95cb30e873f0af3c Mon Sep 17 00:00:00 2001
From 2575e64ee21f774a1efb6960972e9d476a8d5927 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Thu, 24 Jan 2019 18:12:35 +0100
Subject: [PATCH] temporary fix: extend the whitelist of allowed commands
@ -8,7 +8,7 @@ Subject: [PATCH] temporary fix: extend the whitelist of allowed commands
1 file changed, 3 insertions(+)
diff --git a/salt/auth/__init__.py b/salt/auth/__init__.py
index afd7ad65fa..0c64755235 100644
index b87e2aff0d..331baab211 100644
--- a/salt/auth/__init__.py
+++ b/salt/auth/__init__.py
@@ -12,6 +12,7 @@ so that any external authentication system can be used inside of Salt
@ -29,6 +29,6 @@ index afd7ad65fa..0c64755235 100644
"print_event",
"raw",
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 9e527322ee0f5c7e1f9b7c16f14be9c349cf8e55 Mon Sep 17 00:00:00 2001
From b6bf7e1cb3efedbb651b7d6c5f36b73d88cfa1c0 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
Date: Fri, 9 Apr 2021 16:01:32 +0300
Subject: [PATCH] Update target fix for salt-ssh to process targets list
@ -14,7 +14,7 @@ Regression fix of salt-ssh on processing targets (#353)
1 file changed, 29 insertions(+), 17 deletions(-)
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index ef162d2270..ad2796bc87 100644
index 049baff51a..19089ce8ad 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -338,7 +338,7 @@ class SSH(MultiprocessingStateMixin):
@ -93,6 +93,6 @@ index ef162d2270..ad2796bc87 100644
def get_pubkey(self):
"""
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From a2f8b54cd56eb83552eccf87afd9b67f6a4a6f4c Mon Sep 17 00:00:00 2001
From ef6da7d43fcf51a7d705422624c1e7a94b1297f2 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 16:36:57 +0100
Subject: [PATCH] Use Adler32 algorithm to compute string checksums
@ -24,21 +24,21 @@ Remove deprecated warning that breaks miniion execution when "server_id_use_crc"
2 files changed, 48 insertions(+), 4 deletions(-)
diff --git a/salt/config/__init__.py b/salt/config/__init__.py
index a37f7eebcc..7cdee12c4d 100644
index 1632663474..43182f3f92 100644
--- a/salt/config/__init__.py
+++ b/salt/config/__init__.py
@@ -964,6 +964,9 @@ VALID_OPTS = immutabletypes.freeze(
# The port to be used when checking if a master is connected to a
# minion
"remote_minions_port": int,
@@ -991,6 +991,9 @@ VALID_OPTS = immutabletypes.freeze(
"maintenance_interval": int,
# Fileserver process restart interval
"fileserver_interval": int,
+ # Use Adler32 hashing algorithm for server_id (default False until Sodium, "adler32" after)
+ # Possible values are: False, adler32, crc32
+ "server_id_use_crc": (bool, str),
}
)
@@ -1267,6 +1270,7 @@ DEFAULT_MINION_OPTS = immutabletypes.freeze(
"disabled_requisites": [],
@@ -1296,6 +1299,7 @@ DEFAULT_MINION_OPTS = immutabletypes.freeze(
"global_state_conditions": None,
"reactor_niceness": None,
"fips_mode": False,
+ "server_id_use_crc": False,
@ -46,7 +46,7 @@ index a37f7eebcc..7cdee12c4d 100644
)
diff --git a/salt/grains/core.py b/salt/grains/core.py
index b55ab4e472..23d8b8ea42 100644
index 1199ad274f..5c12556346 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -21,6 +21,7 @@ import subprocess
@ -56,8 +56,8 @@ index b55ab4e472..23d8b8ea42 100644
+import zlib
from errno import EACCES, EPERM
import distro
@@ -3015,6 +3016,36 @@ def _hw_data(osdata):
import salt.exceptions
@@ -3382,6 +3383,36 @@ def _hw_data(osdata):
return grains
@ -94,14 +94,14 @@ index b55ab4e472..23d8b8ea42 100644
def get_server_id():
"""
Provides an integer based on the FQDN of a machine.
@@ -3025,10 +3056,19 @@ def get_server_id():
@@ -3392,10 +3423,19 @@ def get_server_id():
# server_id
if salt.utils.platform.is_proxy():
- return {}
- id_ = __opts__.get("id", "")
- hash_ = int(hashlib.sha256(id_.encode()).hexdigest(), 16)
- return {"server_id": abs(hash_ % (2 ** 31))}
- return {"server_id": abs(hash_ % (2**31))}
+ server_id = {}
+ else:
+ use_crc = __opts__.get("server_id_use_crc")
@ -119,6 +119,6 @@ index b55ab4e472..23d8b8ea42 100644
def get_master():
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From c6be36eeea49ee0d0641da272087305f79c32c99 Mon Sep 17 00:00:00 2001
From 578932e56be4b4151aa33bd25997c916b0e00a04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Wed, 4 Jan 2023 13:11:50 +0000
@ -22,6 +22,6 @@ index bbe4269839..b41cc64b8e 100644
def LazyLoader(*args, **kwargs):
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From cd03f33b3ba1ebf267825d29b68d4e88e6a0021a Mon Sep 17 00:00:00 2001
From b0891f83afa354c4b1f803af8a679ecf5a7fb63c Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Mon, 27 Jun 2022 17:59:24 +0300
Subject: [PATCH] Use Salt Bundle in dockermod
@ -12,7 +12,7 @@ Subject: [PATCH] Use Salt Bundle in dockermod
2 files changed, 241 insertions(+), 34 deletions(-)
diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py
index d8581586ca..ab5c2ac609 100644
index 6870c26b0e..8b6ab8058e 100644
--- a/salt/modules/dockermod.py
+++ b/salt/modules/dockermod.py
@@ -201,14 +201,19 @@ import copy
@ -35,7 +35,7 @@ index d8581586ca..ab5c2ac609 100644
import time
import uuid
@@ -6693,6 +6698,111 @@ def _compile_state(sls_opts, mods=None):
@@ -6698,6 +6703,111 @@ def _compile_state(sls_opts, mods=None):
return st_.state.compile_high_data(high_data)
@ -147,7 +147,7 @@ index d8581586ca..ab5c2ac609 100644
def call(name, function, *args, **kwargs):
"""
Executes a Salt function inside a running container
@@ -6728,47 +6838,68 @@ def call(name, function, *args, **kwargs):
@@ -6733,47 +6843,68 @@ def call(name, function, *args, **kwargs):
if function is None:
raise CommandExecutionError("Missing function parameter")
@ -250,7 +250,7 @@ index d8581586ca..ab5c2ac609 100644
"--local",
"--log-file",
diff --git a/tests/pytests/unit/modules/dockermod/test_module.py b/tests/pytests/unit/modules/dockermod/test_module.py
index 47fe5d55e6..19c7f450d7 100644
index 8fb7806497..1ac7dff52a 100644
--- a/tests/pytests/unit/modules/dockermod/test_module.py
+++ b/tests/pytests/unit/modules/dockermod/test_module.py
@@ -3,6 +3,7 @@ Unit tests for the docker module
@ -260,8 +260,8 @@ index 47fe5d55e6..19c7f450d7 100644
+import sys
import pytest
import salt.config
@@ -26,6 +27,7 @@ def configure_loader_modules():
@@ -26,6 +27,7 @@ def configure_loader_modules(minion_opts):
whitelist=[
"args",
"docker",
@ -370,6 +370,6 @@ index 47fe5d55e6..19c7f450d7 100644
+
+ assert {"retcode": 0, "comment": "container cmd"} == ret
--
2.37.3
2.39.2

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:344032370bda5edd6242732587111b0a2fee378fcda2d9a1cfff7e191f9ac89e
size 18016427

BIN
v3006.0.tar.gz (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -1,4 +1,4 @@
From 1b78ceabaf3885e7d90d13a041685e7dda960ac9 Mon Sep 17 00:00:00 2001
From 094b34760a85c3ee27bf64783624b17bd3bbca0a Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 16:38:17 +0100
Subject: [PATCH] X509 fixes (#111)
@ -41,10 +41,10 @@ We are logging in debug and not in trace mode here.
salt/modules/x509.py | 93 ++++++++++++++++-----------------
salt/states/x509.py | 74 ++++++++++++++++++++++++--
tests/unit/modules/test_x509.py | 6 +--
4 files changed, 121 insertions(+), 54 deletions(-)
4 files changed, 120 insertions(+), 55 deletions(-)
diff --git a/salt/modules/publish.py b/salt/modules/publish.py
index c2dd62b913..45ee41ef19 100644
index cc424cc383..a82cb3ac98 100644
--- a/salt/modules/publish.py
+++ b/salt/modules/publish.py
@@ -199,6 +199,8 @@ def _publish(
@ -57,10 +57,10 @@ index c2dd62b913..45ee41ef19 100644
def publish(
tgt, fun, arg=None, tgt_type="glob", returner="", timeout=5, via_master=None
diff --git a/salt/modules/x509.py b/salt/modules/x509.py
index 2f9cc5cc44..194116a85c 100644
index 57c381ea38..6699a5d363 100644
--- a/salt/modules/x509.py
+++ b/salt/modules/x509.py
@@ -30,16 +30,13 @@ from salt.utils.odict import OrderedDict
@@ -42,16 +42,13 @@ from salt.utils.odict import OrderedDict
try:
import M2Crypto
@ -80,11 +80,16 @@ index 2f9cc5cc44..194116a85c 100644
__virtualname__ = "x509"
@@ -79,10 +76,10 @@ def __virtual__():
"""
only load this module if m2crypto is available
"""
@@ -94,15 +91,10 @@ def __virtual__():
# salt.features appears to not be setup when invoked via peer publishing
if __opts__.get("features", {}).get("x509_v2"):
return (False, "Superseded, using x509_v2")
- if HAS_M2:
- salt.utils.versions.warn_until(
- "Potassium",
- "The x509 modules are deprecated. Please migrate to the replacement "
- "modules (x509_v2). They are the default from Salt 3008 (Argon) onwards.",
- )
- return __virtualname__
- else:
- return (False, "Could not load x509 module, m2crypto unavailable")
@ -95,7 +100,7 @@ index 2f9cc5cc44..194116a85c 100644
class _Ctx(ctypes.Structure):
@@ -140,8 +137,8 @@ def _new_extension(name, value, critical=0, issuer=None, _pyfree=1):
@@ -160,8 +152,8 @@ def _new_extension(name, value, critical=0, issuer=None, _pyfree=1):
x509_ext_ptr = M2Crypto.m2.x509v3_ext_conf(None, ctx, name, value)
lhash = None
except AttributeError:
@ -106,7 +111,7 @@ index 2f9cc5cc44..194116a85c 100644
# ctx not zeroed
_fix_ctx(ctx, issuer)
x509_ext_ptr = M2Crypto.m2.x509v3_ext_conf(lhash, ctx, name, value)
@@ -280,7 +277,7 @@ def _get_signing_policy(name):
@@ -300,7 +292,7 @@ def _get_signing_policy(name):
signing_policy = policies.get(name)
if signing_policy:
return signing_policy
@ -115,7 +120,7 @@ index 2f9cc5cc44..194116a85c 100644
def _pretty_hex(hex_str):
@@ -318,9 +315,11 @@ def _text_or_file(input_):
@@ -338,9 +330,11 @@ def _text_or_file(input_):
"""
if _isfile(input_):
with salt.utils.files.fopen(input_) as fp_:
@ -129,7 +134,7 @@ index 2f9cc5cc44..194116a85c 100644
def _parse_subject(subject):
@@ -339,7 +338,7 @@ def _parse_subject(subject):
@@ -359,7 +353,7 @@ def _parse_subject(subject):
ret_list.append((nid_num, nid_name, val))
nids.append(nid_num)
except TypeError as err:
@ -138,7 +143,7 @@ index 2f9cc5cc44..194116a85c 100644
for nid_num, nid_name, val in sorted(ret_list):
ret[nid_name] = val
return ret
@@ -537,8 +536,8 @@ def get_pem_entries(glob_path):
@@ -557,8 +551,8 @@ def get_pem_entries(glob_path):
if os.path.isfile(path):
try:
ret[path] = get_pem_entry(text=path)
@ -149,7 +154,7 @@ index 2f9cc5cc44..194116a85c 100644
return ret
@@ -616,8 +615,8 @@ def read_certificates(glob_path):
@@ -636,8 +630,8 @@ def read_certificates(glob_path):
if os.path.isfile(path):
try:
ret[path] = read_certificate(certificate=path)
@ -160,7 +165,7 @@ index 2f9cc5cc44..194116a85c 100644
return ret
@@ -647,10 +646,9 @@ def read_csr(csr):
@@ -667,10 +661,9 @@ def read_csr(csr):
"Subject": _parse_subject(csr.get_subject()),
"Subject Hash": _dec2hex(csr.get_subject().as_hash()),
"Public Key Hash": hashlib.sha1(csr.get_pubkey().get_modulus()).hexdigest(),
@ -172,7 +177,7 @@ index 2f9cc5cc44..194116a85c 100644
return ret
@@ -960,7 +958,7 @@ def create_crl(
@@ -980,7 +973,7 @@ def create_crl(
# pyOpenSSL Note due to current limitations in pyOpenSSL it is impossible
# to specify a digest For signing the CRL. This will hopefully be fixed
# soon: https://github.com/pyca/pyopenssl/pull/161
@ -181,7 +186,7 @@ index 2f9cc5cc44..194116a85c 100644
raise salt.exceptions.SaltInvocationError(
"Could not load OpenSSL module, OpenSSL unavailable"
)
@@ -1111,6 +1109,7 @@ def get_signing_policy(signing_policy_name):
@@ -1131,6 +1124,7 @@ def get_signing_policy(signing_policy_name):
signing_policy = _get_signing_policy(signing_policy_name)
if not signing_policy:
return "Signing policy {} does not exist.".format(signing_policy_name)
@ -189,7 +194,7 @@ index 2f9cc5cc44..194116a85c 100644
if isinstance(signing_policy, list):
dict_ = {}
for item in signing_policy:
@@ -1127,7 +1126,7 @@ def get_signing_policy(signing_policy_name):
@@ -1147,7 +1141,7 @@ def get_signing_policy(signing_policy_name):
signing_policy["signing_cert"], "CERTIFICATE"
)
except KeyError:
@ -198,7 +203,7 @@ index 2f9cc5cc44..194116a85c 100644
return signing_policy
@@ -1762,7 +1761,8 @@ def create_csr(path=None, text=False, **kwargs):
@@ -1782,7 +1776,8 @@ def create_csr(path=None, text=False, **kwargs):
)
)
@ -208,7 +213,7 @@ index 2f9cc5cc44..194116a85c 100644
if entry in kwargs:
setattr(subject, entry, kwargs[entry])
@@ -1798,7 +1798,6 @@ def create_csr(path=None, text=False, **kwargs):
@@ -1818,7 +1813,6 @@ def create_csr(path=None, text=False, **kwargs):
extstack.push(ext)
csr.add_extensions(extstack)
@ -216,7 +221,7 @@ index 2f9cc5cc44..194116a85c 100644
csr.sign(
_get_private_key_obj(
kwargs["private_key"], passphrase=kwargs["private_key_passphrase"]
@@ -1806,10 +1805,11 @@ def create_csr(path=None, text=False, **kwargs):
@@ -1826,10 +1820,11 @@ def create_csr(path=None, text=False, **kwargs):
kwargs["algorithm"],
)
@ -232,7 +237,7 @@ index 2f9cc5cc44..194116a85c 100644
def verify_private_key(private_key, public_key, passphrase=None):
@@ -1834,7 +1834,7 @@ def verify_private_key(private_key, public_key, passphrase=None):
@@ -1854,7 +1849,7 @@ def verify_private_key(private_key, public_key, passphrase=None):
salt '*' x509.verify_private_key private_key=/etc/pki/myca.key \\
public_key=/etc/pki/myca.crt
"""
@ -241,7 +246,7 @@ index 2f9cc5cc44..194116a85c 100644
def verify_signature(
@@ -1890,7 +1890,10 @@ def verify_crl(crl, cert):
@@ -1910,7 +1905,10 @@ def verify_crl(crl, cert):
salt '*' x509.verify_crl crl=/etc/pki/myca.crl cert=/etc/pki/myca.crt
"""
if not salt.utils.path.which("openssl"):
@ -253,19 +258,7 @@ index 2f9cc5cc44..194116a85c 100644
crltext = _text_or_file(crl)
crltext = get_pem_entry(crltext, pem_type="X509 CRL")
crltempfile = tempfile.NamedTemporaryFile(delete=True)
@@ -1912,10 +1915,7 @@ def verify_crl(crl, cert):
crltempfile.close()
certtempfile.close()
- if "verify OK" in output:
- return True
- else:
- return False
+ return "verify OK" in output
def expired(certificate):
@@ -1953,8 +1953,9 @@ def expired(certificate):
@@ -1970,8 +1968,9 @@ def expired(certificate):
ret["expired"] = True
else:
ret["expired"] = False
@ -277,7 +270,7 @@ index 2f9cc5cc44..194116a85c 100644
return ret
@@ -1977,6 +1978,7 @@ def will_expire(certificate, days):
@@ -1994,6 +1993,7 @@ def will_expire(certificate, days):
salt '*' x509.will_expire "/etc/pki/mycert.crt" days=30
"""
@ -285,7 +278,7 @@ index 2f9cc5cc44..194116a85c 100644
ret = {}
if os.path.isfile(certificate):
@@ -1990,14 +1992,11 @@ def will_expire(certificate, days):
@@ -2007,14 +2007,11 @@ def will_expire(certificate, days):
_expiration_date = cert.get_not_after().get_datetime()
ret["cn"] = _parse_subject(cert.get_subject())["CN"]
@ -307,13 +300,13 @@ index 2f9cc5cc44..194116a85c 100644
return ret
diff --git a/salt/states/x509.py b/salt/states/x509.py
index b3d2f978bd..16811bcfb8 100644
index aebbc4cc82..f9cbec87f9 100644
--- a/salt/states/x509.py
+++ b/salt/states/x509.py
@@ -177,11 +177,12 @@ import os
import re
@@ -192,11 +192,12 @@ import re
import salt.exceptions
import salt.utils.versions
from salt.features import features
+import salt.utils.stringutils
try:
@ -324,8 +317,8 @@ index b3d2f978bd..16811bcfb8 100644
log = logging.getLogger(__name__)
@@ -193,7 +194,7 @@ def __virtual__():
if "x509.get_pem_entry" in __salt__:
@@ -215,7 +216,7 @@ def __virtual__():
)
return "x509"
else:
- return (False, "Could not load x509 state: m2crypto unavailable")
@ -333,7 +326,7 @@ index b3d2f978bd..16811bcfb8 100644
def _revoked_to_list(revs):
@@ -682,7 +683,70 @@ def certificate_managed(name, days_remaining=90, append_certs=None, **kwargs):
@@ -704,7 +705,70 @@ def certificate_managed(name, days_remaining=90, append_certs=None, **kwargs):
"Old": invalid_reason,
"New": "Certificate will be valid and up to date",
}
@ -405,7 +398,7 @@ index b3d2f978bd..16811bcfb8 100644
contents = __salt__["x509.create_certificate"](text=True, **kwargs)
# Check the module actually returned a cert and not an error message as a string
@@ -878,6 +942,8 @@ def pem_managed(name, text, backup=False, **kwargs):
@@ -900,6 +964,8 @@ def pem_managed(name, text, backup=False, **kwargs):
Any arguments supported by :py:func:`file.managed <salt.states.file.managed>` are supported.
"""
file_args, kwargs = _get_file_args(name, **kwargs)
@ -416,10 +409,10 @@ index b3d2f978bd..16811bcfb8 100644
return __states__["file.managed"](**file_args)
diff --git a/tests/unit/modules/test_x509.py b/tests/unit/modules/test_x509.py
index 8f4c433b1a..3105290a2c 100644
index f1ca5bb45a..a5c44f0ed2 100644
--- a/tests/unit/modules/test_x509.py
+++ b/tests/unit/modules/test_x509.py
@@ -118,9 +118,9 @@ class X509TestCase(TestCase, LoaderModuleMockMixin):
@@ -119,9 +119,9 @@ class X509TestCase(TestCase, LoaderModuleMockMixin):
subj = FakeSubject()
x509._parse_subject(subj)
@ -430,9 +423,9 @@ index 8f4c433b1a..3105290a2c 100644
+ assert x509.log.debug.call_args[0][1] == list(subj.nid.keys())[0]
+ assert isinstance(x509.log.debug.call_args[0][2], TypeError)
@skipIf(not HAS_M2CRYPTO, "Skipping, M2Crypto is unavailable")
def test_get_pem_entry(self):
@pytest.mark.skipif(
not HAS_M2CRYPTO, reason="Skipping, reason=M2Crypto is unavailable"
--
2.37.3
2.39.2

View File

@ -1,4 +1,4 @@
From 41e53ad0b03511d65c5d7e6a12e7c460d83b6737 Mon Sep 17 00:00:00 2001
From deaee93b2f83f1524ec136afc1a5198b33d293d2 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Mon, 5 Oct 2020 16:24:16 +0200
Subject: [PATCH] zypperpkg: ignore retcode 104 for search()
@ -6,14 +6,14 @@ Subject: [PATCH] zypperpkg: ignore retcode 104 for search()
---
salt/modules/zypperpkg.py | 28 ++++++---
tests/unit/modules/test_zypperpkg.py | 89 +++++++++++++++++++++-------
2 files changed, 90 insertions(+), 27 deletions(-)
tests/unit/modules/test_zypperpkg.py | 87 ++++++++++++++++++++++------
2 files changed, 89 insertions(+), 26 deletions(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index 32e22ce9a8..6b19c65db3 100644
index d8220a1fdd..4bb10f445a 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -99,6 +99,8 @@ class _Zypper:
@@ -103,6 +103,8 @@ class _Zypper:
}
LOCK_EXIT_CODE = 7
@ -22,7 +22,7 @@ index 32e22ce9a8..6b19c65db3 100644
XML_DIRECTIVES = ["-x", "--xmlout"]
# ZYPPER_LOCK is not affected by --root
ZYPPER_LOCK = "/var/run/zypp.pid"
@@ -129,6 +131,7 @@ class _Zypper:
@@ -134,6 +136,7 @@ class _Zypper:
self.__no_raise = False
self.__refresh = False
self.__ignore_repo_failure = False
@ -30,7 +30,7 @@ index 32e22ce9a8..6b19c65db3 100644
self.__systemd_scope = False
self.__root = None
@@ -148,6 +151,9 @@ class _Zypper:
@@ -153,6 +156,9 @@ class _Zypper:
# Ignore exit code for 106 (repo is not available)
if "no_repo_failure" in kwargs:
self.__ignore_repo_failure = kwargs["no_repo_failure"]
@ -40,7 +40,7 @@ index 32e22ce9a8..6b19c65db3 100644
if "systemd_scope" in kwargs:
self.__systemd_scope = kwargs["systemd_scope"]
if "root" in kwargs:
@@ -306,6 +312,10 @@ class _Zypper:
@@ -333,6 +339,10 @@ class _Zypper:
if self.__root:
self.__cmd.extend(["--root", self.__root])
@ -51,7 +51,7 @@ index 32e22ce9a8..6b19c65db3 100644
self.__cmd.extend(args)
kwargs["output_loglevel"] = "trace"
kwargs["python_shell"] = False
@@ -445,9 +455,11 @@ class Wildcard:
@@ -479,9 +489,11 @@ class Wildcard:
Get available versions of the package.
:return:
"""
@ -66,7 +66,7 @@ index 32e22ce9a8..6b19c65db3 100644
if not solvables:
raise CommandExecutionError(
"No packages found matching '{}'".format(self.name)
@@ -1052,7 +1064,7 @@ def list_repo_pkgs(*args, **kwargs):
@@ -1086,7 +1098,7 @@ def list_repo_pkgs(*args, **kwargs):
root = kwargs.get("root") or None
for node in (
@ -75,7 +75,7 @@ index 32e22ce9a8..6b19c65db3 100644
.xml.call("se", "-s", *targets)
.getElementsByTagName("solvable")
):
@@ -2439,7 +2451,9 @@ def owner(*paths, **kwargs):
@@ -2556,7 +2568,9 @@ def owner(*paths, **kwargs):
def _get_visible_patterns(root=None):
"""Get all available patterns in the repo that are visible."""
patterns = {}
@ -86,7 +86,7 @@ index 32e22ce9a8..6b19c65db3 100644
for element in search_patterns.getElementsByTagName("solvable"):
installed = element.getAttribute("status") == "installed"
patterns[element.getAttribute("name")] = {
@@ -2636,7 +2650,7 @@ def search(criteria, refresh=False, **kwargs):
@@ -2753,7 +2767,7 @@ def search(criteria, refresh=False, **kwargs):
cmd.append(criteria)
solvables = (
@ -95,7 +95,7 @@ index 32e22ce9a8..6b19c65db3 100644
.nolock.noraise.xml.call(*cmd)
.getElementsByTagName("solvable")
)
@@ -2888,7 +2902,7 @@ def _get_patches(installed_only=False, root=None):
@@ -3005,7 +3019,7 @@ def _get_patches(installed_only=False, root=None):
"""
patches = {}
for element in (
@ -105,19 +105,10 @@ index 32e22ce9a8..6b19c65db3 100644
.getElementsByTagName("solvable")
):
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
index 47fca906a7..671adc2779 100644
index 22137a2544..5e4c967520 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -14,7 +14,7 @@ import salt.utils.files
import salt.utils.pkg
from salt.exceptions import CommandExecutionError
from tests.support.mixins import LoaderModuleMockMixin
-from tests.support.mock import MagicMock, Mock, call, patch
+from tests.support.mock import MagicMock, Mock, call, mock_open, patch
from tests.support.unit import TestCase
@@ -27,7 +27,10 @@ class ZyppCallMock:
@@ -28,7 +28,10 @@ class ZyppCallMock:
def __call__(self, *args, **kwargs):
# If the call is for a configuration modifier, we return self
@ -129,7 +120,7 @@ index 47fca906a7..671adc2779 100644
return self
return MagicMock(return_value=self.__return_value)()
@@ -1801,8 +1804,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -1662,8 +1665,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="(System Packages)"/>
</solvable-list></search-result></stream>
"""
@ -141,7 +132,7 @@ index 47fca906a7..671adc2779 100644
wcard = zypper.Wildcard(_zpr)
wcard.name, wcard.version = "libzypp", "*"
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
@@ -1824,8 +1828,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -1685,8 +1689,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
</solvable-list></search-result></stream>
"""
@ -153,7 +144,7 @@ index 47fca906a7..671adc2779 100644
wcard = zypper.Wildcard(_zpr)
wcard.name, wcard.version = "libzypp", "16.2.*-2*"
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
@@ -1846,8 +1851,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -1707,8 +1712,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
</solvable-list></search-result></stream>
"""
@ -165,7 +156,7 @@ index 47fca906a7..671adc2779 100644
wcard = zypper.Wildcard(_zpr)
wcard.name, wcard.version = "libzypp", "16.2.5*"
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
@@ -1867,8 +1873,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -1728,8 +1734,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
</solvable-list></search-result></stream>
"""
@ -177,7 +168,7 @@ index 47fca906a7..671adc2779 100644
wcard = zypper.Wildcard(_zpr)
wcard.name, wcard.version = "libzypp", "*.1"
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
@@ -1889,8 +1896,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -1750,8 +1757,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
</solvable-list></search-result></stream>
"""
@ -189,7 +180,7 @@ index 47fca906a7..671adc2779 100644
assert zypper.Wildcard(_zpr)("libzypp", "16.2.4*") == "16.2.4-19.5"
assert zypper.Wildcard(_zpr)("libzypp", "16.2*") == "16.2.5-25.1"
assert zypper.Wildcard(_zpr)("libzypp", "*6-*") == "17.2.6-27.9.1"
@@ -1909,8 +1917,10 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -1770,8 +1778,10 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
</solvable-list></search-result></stream>
"""
@ -202,7 +193,7 @@ index 47fca906a7..671adc2779 100644
assert zypper.Wildcard(_zpr)("libzypp", None) is None
def test_wildcard_to_query_typecheck(self):
@@ -1926,8 +1936,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -1787,8 +1797,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
</solvable-list></search-result></stream>
"""
@ -214,7 +205,7 @@ index 47fca906a7..671adc2779 100644
assert isinstance(zypper.Wildcard(_zpr)("libzypp", "*.1"), str)
def test_wildcard_to_query_condition_preservation(self):
@@ -1943,8 +1954,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -1804,8 +1815,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
</solvable-list></search-result></stream>
"""
@ -226,7 +217,7 @@ index 47fca906a7..671adc2779 100644
for op in zypper.Wildcard.Z_OP:
assert zypper.Wildcard(_zpr)(
@@ -1970,8 +1982,10 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -1831,8 +1843,10 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
</solvable-list></search-result></stream>
"""
@ -239,10 +230,10 @@ index 47fca906a7..671adc2779 100644
with self.assertRaises(CommandExecutionError):
for op in [">>", "==", "<<", "+"]:
zypper.Wildcard(_zpr)("libzypp", "{}*.1".format(op))
@@ -2063,3 +2077,38 @@ pattern() = package-c"""
with patch("salt.modules.zypperpkg.__zypper__", zypper_mock):
assert zypper.services_need_restart() == expected
zypper_mock(root=None).nolock.call.assert_called_with("ps", "-sss")
@@ -1958,3 +1972,38 @@ pattern() = package-c"""
self.assertFalse(zypper.__zypper__._is_rpm_lock())
self.assertEqual(lockf_mock.call_count, 2)
zypper.__zypper__._reset()
+
+ def test_search(self):
+ """Test zypperpkg.search()"""
@ -279,6 +270,6 @@ index 47fca906a7..671adc2779 100644
+ env={"ZYPP_READONLY_HACK": "1"},
+ )
--
2.37.3
2.39.2