SHA256
1
0
forked from pool/salt

Accepting request 1058037 from systemsmanagement:saltstack

- Allow entrypoint compatibility for "importlib-metadata>=5.0.0" (bsc#1207071)
- Added:
  * allow-entrypoint-compatibility-for-importlib-metadat.patch

- Add missing patch after rebase to fix collections Mapping issues
- Added:
  * fixes-for-python-3.10-502.patch

- Prevent deadlocks in salt-ssh executions
- Added:
  * use-rlock-to-avoid-deadlocks-in-salt-ssh.patch

- Create new salt-tests subpackage containing Salt tests

- Update to Salt release version 3005.1
  * See release notes: https://docs.saltstack.com/en/latest/topics/releases/3005.1.html
- Modified:
  * activate-all-beacons-sources-config-pillar-grains.patch
  * add-amazon-ec2-detection-for-virtual-grains-bsc-1195.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
  * add-support-for-name-pkgs-and-diff_attr-parameters-t.patch
  * align-amazon-ec2-nitro-grains-with-upstream-pr-bsc-1.patch
  * allow-vendor-change-option-with-zypper.patch

OBS-URL: https://build.opensuse.org/request/show/1058037
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/salt?expand=0&rev=134
This commit is contained in:
Dominique Leuenberger 2023-01-13 23:02:27 +00:00 committed by Git OBS Bridge
commit 9c44978ac7
117 changed files with 1887 additions and 15354 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
e04acec89d982e3bd465742afffe6ae5ec82620b
100135e8eac75cc18e3e66fc99bbeed9f5592e88

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/3004</param>
<param name="revision">release/3005.1</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/v3004-suse</param>
<param name="filename">v3004.tar.gz</param>
<param name="path">openSUSE/salt/tar.gz/v3005.1-suse</param>
<param name="filename">v3005.1.tar.gz</param>
</service>
<service name="update_changelog" mode="disabled"></service>
</services>

View File

@ -1,4 +1,4 @@
From c44b897eb1305c6b9c341fc16f729d2293ab24e4 Mon Sep 17 00:00:00 2001
From ae426ff5df3ade9ce16672fb20399634a8b777d5 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,10 +8,10 @@ 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 c255f37c26..4da665a130 100644
index 544805fc62..16452facf4 100644
--- a/salt/minion.py
+++ b/salt/minion.py
@@ -508,9 +508,7 @@ class MinionBase:
@@ -503,9 +503,7 @@ class MinionBase:
the pillar or grains changed
"""
if "config.merge" in functions:
@ -23,6 +23,6 @@ index c255f37c26..4da665a130 100644
return self.beacons.process(
b_conf, self.opts["grains"]
--
2.29.2
2.37.3

View File

@ -1,4 +1,4 @@
From 77e90c4925a4268c5975cf1ce0bb0e4c457618c1 Mon Sep 17 00:00:00 2001
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
@ -29,10 +29,10 @@ index 0000000000..5f402d61c2
@@ -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 c5d996d1bb..9530a43fc5 100644
index 23d8b8ea42..047c33ffd3 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -1173,6 +1173,24 @@ def _virtual(osdata):
@@ -1171,6 +1171,24 @@ def _virtual(osdata):
if grains.get("virtual_subtype") and grains["virtual"] == "physical":
grains["virtual"] = "virtual"
@ -58,10 +58,10 @@ index c5d996d1bb..9530a43fc5 100644
log.info(
"Although '%s' was found in path, the current user "
diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py
index 61b328b13b..cd42e2cda0 100644
index a26220718a..07b6e100d2 100644
--- a/salt/modules/cmdmod.py
+++ b/salt/modules/cmdmod.py
@@ -907,6 +907,7 @@ def _run_quiet(
@@ -932,6 +932,7 @@ def _run_quiet(
success_retcodes=None,
success_stdout=None,
success_stderr=None,
@ -69,7 +69,7 @@ index 61b328b13b..cd42e2cda0 100644
):
"""
Helper for running commands quietly for minion startup
@@ -933,6 +934,7 @@ def _run_quiet(
@@ -958,6 +959,7 @@ def _run_quiet(
success_retcodes=success_retcodes,
success_stdout=success_stdout,
success_stderr=success_stderr,
@ -77,7 +77,7 @@ index 61b328b13b..cd42e2cda0 100644
)["stdout"]
@@ -955,6 +957,7 @@ def _run_all_quiet(
@@ -980,6 +982,7 @@ def _run_all_quiet(
success_retcodes=None,
success_stdout=None,
success_stderr=None,
@ -85,7 +85,7 @@ index 61b328b13b..cd42e2cda0 100644
):
"""
@@ -987,6 +990,7 @@ def _run_all_quiet(
@@ -1012,6 +1015,7 @@ def _run_all_quiet(
success_retcodes=success_retcodes,
success_stdout=success_stdout,
success_stderr=success_stderr,
@ -94,10 +94,10 @@ index 61b328b13b..cd42e2cda0 100644
diff --git a/tests/pytests/unit/grains/test_core.py b/tests/pytests/unit/grains/test_core.py
index bc3947fa1b..84dd97d62f 100644
index 5c43dbdb09..7c4ea1f17f 100644
--- a/tests/pytests/unit/grains/test_core.py
+++ b/tests/pytests/unit/grains/test_core.py
@@ -2720,3 +2720,120 @@ def test_get_server_id():
@@ -2823,3 +2823,120 @@ def test_get_server_id():
with patch.dict(core.__opts__, {"id": "otherid"}):
assert core.get_server_id() != expected
@ -219,6 +219,6 @@ index bc3947fa1b..84dd97d62f 100644
+ assert virtual_grains["virtual"] == "kvm"
+ assert "virtual_subtype" not in virtual_grains
--
2.37.2
2.37.3

View File

@ -1,4 +1,4 @@
From 1c20e6e1acf21d301d6e53432afaa7cc42db2380 Mon Sep 17 00:00:00 2001
From cb31b475c2ac02e06b167f30fc36fe49f7f5d4f6 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.34.1
2.37.3

View File

@ -1,4 +1,4 @@
From 6ba30d3900bc328efd3480c0ff3d9e9b126fc5cb Mon Sep 17 00:00:00 2001
From 0cbc4e8f8ed5c8366ed6864216d70d58f5ae0a82 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,7 +9,7 @@ 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 cf684e20f7..8d089c6aa4 100644
index 3f855d255f..08dccafceb 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -965,7 +965,9 @@ def list_repo_pkgs(*args, **kwargs):
@ -23,7 +23,7 @@ index cf684e20f7..8d089c6aa4 100644
.splitlines()[0]
.strip()
)
@@ -2422,7 +2424,9 @@ def list_holds(pattern=__HOLD_PATTERN, full=True):
@@ -2433,7 +2435,9 @@ def list_holds(pattern=__HOLD_PATTERN, full=True):
"""
_check_versionlock()
@ -34,7 +34,7 @@ index cf684e20f7..8d089c6aa4 100644
ret = []
for line in salt.utils.itertools.split(out, "\n"):
match = _get_hold(line, pattern=pattern, full=full)
@@ -2490,7 +2494,10 @@ def group_list():
@@ -2501,7 +2505,10 @@ def group_list():
}
out = __salt__["cmd.run_stdout"](
@ -46,7 +46,7 @@ index cf684e20f7..8d089c6aa4 100644
)
key = None
for line in salt.utils.itertools.split(out, "\n"):
@@ -2561,7 +2568,9 @@ def group_info(name, expand=False, ignore_groups=None):
@@ -2572,7 +2579,9 @@ def group_info(name, expand=False, ignore_groups=None):
ret[pkgtype] = set()
cmd = [_yum(), "--quiet", "groupinfo", name]
@ -57,7 +57,7 @@ index cf684e20f7..8d089c6aa4 100644
g_info = {}
for line in salt.utils.itertools.split(out, "\n"):
@@ -3278,7 +3287,9 @@ def download(*packages, **kwargs):
@@ -3301,7 +3310,9 @@ def download(*packages, **kwargs):
cmd = ["yumdownloader", "-q", "--destdir={}".format(CACHE_DIR)]
cmd.extend(packages)
@ -68,7 +68,7 @@ index cf684e20f7..8d089c6aa4 100644
ret = {}
for dld_result in os.listdir(CACHE_DIR):
if not dld_result.endswith(".rpm"):
@@ -3354,7 +3365,7 @@ def _get_patches(installed_only=False):
@@ -3377,7 +3388,7 @@ def _get_patches(installed_only=False):
patches = {}
cmd = [_yum(), "--quiet", "updateinfo", "list", "all"]
@ -78,6 +78,6 @@ index cf684e20f7..8d089c6aa4 100644
for line in salt.utils.itertools.split(ret, os.linesep):
--
2.34.1
2.37.3

View File

@ -1,4 +1,4 @@
From 82ceb569ea57fc14ff3e2fa1c3f7ef5b95bb5eb0 Mon Sep 17 00:00:00 2001
From 97753443c2d782b61fd51457d13309405e8f12d8 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
@ -20,7 +20,7 @@ same virtual package, based on the counterpart from rpm_lowpkg API.
Convert test to pytests
---
salt/modules/aptpkg.py | 7 +-
salt/modules/aptpkg.py | 4 +-
salt/modules/rpm_lowpkg.py | 151 +++++++
salt/modules/yumpkg.py | 88 ++++
salt/modules/zypperpkg.py | 88 ++++
@ -28,40 +28,37 @@ 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, 1073 insertions(+), 5 deletions(-)
8 files changed, 1071 insertions(+), 4 deletions(-)
diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py
index 0d378355ab..558033c931 100644
index 544143d286..21ccc2a73c 100644
--- a/salt/modules/aptpkg.py
+++ b/salt/modules/aptpkg.py
@@ -2036,7 +2036,7 @@ def _convert_if_int(value):
return value
-def get_repo_keys():
+def get_repo_keys(**kwargs):
"""
.. versionadded:: 2017.7.0
@@ -2118,7 +2118,9 @@ def get_repo_keys():
@@ -2211,7 +2211,7 @@ def _parse_repo_keys_output(cmd_ret):
return ret
-def add_repo_key(path=None, text=None, keyserver=None, keyid=None, saltenv="base"):
+def add_repo_key(
+ path=None, text=None, keyserver=None, keyid=None, saltenv="base", **kwargs
+):
-def get_repo_keys(aptkey=True, keydir=None):
+def get_repo_keys(aptkey=True, keydir=None, **kwargs):
"""
.. versionadded:: 2017.7.0
@@ -2144,7 +2146,6 @@ def add_repo_key(path=None, text=None, keyserver=None, keyid=None, saltenv="base
salt '*' pkg.add_repo_key keyserver='keyserver.example' keyid='0000AAAA'
@@ -2319,6 +2319,7 @@ def add_repo_key(
aptkey=True,
keydir=None,
keyfile=None,
+ **kwargs
):
"""
.. versionadded:: 2017.7.0
@@ -2372,7 +2373,6 @@ def add_repo_key(
if not salt.utils.path.which("apt-key"):
aptkey = False
cmd = ["apt-key"]
- kwargs = {}
current_repo_keys = get_repo_keys()
# 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
--- a/salt/modules/rpm_lowpkg.py
@ -222,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 8d089c6aa4..9737508377 100644
index 08dccafceb..46f0b1f613 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -3471,3 +3471,91 @@ def services_need_restart(**kwargs):
@@ -3494,3 +3494,91 @@ def services_need_restart(**kwargs):
services.add(service)
return list(services)
@ -318,10 +315,10 @@ index 8d089c6aa4..9737508377 100644
+ """
+ return __salt__["lowpkg.remove_gpg_key"](keyid, root)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index 43c4e91109..4fc045c313 100644
index c2452d6dec..4e3006a8cd 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -3134,3 +3134,91 @@ def services_need_restart(root=None, **kwargs):
@@ -3142,3 +3142,91 @@ def services_need_restart(root=None, **kwargs):
services = zypper_output.split()
return services
@ -414,10 +411,10 @@ index 43c4e91109..4fc045c313 100644
+ """
+ return __salt__["lowpkg.remove_gpg_key"](keyid, root)
diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py
index f395dec1ed..00d3cbfcd8 100644
index 358c927695..a777fe4a96 100644
--- a/salt/states/pkgrepo.py
+++ b/salt/states/pkgrepo.py
@@ -85,6 +85,7 @@ package managers are APT, DNF, YUM and Zypper. Here is some example SLS:
@@ -118,6 +118,7 @@ Using ``aptkey: False`` with ``keyserver`` and ``keyid``:
"""
@ -425,7 +422,7 @@ index f395dec1ed..00d3cbfcd8 100644
import sys
import salt.utils.data
@@ -672,3 +673,209 @@ def absent(name, **kwargs):
@@ -714,3 +715,209 @@ def absent(name, **kwargs):
ret["comment"] = "Failed to remove repo {}".format(name)
return ret
@ -636,7 +633,7 @@ index f395dec1ed..00d3cbfcd8 100644
+
+ return ret
diff --git a/tests/pytests/unit/modules/test_yumpkg.py b/tests/pytests/unit/modules/test_yumpkg.py
index ea8135bcef..475e1d6094 100644
index 99ec05b990..a495569c5d 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
@ -648,7 +645,7 @@ index ea8135bcef..475e1d6094 100644
try:
import pytest
@@ -1849,6 +1849,48 @@ def test_get_repo_with_non_existent_repo(list_repos_var):
@@ -1911,6 +1911,48 @@ def test_get_repo_with_non_existent_repo(list_repos_var):
assert ret == expected, ret
@ -698,7 +695,7 @@ index ea8135bcef..475e1d6094 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 4a0055e11c..eb1e63f6d7 100644
index 70bd837c5f..351a173b81 100644
--- a/tests/pytests/unit/modules/test_zypperpkg.py
+++ b/tests/pytests/unit/modules/test_zypperpkg.py
@@ -8,7 +8,8 @@ import os
@ -711,10 +708,10 @@ index 4a0055e11c..eb1e63f6d7 100644
@pytest.fixture
@@ -78,3 +79,45 @@ def test_normalize_name():
assert result == "foo", result
result = zypper.normalize_name("foo.noarch")
assert result == "foo", result
@@ -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
+
+
+def test_get_repo_keys():
@ -1214,6 +1211,6 @@ index daa913bcc2..cbb12cfb9b 100644
+ "comment": "There are keys or repositories to migrate or drop",
+ }
--
2.34.1
2.37.3

View File

@ -1,40 +0,0 @@
From aec7965f19f55d3d33893833fd259606d3a7e641 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Tue, 8 Feb 2022 11:53:47 +0000
Subject: [PATCH] Add missing "ansible" module functions to whitelist in
Salt 3004 (bsc#1195625) (#485)
* Add missing functions to ansible __load__
* Properly get separated copies from list
---
salt/modules/ansiblegate.py | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/salt/modules/ansiblegate.py b/salt/modules/ansiblegate.py
index f33be6a00e..7c3a17861a 100644
--- a/salt/modules/ansiblegate.py
+++ b/salt/modules/ansiblegate.py
@@ -45,7 +45,16 @@ hosts:
"""
DEFAULT_TIMEOUT = 1200 # seconds (20 minutes)
-__load__ = __non_ansible_functions__ = ["help", "list_", "call", "playbooks"][:]
+__non_ansible_functions__ = []
+
+__load__ = __non_ansible_functions__[:] = [
+ "help",
+ "list_",
+ "call",
+ "playbooks",
+ "discover_playbooks",
+ "targets",
+]
def _set_callables(modules):
--
2.35.1

View File

@ -1,4 +1,4 @@
From 2422d30358bcd0f96e399e623136f7984d136b38 Mon Sep 17 00:00:00 2001
From e6f6b011849536c5ff9a9bdef56e900ed5a7fb1d 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 ab85c7f5c6..59bb19ce75 100644
index 705a1bc2fb..7f41ffe77b 100644
--- a/salt/master.py
+++ b/salt/master.py
@@ -2042,6 +2042,7 @@ class ClearFuncs(TransportMethods):
@@ -1952,6 +1952,7 @@ class ClearFuncs(TransportMethods):
expose_methods = (
"ping",
"publish",
@ -21,6 +21,6 @@ index ab85c7f5c6..59bb19ce75 100644
"mk_token",
"wheel",
--
2.29.2
2.37.3

View File

@ -1,402 +0,0 @@
From a15321796586b033d8fa8366074087ceddaa4d23 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Wed, 19 Jan 2022 17:41:11 +0100
Subject: [PATCH] Add rpm_vercmp python library for version comparison -
3003.3 (#448)
* Add rpm_vercmp python library for version comparison
* Add rpm-vercmp to tiamat builds
* Put GPG tests back to test_rpm_lowpkg
Co-authored-by: Megan Wilhite <mwilhite@vmware.com>
---
changelog/60814.added | 1 +
tests/pytests/unit/modules/test_rpm_lowpkg.py | 326 ++++++++++++++----
2 files changed, 263 insertions(+), 64 deletions(-)
create mode 100644 changelog/60814.added
diff --git a/changelog/60814.added b/changelog/60814.added
new file mode 100644
index 0000000000..7a9ffe1b25
--- /dev/null
+++ b/changelog/60814.added
@@ -0,0 +1 @@
+Add the python rpm-vercmp library in the rpm_lowpkg.py module.
diff --git a/tests/pytests/unit/modules/test_rpm_lowpkg.py b/tests/pytests/unit/modules/test_rpm_lowpkg.py
index f19afa854e..c9d1ac2b1c 100644
--- a/tests/pytests/unit/modules/test_rpm_lowpkg.py
+++ b/tests/pytests/unit/modules/test_rpm_lowpkg.py
@@ -3,6 +3,7 @@
"""
+import datetime
import pytest
import salt.modules.cmdmod
import salt.modules.rpm_lowpkg as rpm
@@ -250,92 +251,57 @@ def test_version_cmp_rpm_all_libraries(rpm_lib):
assert 1 == rpm.version_cmp("3:2.9.1-8.el7.4", "3:2.9.1-7.el7.4")
-def test_version_cmp_rpm():
+@patch("salt.modules.rpm_lowpkg.HAS_RPM", True)
+@patch("salt.modules.rpm_lowpkg.rpm.labelCompare", return_value=-1)
+@patch("salt.modules.rpm_lowpkg.log")
+def test_version_cmp_rpm(mock_log, mock_labelCompare):
"""
Test package version if RPM-Python is installed
:return:
"""
- mock_label = MagicMock(return_value=-1)
- mock_log = MagicMock()
- patch_label = patch("salt.modules.rpm_lowpkg.rpm.labelCompare", mock_label)
- patch_log = patch("salt.modules.rpm_lowpkg.log", mock_log)
- patch_rpm = patch("salt.modules.rpm_lowpkg.HAS_RPM", True)
- with patch_label, patch_rpm, patch_log:
- assert -1 == rpm.version_cmp("1", "2")
- assert not mock_log.warning.called
- assert mock_label.called
+ assert -1 == rpm.version_cmp("1", "2")
+ assert not mock_log.warning.called
+ assert mock_labelCompare.called
-def test_version_cmp_rpmutils():
+@patch("salt.modules.rpm_lowpkg.HAS_RPM", False)
+@patch("salt.modules.rpm_lowpkg.HAS_RPMUTILS", True)
+@patch("salt.modules.rpm_lowpkg.HAS_PY_RPM", False)
+@patch("salt.modules.rpm_lowpkg.rpmUtils", create=True)
+@patch("salt.modules.rpm_lowpkg.log")
+def test_version_cmp_rpmutils(mock_log, mock_rpmUtils):
"""
Test package version if rpmUtils.miscutils called
:return:
"""
- mock_log = MagicMock()
- mock_rpmUtils = MagicMock()
mock_rpmUtils.miscutils = MagicMock()
mock_rpmUtils.miscutils.compareEVR = MagicMock(return_value=-1)
- patch_utils = patch("salt.modules.rpm_lowpkg.rpmUtils", mock_rpmUtils, create=True)
- patch_rpm = patch("salt.modules.rpm_lowpkg.HAS_RPM", False)
- patch_utils_lib = patch("salt.modules.rpm_lowpkg.HAS_RPMUTILS", True)
- patch_py_rpm = patch("salt.modules.rpm_lowpkg.HAS_PY_RPM", False)
- patch_log = patch("salt.modules.rpm_lowpkg.log", mock_log)
-
- with patch_utils, patch_rpm, patch_py_rpm, patch_utils_lib, patch_log:
- assert -1 == rpm.version_cmp("1", "2")
- assert mock_log.warning.called
- assert mock_rpmUtils.miscutils.compareEVR.called
+ assert -1 == rpm.version_cmp("1", "2")
+ assert mock_log.warning.called
+ assert mock_rpmUtils.miscutils.compareEVR.called
+ assert (
+ mock_log.warning.mock_calls[0][1][0]
+ == "Please install a package that provides rpm.labelCompare for more accurate version comparisons."
+ )
-def test_version_cmp_rpmdev_vercmp():
+@patch("salt.modules.rpm_lowpkg.HAS_RPM", False)
+@patch("salt.modules.rpm_lowpkg.HAS_RPMUTILS", False)
+@patch("salt.modules.rpm_lowpkg.HAS_PY_RPM", False)
+@patch("salt.utils.path.which", return_value=True)
+@patch("salt.modules.rpm_lowpkg.log")
+def test_version_cmp_rpmdev_vercmp(mock_log, mock_which):
"""
Test package version if rpmdev-vercmp is installed
:return:
"""
mock__salt__ = MagicMock(return_value={"retcode": 12})
- mock_log = MagicMock()
- patch_rpm = patch("salt.modules.rpm_lowpkg.HAS_RPM", False)
- patch_rpmutils = patch("salt.modules.rpm_lowpkg.HAS_RPMUTILS", False)
- patch_py_rpm = patch("salt.modules.rpm_lowpkg.HAS_PY_RPM", False)
- patch_which = patch("salt.utils.path.which", return_value=True)
- patch_log = patch("salt.modules.rpm_lowpkg.log", mock_log)
-
- with patch_rpm, patch_rpmutils, patch_py_rpm, patch_which, patch_log:
- with patch.dict(rpm.__salt__, {"cmd.run_all": mock__salt__}):
- assert -1 == rpm.version_cmp("1", "2")
- assert mock__salt__.called
- assert mock_log.warning.called
- assert (
- mock_log.warning.mock_calls[0][1][0]
- == "Please install a package that provides rpm.labelCompare for more accurate version comparisons."
- )
- assert (
- mock_log.warning.mock_calls[1][1][0]
- == "Installing the rpmdevtools package may surface dev tools in production."
- )
-
-
-def test_version_cmp_python():
- """
- Test package version if falling back to python
-
- :return:
- """
- mock_log = MagicMock()
- patch_rpm = patch("salt.modules.rpm_lowpkg.HAS_RPM", False)
- patch_rpmutils = patch("salt.modules.rpm_lowpkg.HAS_RPMUTILS", False)
- mock_version_cmp = MagicMock(return_value=-1)
- patch_py_rpm = patch("salt.modules.rpm_lowpkg.HAS_PY_RPM", False)
- patch_cmp = patch("salt.utils.versions.version_cmp", mock_version_cmp)
- patch_which = patch("salt.utils.path.which", return_value=False)
- patch_log = patch("salt.modules.rpm_lowpkg.log", mock_log)
-
- with patch_rpm, patch_rpmutils, patch_py_rpm, patch_cmp, patch_which, patch_log:
+ with patch.dict(rpm.__salt__, {"cmd.run_all": mock__salt__}):
assert -1 == rpm.version_cmp("1", "2")
- assert mock_version_cmp.called
+ assert mock__salt__.called
assert mock_log.warning.called
assert (
mock_log.warning.mock_calls[0][1][0]
@@ -343,5 +309,237 @@ def test_version_cmp_python():
)
assert (
mock_log.warning.mock_calls[1][1][0]
- == "Falling back on salt.utils.versions.version_cmp() for version comparisons"
+ == "Installing the rpmdevtools package may surface dev tools in production."
)
+
+
+@patch("salt.modules.rpm_lowpkg.HAS_RPM", False)
+@patch("salt.modules.rpm_lowpkg.HAS_RPMUTILS", False)
+@patch("salt.modules.rpm_lowpkg.HAS_PY_RPM", False)
+@patch("salt.utils.versions.version_cmp", return_value=-1)
+@patch("salt.utils.path.which", return_value=False)
+@patch("salt.modules.rpm_lowpkg.log")
+def test_version_cmp_python(mock_log, mock_which, mock_version_cmp):
+ """
+ Test package version if falling back to python
+
+ :return:
+ """
+ assert -1 == rpm.version_cmp("1", "2")
+ assert mock_version_cmp.called
+ assert mock_log.warning.called
+ assert (
+ mock_log.warning.mock_calls[0][1][0]
+ == "Please install a package that provides rpm.labelCompare for more accurate version comparisons."
+ )
+ assert (
+ mock_log.warning.mock_calls[1][1][0]
+ == "Falling back on salt.utils.versions.version_cmp() for version comparisons"
+ )
+
+
+def test_list_gpg_keys_no_info():
+ """
+ Test list_gpg_keys with no extra information
+ """
+ mock = MagicMock(return_value="\n".join(["gpg-pubkey-1", "gpg-pubkey-2"]))
+ with patch.dict(rpm.__salt__, {"cmd.run_stdout": mock}):
+ assert rpm.list_gpg_keys() == ["gpg-pubkey-1", "gpg-pubkey-2"]
+ assert not _called_with_root(mock)
+
+
+def test_list_gpg_keys_no_info_root():
+ """
+ Test list_gpg_keys with no extra information and root
+ """
+ mock = MagicMock(return_value="\n".join(["gpg-pubkey-1", "gpg-pubkey-2"]))
+ with patch.dict(rpm.__salt__, {"cmd.run_stdout": mock}):
+ assert rpm.list_gpg_keys(root="/mnt") == ["gpg-pubkey-1", "gpg-pubkey-2"]
+ assert _called_with_root(mock)
+
+
+@patch("salt.modules.rpm_lowpkg.info_gpg_key")
+def test_list_gpg_keys_info(info_gpg_key):
+ """
+ Test list_gpg_keys with extra information
+ """
+ info_gpg_key.side_effect = lambda x, root: {"Description": "key for {}".format(x)}
+ mock = MagicMock(return_value="\n".join(["gpg-pubkey-1", "gpg-pubkey-2"]))
+ with patch.dict(rpm.__salt__, {"cmd.run_stdout": mock}):
+ assert rpm.list_gpg_keys(info=True) == {
+ "gpg-pubkey-1": {"Description": "key for gpg-pubkey-1"},
+ "gpg-pubkey-2": {"Description": "key for gpg-pubkey-2"},
+ }
+ assert not _called_with_root(mock)
+
+
+def test_info_gpg_key():
+ """
+ Test info_gpg_keys from a normal output
+ """
+ info = """Name : gpg-pubkey
+Version : 3dbdc284
+Release : 53674dd4
+Architecture: (none)
+Install Date: Fri 08 Mar 2019 11:57:44 AM UTC
+Group : Public Keys
+Size : 0
+License : pubkey
+Signature : (none)
+Source RPM : (none)
+Build Date : Mon 05 May 2014 10:37:40 AM UTC
+Build Host : localhost
+Packager : openSUSE Project Signing Key <opensuse@opensuse.org>
+Summary : gpg(openSUSE Project Signing Key <opensuse@opensuse.org>)
+Description :
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.14.2.1 (NSS-3)
+
+mQENBEkUTD8BCADWLy5d5IpJedHQQSXkC1VK/oAZlJEeBVpSZjMCn8LiHaI9Wq3G
+3Vp6wvsP1b3kssJGzVFNctdXt5tjvOLxvrEfRJuGfqHTKILByqLzkeyWawbFNfSQ
+93/8OunfSTXC1Sx3hgsNXQuOrNVKrDAQUqT620/jj94xNIg09bLSxsjN6EeTvyiO
+mtE9H1J03o9tY6meNL/gcQhxBvwuo205np0JojYBP0pOfN8l9hnIOLkA0yu4ZXig
+oKOVmf4iTjX4NImIWldT+UaWTO18NWcCrujtgHueytwYLBNV5N0oJIP2VYuLZfSD
+VYuPllv7c6O2UEOXJsdbQaVuzU1HLocDyipnABEBAAG0NG9wZW5TVVNFIFByb2pl
+Y3QgU2lnbmluZyBLZXkgPG9wZW5zdXNlQG9wZW5zdXNlLm9yZz6JATwEEwECACYC
+GwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUCU2dN1AUJHR8ElQAKCRC4iy/UPb3C
+hGQrB/9teCZ3Nt8vHE0SC5NmYMAE1Spcjkzx6M4r4C70AVTMEQh/8BvgmwkKP/qI
+CWo2vC1hMXRgLg/TnTtFDq7kW+mHsCXmf5OLh2qOWCKi55Vitlf6bmH7n+h34Sha
+Ei8gAObSpZSF8BzPGl6v0QmEaGKM3O1oUbbB3Z8i6w21CTg7dbU5vGR8Yhi9rNtr
+hqrPS+q2yftjNbsODagaOUb85ESfQGx/LqoMePD+7MqGpAXjKMZqsEDP0TbxTwSk
+4UKnF4zFCYHPLK3y/hSH5SEJwwPY11l6JGdC1Ue8Zzaj7f//axUs/hTC0UZaEE+a
+5v4gbqOcigKaFs9Lc3Bj8b/lE10Y
+=i2TA
+-----END PGP PUBLIC KEY BLOCK-----
+
+"""
+ mock = MagicMock(return_value=info)
+ with patch.dict(rpm.__salt__, {"cmd.run_stdout": mock}):
+ assert rpm.info_gpg_key("key") == {
+ "Name": "gpg-pubkey",
+ "Version": "3dbdc284",
+ "Release": "53674dd4",
+ "Architecture": None,
+ "Install Date": datetime.datetime(2019, 3, 8, 11, 57, 44),
+ "Group": "Public Keys",
+ "Size": 0,
+ "License": "pubkey",
+ "Signature": None,
+ "Source RPM": None,
+ "Build Date": datetime.datetime(2014, 5, 5, 10, 37, 40),
+ "Build Host": "localhost",
+ "Packager": "openSUSE Project Signing Key <opensuse@opensuse.org>",
+ "Summary": "gpg(openSUSE Project Signing Key <opensuse@opensuse.org>)",
+ "Description": """-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.14.2.1 (NSS-3)
+
+mQENBEkUTD8BCADWLy5d5IpJedHQQSXkC1VK/oAZlJEeBVpSZjMCn8LiHaI9Wq3G
+3Vp6wvsP1b3kssJGzVFNctdXt5tjvOLxvrEfRJuGfqHTKILByqLzkeyWawbFNfSQ
+93/8OunfSTXC1Sx3hgsNXQuOrNVKrDAQUqT620/jj94xNIg09bLSxsjN6EeTvyiO
+mtE9H1J03o9tY6meNL/gcQhxBvwuo205np0JojYBP0pOfN8l9hnIOLkA0yu4ZXig
+oKOVmf4iTjX4NImIWldT+UaWTO18NWcCrujtgHueytwYLBNV5N0oJIP2VYuLZfSD
+VYuPllv7c6O2UEOXJsdbQaVuzU1HLocDyipnABEBAAG0NG9wZW5TVVNFIFByb2pl
+Y3QgU2lnbmluZyBLZXkgPG9wZW5zdXNlQG9wZW5zdXNlLm9yZz6JATwEEwECACYC
+GwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUCU2dN1AUJHR8ElQAKCRC4iy/UPb3C
+hGQrB/9teCZ3Nt8vHE0SC5NmYMAE1Spcjkzx6M4r4C70AVTMEQh/8BvgmwkKP/qI
+CWo2vC1hMXRgLg/TnTtFDq7kW+mHsCXmf5OLh2qOWCKi55Vitlf6bmH7n+h34Sha
+Ei8gAObSpZSF8BzPGl6v0QmEaGKM3O1oUbbB3Z8i6w21CTg7dbU5vGR8Yhi9rNtr
+hqrPS+q2yftjNbsODagaOUb85ESfQGx/LqoMePD+7MqGpAXjKMZqsEDP0TbxTwSk
+4UKnF4zFCYHPLK3y/hSH5SEJwwPY11l6JGdC1Ue8Zzaj7f//axUs/hTC0UZaEE+a
+5v4gbqOcigKaFs9Lc3Bj8b/lE10Y
+=i2TA
+-----END PGP PUBLIC KEY BLOCK-----""",
+ }
+ assert not _called_with_root(mock)
+
+
+def test_info_gpg_key_extended():
+ """
+ Test info_gpg_keys from an extended output
+ """
+ info = """Name : gpg-pubkey
+Version : 3dbdc284
+Release : 53674dd4
+Architecture: (none)
+Install Date: Fri 08 Mar 2019 11:57:44 AM UTC
+Group : Public Keys
+Size : 0
+License : pubkey
+Signature : (none)
+Source RPM : (none)
+Build Date : Mon 05 May 2014 10:37:40 AM UTC
+Build Host : localhost
+Packager : openSUSE Project Signing Key <opensuse@opensuse.org>
+Summary : gpg(openSUSE Project Signing Key <opensuse@opensuse.org>)
+Description :
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.14.2.1 (NSS-3)
+
+mQENBEkUTD8BCADWLy5d5IpJedHQQSXkC1VK/oAZlJEeBVpSZjMCn8LiHaI9Wq3G
+3Vp6wvsP1b3kssJGzVFNctdXt5tjvOLxvrEfRJuGfqHTKILByqLzkeyWawbFNfSQ
+93/8OunfSTXC1Sx3hgsNXQuOrNVKrDAQUqT620/jj94xNIg09bLSxsjN6EeTvyiO
+mtE9H1J03o9tY6meNL/gcQhxBvwuo205np0JojYBP0pOfN8l9hnIOLkA0yu4ZXig
+oKOVmf4iTjX4NImIWldT+UaWTO18NWcCrujtgHueytwYLBNV5N0oJIP2VYuLZfSD
+VYuPllv7c6O2UEOXJsdbQaVuzU1HLocDyipnABEBAAG0NG9wZW5TVVNFIFByb2pl
+Y3QgU2lnbmluZyBLZXkgPG9wZW5zdXNlQG9wZW5zdXNlLm9yZz6JATwEEwECACYC
+GwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUCU2dN1AUJHR8ElQAKCRC4iy/UPb3C
+hGQrB/9teCZ3Nt8vHE0SC5NmYMAE1Spcjkzx6M4r4C70AVTMEQh/8BvgmwkKP/qI
+CWo2vC1hMXRgLg/TnTtFDq7kW+mHsCXmf5OLh2qOWCKi55Vitlf6bmH7n+h34Sha
+Ei8gAObSpZSF8BzPGl6v0QmEaGKM3O1oUbbB3Z8i6w21CTg7dbU5vGR8Yhi9rNtr
+hqrPS+q2yftjNbsODagaOUb85ESfQGx/LqoMePD+7MqGpAXjKMZqsEDP0TbxTwSk
+4UKnF4zFCYHPLK3y/hSH5SEJwwPY11l6JGdC1Ue8Zzaj7f//axUs/hTC0UZaEE+a
+5v4gbqOcigKaFs9Lc3Bj8b/lE10Y
+=i2TA
+-----END PGP PUBLIC KEY BLOCK-----
+
+Distribution: (none)
+"""
+ mock = MagicMock(return_value=info)
+ with patch.dict(rpm.__salt__, {"cmd.run_stdout": mock}):
+ assert rpm.info_gpg_key("key") == {
+ "Name": "gpg-pubkey",
+ "Version": "3dbdc284",
+ "Release": "53674dd4",
+ "Architecture": None,
+ "Install Date": datetime.datetime(2019, 3, 8, 11, 57, 44),
+ "Group": "Public Keys",
+ "Size": 0,
+ "License": "pubkey",
+ "Signature": None,
+ "Source RPM": None,
+ "Build Date": datetime.datetime(2014, 5, 5, 10, 37, 40),
+ "Build Host": "localhost",
+ "Packager": "openSUSE Project Signing Key <opensuse@opensuse.org>",
+ "Summary": "gpg(openSUSE Project Signing Key <opensuse@opensuse.org>)",
+ "Description": """-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.14.2.1 (NSS-3)
+
+mQENBEkUTD8BCADWLy5d5IpJedHQQSXkC1VK/oAZlJEeBVpSZjMCn8LiHaI9Wq3G
+3Vp6wvsP1b3kssJGzVFNctdXt5tjvOLxvrEfRJuGfqHTKILByqLzkeyWawbFNfSQ
+93/8OunfSTXC1Sx3hgsNXQuOrNVKrDAQUqT620/jj94xNIg09bLSxsjN6EeTvyiO
+mtE9H1J03o9tY6meNL/gcQhxBvwuo205np0JojYBP0pOfN8l9hnIOLkA0yu4ZXig
+oKOVmf4iTjX4NImIWldT+UaWTO18NWcCrujtgHueytwYLBNV5N0oJIP2VYuLZfSD
+VYuPllv7c6O2UEOXJsdbQaVuzU1HLocDyipnABEBAAG0NG9wZW5TVVNFIFByb2pl
+Y3QgU2lnbmluZyBLZXkgPG9wZW5zdXNlQG9wZW5zdXNlLm9yZz6JATwEEwECACYC
+GwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUCU2dN1AUJHR8ElQAKCRC4iy/UPb3C
+hGQrB/9teCZ3Nt8vHE0SC5NmYMAE1Spcjkzx6M4r4C70AVTMEQh/8BvgmwkKP/qI
+CWo2vC1hMXRgLg/TnTtFDq7kW+mHsCXmf5OLh2qOWCKi55Vitlf6bmH7n+h34Sha
+Ei8gAObSpZSF8BzPGl6v0QmEaGKM3O1oUbbB3Z8i6w21CTg7dbU5vGR8Yhi9rNtr
+hqrPS+q2yftjNbsODagaOUb85ESfQGx/LqoMePD+7MqGpAXjKMZqsEDP0TbxTwSk
+4UKnF4zFCYHPLK3y/hSH5SEJwwPY11l6JGdC1Ue8Zzaj7f//axUs/hTC0UZaEE+a
+5v4gbqOcigKaFs9Lc3Bj8b/lE10Y
+=i2TA
+-----END PGP PUBLIC KEY BLOCK-----""",
+ "Distribution": None,
+ }
+ assert not _called_with_root(mock)
+
+
+def test_remove_gpg_key():
+ """
+ Test remove_gpg_key
+ """
+ mock = MagicMock(return_value=0)
+ with patch.dict(rpm.__salt__, {"cmd.retcode": mock}):
+ assert rpm.remove_gpg_key("gpg-pubkey-1")
+ assert not _called_with_root(mock)
--
2.34.1

View File

@ -1,4 +1,4 @@
From 8d1aba4e450922ec7ae4ce5fcf13dc5f7d2b8b7e Mon Sep 17 00:00:00 2001
From c683ceaf9321a646d32e3b2b5fca705563fe8e73 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
@ -54,49 +54,45 @@ the child process as failed
* Do not run pre flight script for raw_shell
---
salt/_logging/impl.py | 59 ++++++-----
salt/client/ssh/__init__.py | 174 ++++++++++++++++++++++++++++-----
salt/_logging/impl.py | 55 +++++++-----
salt/client/ssh/__init__.py | 157 ++++++++++++++++++++++++++++-----
salt/client/ssh/client.py | 7 +-
salt/client/ssh/shell.py | 8 ++
salt/client/ssh/ssh_py_shim.py | 108 +++++++++++---------
salt/loader/__init__.py | 31 +++++-
salt/client/ssh/ssh_py_shim.py | 108 +++++++++++++----------
salt/loader/__init__.py | 31 ++++++-
salt/netapi/__init__.py | 3 +-
salt/roster/__init__.py | 6 +-
tests/unit/test_loader.py | 2 +-
9 files changed, 292 insertions(+), 106 deletions(-)
9 files changed, 278 insertions(+), 99 deletions(-)
diff --git a/salt/_logging/impl.py b/salt/_logging/impl.py
index 779316ce0b..953490b284 100644
index cc18f49a9e..e050f43caf 100644
--- a/salt/_logging/impl.py
+++ b/salt/_logging/impl.py
@@ -7,6 +7,7 @@
import logging
import re
@@ -14,6 +14,7 @@ import re
import socket
import sys
import traceback
+import threading
import types
import urllib.parse
# Let's define these custom logging levels before importing the salt._logging.mixins
@@ -89,6 +90,10 @@ SORTED_LEVEL_NAMES = [l[0] for l in sorted(LOG_LEVELS.items(), key=lambda x: x[1
MODNAME_PATTERN = re.compile(r"(?P<name>%%\(name\)(?:\-(?P<digits>[\d]+))?s)")
@@ -104,6 +105,10 @@ DFLT_LOG_DATEFMT_LOGFILE = "%Y-%m-%d %H:%M:%S"
DFLT_LOG_FMT_CONSOLE = "[%(levelname)-8s] %(message)s"
DFLT_LOG_FMT_LOGFILE = "%(asctime)s,%(msecs)03d [%(name)-17s:%(lineno)-4d][%(levelname)-8s][%(process)d] %(message)s"
+# LOG_LOCK is used to prevent deadlocks on using logging
+# in combination with multiprocessing with salt-api
+LOG_LOCK = threading.Lock()
+
# ----- REMOVE ME ON REFACTOR COMPLETE ------------------------------------------------------------------------------>
class __NullLoggingHandler(TemporaryLoggingHandler):
@@ -283,31 +288,35 @@ class SaltLoggingClass(
class SaltLogRecord(logging.LogRecord):
def __init__(self, *args, **kwargs):
@@ -270,27 +275,35 @@ class SaltLoggingClass(LOGGING_LOGGER_CLASS, metaclass=LoggingMixinMeta):
else:
extra["exc_info_on_loglevel"] = exc_info_on_loglevel
- if sys.version_info < (3,):
- LOGGING_LOGGER_CLASS._log(
- self, level, msg, args, exc_info=exc_info, extra=extra
- )
- elif sys.version_info < (3, 8):
- if sys.version_info < (3, 8):
- LOGGING_LOGGER_CLASS._log(
- self,
- level,
@ -150,7 +146,7 @@ index 779316ce0b..953490b284 100644
def makeRecord(
self,
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index 37faa869bc..0066f4597b 100644
index ad2796bc87..6db2dfcbb0 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -6,11 +6,13 @@ import base64
@ -166,8 +162,8 @@ index 37faa869bc..0066f4597b 100644
+import psutil
import queue
import re
import subprocess
@@ -19,6 +21,7 @@ import tarfile
import shlex
@@ -20,6 +22,7 @@ import tarfile
import tempfile
import time
import uuid
@ -175,16 +171,16 @@ index 37faa869bc..0066f4597b 100644
import salt.client.ssh.shell
import salt.client.ssh.wrapper
@@ -44,6 +47,7 @@ import salt.utils.stringutils
import salt.utils.thin
import salt.utils.url
@@ -47,6 +50,7 @@ import salt.utils.url
import salt.utils.verify
from salt._logging import LOG_LEVELS
from salt._logging.mixins import MultiprocessingStateMixin
+from salt._logging.impl import LOG_LOCK
from salt.template import compile_template
from salt.utils.platform import is_junos, is_windows
from salt.utils.process import Process
@@ -146,15 +150,26 @@ elif [ "$SUDO" ] && [ -n "$SUDO_USER" ]
then SUDO="sudo "
from salt.utils.zeromq import zmq
@@ -146,15 +150,26 @@ if [ "$SUDO" ] && [ "$SUDO_USER" ]
then SUDO="$SUDO -u $SUDO_USER"
fi
EX_PYTHON_INVALID={EX_THIN_PYTHON_INVALID}
-PYTHON_CMDS="python3 /usr/libexec/platform-python python27 python2.7 python26 python2.6 python2 python"
@ -234,10 +230,10 @@ index 37faa869bc..0066f4597b 100644
+# The file on a salt-ssh minion used to identify if Salt Bundle was deployed
+VENV_HASH_FILE = "/var/tmp/venv-salt-minion/venv-hash.txt"
+
if not is_windows() and not is_junos():
if not salt.utils.platform.is_windows() and not salt.utils.platform.is_junos():
shim_file = os.path.join(os.path.dirname(__file__), "ssh_py_shim.py")
if not os.path.exists(shim_file):
@@ -209,7 +223,7 @@ class SSH:
@@ -209,7 +223,7 @@ class SSH(MultiprocessingStateMixin):
ROSTER_UPDATE_FLAG = "#__needs_update"
@ -246,7 +242,7 @@ index 37faa869bc..0066f4597b 100644
self.__parsed_rosters = {SSH.ROSTER_UPDATE_FLAG: True}
pull_sock = os.path.join(opts["sock_dir"], "master_event_pull.ipc")
if os.path.exists(pull_sock) and zmq:
@@ -236,7 +250,9 @@ class SSH:
@@ -236,7 +250,9 @@ class SSH(MultiprocessingStateMixin):
else "glob"
)
self._expand_target()
@ -257,10 +253,10 @@ index 37faa869bc..0066f4597b 100644
self.targets = self.roster.targets(self.opts["tgt"], self.tgt_type)
if not self.targets:
self._update_targets()
@@ -317,6 +333,14 @@ class SSH:
@@ -316,6 +332,13 @@ class SSH(MultiprocessingStateMixin):
extended_cfg=self.opts.get("ssh_ext_alternatives"),
)
self.mods = mod_data(self.fsclient)
+ self.cache = salt.cache.Cache(self.opts)
+ self.master_id = self.opts["id"]
+ self.max_pid_wait = int(self.opts.get("ssh_max_pid_wait", 600))
@ -268,11 +264,10 @@ index 37faa869bc..0066f4597b 100644
+ self.opts["cachedir"], "salt-ssh.session.lock"
+ )
+ self.ssh_session_grace_time = int(self.opts.get("ssh_session_grace_time", 3))
+
@property
def parse_tgt(self):
"""
@@ -531,6 +555,8 @@ class SSH:
# __setstate__ and __getstate__ are only used on spawning platforms.
def __setstate__(self, state):
@@ -546,6 +569,8 @@ class SSH(MultiprocessingStateMixin):
"""
Run the routine in a "Thread", put a dict on the queue
"""
@ -281,7 +276,7 @@ index 37faa869bc..0066f4597b 100644
opts = copy.deepcopy(opts)
single = Single(
opts,
@@ -570,7 +596,7 @@ class SSH:
@@ -585,7 +610,7 @@ class SSH(MultiprocessingStateMixin):
"""
que = multiprocessing.Queue()
running = {}
@ -290,7 +285,7 @@ index 37faa869bc..0066f4597b 100644
returned = set()
rets = set()
init = False
@@ -579,11 +605,43 @@ class SSH:
@@ -594,11 +619,43 @@ class SSH(MultiprocessingStateMixin):
log.error("No matching targets found in roster.")
break
if len(running) < self.opts.get("ssh_max_procs", 25) and not init:
@ -337,7 +332,7 @@ index 37faa869bc..0066f4597b 100644
for default in self.defaults:
if default not in self.targets[host]:
self.targets[host][default] = self.defaults[default]
@@ -615,8 +673,38 @@ class SSH:
@@ -630,8 +687,38 @@ class SSH(MultiprocessingStateMixin):
mine,
)
routine = Process(target=self.handle_routine, args=args)
@ -377,7 +372,7 @@ index 37faa869bc..0066f4597b 100644
continue
ret = {}
try:
@@ -647,12 +735,27 @@ class SSH:
@@ -662,12 +749,27 @@ class SSH(MultiprocessingStateMixin):
)
ret = {"id": host, "ret": error}
log.error(error)
@ -405,24 +400,7 @@ index 37faa869bc..0066f4597b 100644
if len(rets) >= len(self.targets):
break
# Sleep when limit or all threads started
@@ -916,6 +1019,7 @@ class Single:
self.context = {"master_opts": self.opts, "fileclient": self.fsclient}
self.ssh_pre_flight = kwargs.get("ssh_pre_flight", None)
+ self.ssh_pre_flight_args = kwargs.get("ssh_pre_flight_args", None)
if self.ssh_pre_flight:
self.ssh_pre_file = os.path.basename(self.ssh_pre_flight)
@@ -1007,7 +1111,7 @@ class Single:
self.shell.send(self.ssh_pre_flight, script)
- return self.execute_script(script)
+ return self.execute_script(script, script_args=self.ssh_pre_flight_args)
def check_thin_dir(self):
"""
@@ -1020,14 +1124,24 @@ class Single:
@@ -1036,14 +1138,24 @@ class Single:
return False
return True
@ -451,7 +429,7 @@ index 37faa869bc..0066f4597b 100644
self.deploy_ext()
return True
@@ -1055,8 +1169,9 @@ class Single:
@@ -1071,8 +1183,9 @@ class Single:
Returns tuple of (stdout, stderr, retcode)
"""
stdout = stderr = retcode = None
@ -462,7 +440,7 @@ index 37faa869bc..0066f4597b 100644
if not self.opts.get("ssh_run_pre_flight", False) and self.check_thin_dir():
log.info(
"%s thin dir already exists. Not running ssh_pre_flight script",
@@ -1070,14 +1185,16 @@ class Single:
@@ -1086,14 +1199,16 @@ class Single:
stdout, stderr, retcode = self.run_ssh_pre_flight()
if retcode != 0:
log.error(
@ -481,38 +459,11 @@ index 37faa869bc..0066f4597b 100644
cmd_str = " ".join([self._escape_arg(arg) for arg in self.argv])
stdout, stderr, retcode = self.shell.exec_cmd(cmd_str)
@@ -1335,15 +1452,24 @@ ARGS = {arguments}\n'''.format(
return cmd
- def execute_script(self, script, extension="py", pre_dir=""):
+ def execute_script(self, script, extension="py", pre_dir="", script_args=None):
"""
execute a script on the minion then delete
"""
+ args = ""
+ if script_args:
+ args = " {}".format(
+ " ".join([str(el) for el in script_args])
+ if isinstance(script_args, (list, tuple))
+ else script_args
+ )
if extension == "ps1":
ret = self.shell.exec_cmd('"powershell {}"'.format(script))
else:
if not self.winrm:
- ret = self.shell.exec_cmd("/bin/sh '{}{}'".format(pre_dir, script))
+ ret = self.shell.exec_cmd(
+ "/bin/sh '{}{}'{}".format(pre_dir, script, args)
+ )
else:
ret = saltwinshell.call_python(self, script)
diff --git a/salt/client/ssh/client.py b/salt/client/ssh/client.py
index 245e1529c6..a45deeb325 100644
index be9247cb15..0b67598fc6 100644
--- a/salt/client/ssh/client.py
+++ b/salt/client/ssh/client.py
@@ -107,7 +107,7 @@ class SSHClient:
@@ -108,7 +108,7 @@ class SSHClient:
return sane_kwargs
def _prep_ssh(
@ -521,7 +472,7 @@ index 245e1529c6..a45deeb325 100644
):
"""
Prepare the arguments
@@ -122,7 +122,7 @@ class SSHClient:
@@ -123,7 +123,7 @@ class SSHClient:
opts["selected_target_option"] = tgt_type
opts["tgt"] = tgt
opts["arg"] = arg
@ -530,7 +481,7 @@ index 245e1529c6..a45deeb325 100644
def cmd_iter(
self,
@@ -159,7 +159,7 @@ class SSHClient:
@@ -160,7 +160,7 @@ class SSHClient:
final.update(ret)
return final
@ -539,7 +490,7 @@ index 245e1529c6..a45deeb325 100644
"""
Execute a salt-ssh call synchronously.
@@ -192,6 +192,7 @@ class SSHClient:
@@ -193,6 +193,7 @@ class SSHClient:
low.get("timeout"),
low.get("tgt_type"),
low.get("kwarg"),
@ -548,10 +499,10 @@ index 245e1529c6..a45deeb325 100644
)
diff --git a/salt/client/ssh/shell.py b/salt/client/ssh/shell.py
index 7461618a2e..6b54a20abd 100644
index cfa82d13c2..bc1ad034df 100644
--- a/salt/client/ssh/shell.py
+++ b/salt/client/ssh/shell.py
@@ -442,6 +442,14 @@ class Shell:
@@ -464,6 +464,14 @@ class Shell:
if stdout:
old_stdout = stdout
time.sleep(0.01)
@ -699,10 +650,10 @@ index b77749f495..293ea1b7fa 100644
"--local",
"--metadata",
diff --git a/salt/loader/__init__.py b/salt/loader/__init__.py
index f7815acc03..a0f2220476 100644
index 72a5e54401..32f8a7702c 100644
--- a/salt/loader/__init__.py
+++ b/salt/loader/__init__.py
@@ -8,6 +8,7 @@ import contextlib
@@ -9,6 +9,7 @@ import inspect
import logging
import os
import re
@ -738,14 +689,18 @@ index f7815acc03..a0f2220476 100644
def static_loader(
opts,
@@ -597,16 +610,19 @@ def fileserver(opts, backends):
@@ -725,7 +738,7 @@ def fileserver(opts, backends, loaded_base_name=None):
)
-def roster(opts, runner=None, utils=None, whitelist=None):
+def roster(opts, runner=None, utils=None, whitelist=None, context=None):
-def roster(opts, runner=None, utils=None, whitelist=None, loaded_base_name=None):
+def roster(opts, runner=None, utils=None, whitelist=None, loaded_base_name=None, context=None):
"""
Returns the roster modules
@@ -736,12 +749,15 @@ def roster(opts, runner=None, utils=None, whitelist=None, loaded_base_name=None)
:param str loaded_base_name: The imported modules namespace when imported
by the salt loader.
"""
+ if context is None:
+ context = {}
@ -758,9 +713,9 @@ index f7815acc03..a0f2220476 100644
- pack={"__runner__": runner, "__utils__": utils},
+ pack={"__runner__": runner, "__utils__": utils, "__context__": context},
extra_module_dirs=utils.module_dirs if utils else None,
loaded_base_name=loaded_base_name,
)
@@ -744,7 +760,14 @@ def render(opts, functions, states=None, proxy=None, context=None):
@@ -933,7 +949,14 @@ def render(
)
rend = FilterDictWrapper(ret, ".render")
@ -777,10 +732,10 @@ index f7815acc03..a0f2220476 100644
):
err = (
diff --git a/salt/netapi/__init__.py b/salt/netapi/__init__.py
index 81954acb96..5d2ff994a6 100644
index 7127dc2b3c..4a80697648 100644
--- a/salt/netapi/__init__.py
+++ b/salt/netapi/__init__.py
@@ -46,6 +46,7 @@ class NetapiClient:
@@ -79,6 +79,7 @@ class NetapiClient:
self.loadauth = salt.auth.LoadAuth(apiopts)
self.key = salt.daemons.masterapi.access_keys(apiopts)
self.ckminions = salt.utils.minions.CkMinions(apiopts)
@ -788,7 +743,7 @@ index 81954acb96..5d2ff994a6 100644
def _is_master_running(self):
"""
@@ -205,7 +206,7 @@ class NetapiClient:
@@ -238,7 +239,7 @@ class NetapiClient:
with salt.client.ssh.client.SSHClient(
mopts=self.opts, disable_custom_roster=True
) as client:
@ -798,7 +753,7 @@ index 81954acb96..5d2ff994a6 100644
def runner(self, fun, timeout=None, full_return=False, **kwargs):
"""
diff --git a/salt/roster/__init__.py b/salt/roster/__init__.py
index b45afffd24..4b6182b2dd 100644
index fc7339d785..ea23d550d7 100644
--- a/salt/roster/__init__.py
+++ b/salt/roster/__init__.py
@@ -59,7 +59,7 @@ class Roster:
@ -822,7 +777,7 @@ index b45afffd24..4b6182b2dd 100644
def _gen_back(self):
"""
diff --git a/tests/unit/test_loader.py b/tests/unit/test_loader.py
index 2319f815d3..e83f86cd01 100644
index 66ba3d4e05..412d412398 100644
--- a/tests/unit/test_loader.py
+++ b/tests/unit/test_loader.py
@@ -1696,7 +1696,7 @@ class LazyLoaderRefreshFileMappingTest(TestCase):
@ -835,6 +790,6 @@ index 2319f815d3..e83f86cd01 100644
self.LOADER_CLASS = LazyLoaderMock
--
2.35.1
2.37.3

View File

@ -1,4 +1,4 @@
From aafa76ddd04114f699d760577681db75579685d7 Mon Sep 17 00:00:00 2001
From b772fc7540cea4088ecac0bdc0e24d2be84bfcad 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 4da665a130..dacff1e0a9 100644
index 16452facf4..780b397e83 100644
--- a/salt/minion.py
+++ b/salt/minion.py
@@ -1123,6 +1123,9 @@ class MinionManager(MinionBase):
@ -25,7 +25,7 @@ index 4da665a130..dacff1e0a9 100644
while True:
try:
if minion.opts.get("beacons_before_connect", False):
@@ -1158,6 +1161,9 @@ class MinionManager(MinionBase):
@@ -1161,6 +1164,9 @@ class MinionManager(MinionBase):
minion.opts["master"],
exc_info=True,
)
@ -36,6 +36,6 @@ index 4da665a130..dacff1e0a9 100644
# Multi Master Tune In
def tune_in(self):
--
2.29.2
2.37.3

View File

@ -1,9 +1,9 @@
From 8ad65d6fa39edc7fc1967e2df1f3db0aa7df4d11 Mon Sep 17 00:00:00 2001
From 875fb95ae468042005cd0db463f13a9315c1e756 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
Subject: [PATCH] Add standalone configuration file for enabling
package formulas
Subject: [PATCH] Add standalone configuration file for enabling package
formulas
---
conf/suse/standalone-formulas-configuration.conf | 4 ++++
@ -21,6 +21,6 @@ index 0000000000..94d05fb2ee
+ - /usr/share/salt-formulas/states
+ - /srv/salt
--
2.29.2
2.37.3

View File

@ -1,4 +1,4 @@
From fbd5163bd0d5409a1823e9fb8e0cb623c22d6036 Mon Sep 17 00:00:00 2001
From f92891c007ee55d9ccc2d7b3da53e4e0a6fc94c3 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 39d26f0e93..b622105e15 100644
index cbfbc4b78d..2c36e2968a 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -591,7 +591,7 @@ def list_upgrades(refresh=True, root=None, **kwargs):
@@ -589,7 +589,7 @@ def list_upgrades(refresh=True, root=None, **kwargs):
salt '*' pkg.list_upgrades
"""
if refresh:
@ -30,7 +30,7 @@ index 39d26f0e93..b622105e15 100644
ret = dict()
cmd = ["list-updates"]
@@ -705,7 +705,7 @@ def info_available(*names, **kwargs):
@@ -703,7 +703,7 @@ def info_available(*names, **kwargs):
# Refresh db before extracting the latest package
if kwargs.get("refresh", True):
@ -39,7 +39,7 @@ index 39d26f0e93..b622105e15 100644
pkg_info = []
batch = names[:]
@@ -1395,7 +1395,6 @@ def mod_repo(repo, **kwargs):
@@ -1393,7 +1393,6 @@ def mod_repo(repo, **kwargs):
cmd_opt.append("--name='{}'".format(kwargs.get("humanname")))
if kwargs.get("gpgautoimport") is True:
@ -47,7 +47,7 @@ index 39d26f0e93..b622105e15 100644
call_refresh = True
if cmd_opt:
@@ -1407,8 +1406,8 @@ def mod_repo(repo, **kwargs):
@@ -1405,8 +1404,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 39d26f0e93..b622105e15 100644
elif not added and not cmd_opt:
comment = "Specified arguments did not result in modification of repo"
@@ -1419,7 +1418,7 @@ def mod_repo(repo, **kwargs):
@@ -1417,7 +1416,7 @@ def mod_repo(repo, **kwargs):
return repo
@ -67,7 +67,7 @@ index 39d26f0e93..b622105e15 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
@@ -1430,6 +1429,17 @@ def refresh_db(force=None, root=None):
@@ -1428,6 +1427,17 @@ def refresh_db(force=None, root=None):
{'<database name>': Bool}
@ -85,7 +85,7 @@ index 39d26f0e93..b622105e15 100644
root
operate on a different root directory.
@@ -1450,11 +1460,22 @@ def refresh_db(force=None, root=None):
@@ -1448,11 +1458,22 @@ def refresh_db(force=None, root=None):
salt.utils.pkg.clear_rtag(__opts__)
ret = {}
refresh_opts = ["refresh"]
@ -109,7 +109,7 @@ index 39d26f0e93..b622105e15 100644
for line in out.splitlines():
if not line:
@@ -1639,7 +1660,7 @@ def install(
@@ -1637,7 +1658,7 @@ def install(
'arch': '<new-arch>'}}}
"""
if refresh:
@ -118,7 +118,7 @@ index 39d26f0e93..b622105e15 100644
try:
pkg_params, pkg_type = __salt__["pkg_resource.parse_targets"](
@@ -1934,7 +1955,7 @@ def upgrade(
@@ -1932,7 +1953,7 @@ def upgrade(
cmd_update.insert(0, "--no-gpg-checks")
if refresh:
@ -127,7 +127,7 @@ index 39d26f0e93..b622105e15 100644
if dryrun:
cmd_update.append("--dry-run")
@@ -2844,7 +2865,7 @@ def search(criteria, refresh=False, **kwargs):
@@ -2759,7 +2780,7 @@ def search(criteria, refresh=False, **kwargs):
root = kwargs.get("root", None)
if refresh:
@ -136,7 +136,7 @@ index 39d26f0e93..b622105e15 100644
cmd = ["search"]
if kwargs.get("match") == "exact":
@@ -2995,7 +3016,7 @@ def download(*packages, **kwargs):
@@ -2910,7 +2931,7 @@ def download(*packages, **kwargs):
refresh = kwargs.get("refresh", False)
if refresh:
@ -145,7 +145,7 @@ index 39d26f0e93..b622105e15 100644
pkg_ret = {}
for dld_result in (
@@ -3147,7 +3168,7 @@ def list_patches(refresh=False, root=None, **kwargs):
@@ -3062,7 +3083,7 @@ def list_patches(refresh=False, root=None, **kwargs):
salt '*' pkg.list_patches
"""
if refresh:
@ -154,7 +154,7 @@ index 39d26f0e93..b622105e15 100644
return _get_patches(root=root)
@@ -3241,7 +3262,7 @@ def resolve_capabilities(pkgs, refresh=False, root=None, **kwargs):
@@ -3156,7 +3177,7 @@ def resolve_capabilities(pkgs, refresh=False, root=None, **kwargs):
salt '*' pkg.resolve_capabilities resolve_capabilities=True w3m_ssl
"""
if refresh:
@ -364,6 +364,6 @@ index fea6eeb004..3f1560a385 100644
def test_wildcard_to_query_match_all(self):
--
2.36.1
2.37.3

View File

@ -1,8 +1,8 @@
From c162e36fc52ca2f10b25354f1e430e13113f2976 Mon Sep 17 00:00:00 2001
From 0165c300ec0f7ac70b274b81a8857c2e6d71552d Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Thu, 7 Jul 2022 11:26:34 +0200
Subject: [PATCH] Add support for name, pkgs and diff_attr parameters
to zypperpkg.upgrade()/yumpkg.upgrade() - backport 3004 (#538)
Subject: [PATCH] Add support for name, pkgs and diff_attr parameters to
zypperpkg.upgrade()/yumpkg.upgrade() - backport 3004 (#538)
* Migrate zypper.upgrade tests to pytest
@ -37,9 +37,9 @@ Fixes: https://github.com/saltstack/salt/issues/62031
changelog/62032.fixed | 1 +
salt/modules/yumpkg.py | 7 +-
salt/modules/zypperpkg.py | 76 ++-
tests/pytests/unit/modules/test_zypperpkg.py | 278 ++++++++++-
tests/pytests/unit/modules/test_zypperpkg.py | 277 ++++++++++-
tests/unit/modules/test_zypperpkg.py | 482 -------------------
7 files changed, 356 insertions(+), 490 deletions(-)
7 files changed, 355 insertions(+), 490 deletions(-)
create mode 100644 changelog/62030.fixed
create mode 100644 changelog/62031.added
create mode 100644 changelog/62032.fixed
@ -66,7 +66,7 @@ index 0000000000..ceb3cc89b9
@@ -0,0 +1 @@
+Fix attr=all handling in pkg.list_pkgs() (yum/zypper).
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
index 3138ac2e59..0013282507 100644
index f52e084346..fcfc5d4045 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -735,7 +735,7 @@ def list_pkgs(versions_as_list=False, **kwargs):
@ -78,7 +78,7 @@ index 3138ac2e59..0013282507 100644
attr = salt.utils.args.split_input(attr)
contextkey = "pkg.list_pkgs"
@@ -1835,6 +1835,7 @@ def upgrade(
@@ -1844,6 +1844,7 @@ def upgrade(
normalize=True,
minimal=False,
obsoletes=True,
@ -86,7 +86,7 @@ index 3138ac2e59..0013282507 100644
**kwargs
):
"""
@@ -1991,7 +1992,7 @@ def upgrade(
@@ -2000,7 +2001,7 @@ def upgrade(
if salt.utils.data.is_true(refresh):
refresh_db(**kwargs)
@ -95,7 +95,7 @@ index 3138ac2e59..0013282507 100644
targets = []
if name or pkgs:
@@ -2023,7 +2024,7 @@ def upgrade(
@@ -2032,7 +2033,7 @@ def upgrade(
cmd.extend(targets)
result = _call_yum(cmd)
__context__.pop("pkg.list_pkgs", None)
@ -105,10 +105,10 @@ index 3138ac2e59..0013282507 100644
if result["retcode"] != 0:
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index ac6c36a09f..39d26f0e93 100644
index 4e3006a8cd..cbfbc4b78d 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -941,7 +941,7 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs):
@@ -939,7 +939,7 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs):
return {}
attr = kwargs.get("attr")
@ -117,7 +117,7 @@ index ac6c36a09f..39d26f0e93 100644
attr = salt.utils.args.split_input(attr)
includes = includes if includes else []
@@ -1793,6 +1793,8 @@ def install(
@@ -1791,6 +1791,8 @@ def install(
def upgrade(
@ -126,7 +126,7 @@ index ac6c36a09f..39d26f0e93 100644
refresh=True,
dryrun=False,
dist_upgrade=False,
@@ -1802,6 +1804,7 @@ def upgrade(
@@ -1800,6 +1802,7 @@ def upgrade(
skip_verify=False,
no_recommends=False,
root=None,
@ -134,7 +134,7 @@ index ac6c36a09f..39d26f0e93 100644
**kwargs
): # pylint: disable=unused-argument
"""
@@ -1821,6 +1824,27 @@ def upgrade(
@@ -1819,6 +1822,27 @@ def upgrade(
Run a full system upgrade, a zypper upgrade
@ -162,7 +162,7 @@ index ac6c36a09f..39d26f0e93 100644
refresh
force a refresh if set to True (default).
If set to False it depends on zypper if a refresh is
@@ -1852,6 +1876,24 @@ def upgrade(
@@ -1850,6 +1874,24 @@ def upgrade(
root
Operate on a different root directory.
@ -187,7 +187,7 @@ index ac6c36a09f..39d26f0e93 100644
Returns a dictionary containing the changes:
.. code-block:: python
@@ -1859,11 +1901,27 @@ def upgrade(
@@ -1857,11 +1899,27 @@ def upgrade(
{'<package>': {'old': '<old-version>',
'new': '<new-version>'}}
@ -215,7 +215,7 @@ index ac6c36a09f..39d26f0e93 100644
salt '*' pkg.upgrade dist_upgrade=True fromrepo='["MyRepoName"]' novendorchange=True
salt '*' pkg.upgrade dist_upgrade=True dryrun=True
"""
@@ -1899,12 +1957,24 @@ def upgrade(
@@ -1897,12 +1955,24 @@ def upgrade(
allowvendorchange, novendorchange
).noraise.call(*cmd_update + ["--debug-solver"])
@ -243,7 +243,7 @@ index ac6c36a09f..39d26f0e93 100644
if __zypper__.exit_code not in __zypper__.SUCCESS_EXIT_CODES:
diff --git a/tests/pytests/unit/modules/test_zypperpkg.py b/tests/pytests/unit/modules/test_zypperpkg.py
index bfc1558c9a..e02bba9a07 100644
index 351a173b81..84dc7a10b4 100644
--- a/tests/pytests/unit/modules/test_zypperpkg.py
+++ b/tests/pytests/unit/modules/test_zypperpkg.py
@@ -4,17 +4,31 @@
@ -280,11 +280,10 @@ index bfc1558c9a..e02bba9a07 100644
def test_list_pkgs_no_context():
@@ -254,3 +268,263 @@ def test_pkg_list_holds():
ret = zypper.list_holds()
assert len(ret) == 1
assert "bar-2:2.3.4-2.1.*" in ret
+
@@ -254,3 +268,262 @@ 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",
@ -1052,6 +1051,6 @@ index 39f28f2198..fea6eeb004 100644
"""
Test whether or not an upgrade is available for a given package.
--
2.36.1
2.37.3

View File

@ -1,32 +0,0 @@
From 3beb3379dafe1adf9c1a43694f7b71938be3f583 Mon Sep 17 00:00:00 2001
From: Jochen Breuer <jbreuer@suse.de>
Date: Wed, 1 Apr 2020 16:13:23 +0200
Subject: [PATCH] Adds explicit type cast for port
If a port was passed as a string, the execution logic was broken
and a wrong set of remotes was returned.
The type casting to int solves this issue.
---
salt/utils/network.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/salt/utils/network.py b/salt/utils/network.py
index 5fc9a34ca4..0dd20c5599 100644
--- a/salt/utils/network.py
+++ b/salt/utils/network.py
@@ -1703,6 +1703,10 @@ def _netlink_tool_remote_on(port, which_end):
chunks = line.split()
remote_host, remote_port = chunks[4].rsplit(":", 1)
+ if which_end == "remote_port" and int(remote_port) != int(port):
+ continue
+ if which_end == "local_port" and int(local_port) != int(port):
+ continue
remotes.add(remote_host.strip("[]"))
if valid is False:
--
2.33.0

View File

@ -0,0 +1,124 @@
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

@ -0,0 +1,151 @@
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 07d1b742f16799d3df9d7eeb04bbce5d814e519d Mon Sep 17 00:00:00 2001
From 51836a4c37f05262e708f058f323c1fbc2123ade 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
@ -64,7 +64,7 @@ Co-authored-by: Pablo Suárez Hernández <psuarezhernandez@suse.com>
2 files changed, 462 insertions(+), 61 deletions(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index 1777bec031..7216e25b86 100644
index 6b19c65db3..c2452d6dec 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -35,6 +35,8 @@ import salt.utils.stringutils
@ -76,7 +76,7 @@ index 1777bec031..7216e25b86 100644
from salt.utils.versions import LooseVersion
log = logging.getLogger(__name__)
@@ -128,6 +130,13 @@ class _Zypper:
@@ -135,6 +137,13 @@ class _Zypper:
self.__systemd_scope = False
self.__root = None
@ -90,7 +90,7 @@ index 1777bec031..7216e25b86 100644
# Call status
self.__called = False
@@ -172,6 +181,8 @@ class _Zypper:
@@ -179,6 +188,8 @@ class _Zypper:
self.__no_raise = True
elif item == "refreshable":
self.__refresh = True
@ -99,7 +99,7 @@ index 1777bec031..7216e25b86 100644
elif item == "call":
return self.__call
else:
@@ -212,6 +223,33 @@ class _Zypper:
@@ -219,6 +230,33 @@ class _Zypper:
def pid(self):
return self.__call_result.get("pid", "")
@ -133,7 +133,7 @@ index 1777bec031..7216e25b86 100644
def _is_error(self):
"""
Is this is an error code?
@@ -326,6 +364,15 @@ class _Zypper:
@@ -335,6 +373,15 @@ class _Zypper:
if self.__systemd_scope:
cmd.extend(["systemd-run", "--scope"])
cmd.extend(self.__cmd)
@ -149,7 +149,7 @@ index 1777bec031..7216e25b86 100644
log.debug("Calling Zypper: %s", " ".join(cmd))
self.__call_result = __salt__["cmd.run_all"](cmd, **kwargs)
if self._check_result():
@@ -1435,6 +1482,8 @@ def install(
@@ -1444,6 +1491,8 @@ def install(
no_recommends=False,
root=None,
inclusion_detection=False,
@ -158,7 +158,7 @@ index 1777bec031..7216e25b86 100644
**kwargs
):
"""
@@ -1482,6 +1531,13 @@ def install(
@@ -1491,6 +1540,13 @@ def install(
skip_verify
Skip the GPG verification check (e.g., ``--no-gpg-checks``)
@ -172,7 +172,7 @@ index 1777bec031..7216e25b86 100644
version
Can be either a version number, or the combination of a comparison
operator (<, >, <=, >=, =) and a version number (ex. '>1.2.3-4').
@@ -1647,6 +1703,7 @@ def install(
@@ -1656,6 +1712,7 @@ def install(
cmd_install.append(
kwargs.get("resolve_capabilities") and "--capability" or "--name"
)
@ -180,7 +180,7 @@ index 1777bec031..7216e25b86 100644
if not refresh:
cmd_install.insert(0, "--no-refresh")
@@ -1683,6 +1740,7 @@ def install(
@@ -1692,6 +1749,7 @@ def install(
systemd_scope=systemd_scope,
root=root,
)
@ -188,7 +188,7 @@ index 1777bec031..7216e25b86 100644
.call(*cmd)
.splitlines()
):
@@ -1695,7 +1753,9 @@ def install(
@@ -1704,7 +1762,9 @@ def install(
while downgrades:
cmd = cmd_install + ["--force"] + downgrades[:500]
downgrades = downgrades[500:]
@ -199,7 +199,7 @@ index 1777bec031..7216e25b86 100644
_clean_cache()
new = (
@@ -1726,7 +1786,8 @@ def upgrade(
@@ -1735,7 +1795,8 @@ def upgrade(
dryrun=False,
dist_upgrade=False,
fromrepo=None,
@ -209,7 +209,7 @@ index 1777bec031..7216e25b86 100644
skip_verify=False,
no_recommends=False,
root=None,
@@ -1765,7 +1826,11 @@ def upgrade(
@@ -1774,7 +1835,11 @@ def upgrade(
Specify a list of package repositories to upgrade from. Default: None
novendorchange
@ -222,7 +222,7 @@ index 1777bec031..7216e25b86 100644
skip_verify
Skip the GPG verification check (e.g., ``--no-gpg-checks``)
@@ -1812,31 +1877,21 @@ def upgrade(
@@ -1821,31 +1886,21 @@ def upgrade(
cmd_update.extend(["--from" if dist_upgrade else "--repo", repo])
log.info("Targeting repos: %s", fromrepo)
@ -267,10 +267,10 @@ index 1777bec031..7216e25b86 100644
new = list_pkgs(root=root)
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 0ba5595d65..78fe226914 100644
index 671adc2779..39f28f2198 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -137,6 +137,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -135,6 +135,7 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
stdout_xml_snippet = '<?xml version="1.0"?><test foo="bar"/>'
sniffer = RunSniffer(stdout=stdout_xml_snippet)
@ -278,7 +278,7 @@ index 0ba5595d65..78fe226914 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)
@@ -592,13 +593,373 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -609,13 +610,373 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
{"vim": "7.4.326-2.62", "fakepkg": ""},
)
@ -653,7 +653,7 @@ index 0ba5595d65..78fe226914 100644
"salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)
), patch(
"salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False)
@@ -637,16 +998,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -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")
@ -670,7 +670,7 @@ index 0ba5595d65..78fe226914 100644
with patch(
"salt.modules.zypperpkg.list_pkgs",
MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
@@ -662,6 +1013,22 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -679,6 +1030,22 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
"--debug-solver",
)
@ -693,7 +693,7 @@ index 0ba5595d65..78fe226914 100644
with patch(
"salt.modules.zypperpkg.list_pkgs",
MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
@@ -680,7 +1047,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -697,7 +1064,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
"Dummy",
"--from",
"Dummy2",
@ -701,7 +701,7 @@ index 0ba5595d65..78fe226914 100644
)
zypper_mock.assert_any_call(
"dist-upgrade",
@@ -690,7 +1056,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -707,7 +1073,6 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
"Dummy",
"--from",
"Dummy2",
@ -709,7 +709,7 @@ index 0ba5595d65..78fe226914 100644
"--debug-solver",
)
@@ -710,33 +1075,13 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
@@ -727,33 +1092,13 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
"Dummy2",
)
@ -744,7 +744,7 @@ index 0ba5595d65..78fe226914 100644
"salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)
), patch(
"salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False)
@@ -795,12 +1140,13 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -812,12 +1157,13 @@ Repository 'DUMMY' not found by its alias, number, or URI.
self.pid = 1234
self.exit_code = 555
self.noraise = MagicMock()
@ -759,7 +759,7 @@ index 0ba5595d65..78fe226914 100644
"salt.modules.zypperpkg.__zypper__", FailingZypperDummy()
) as zypper_mock, patch(
"salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)
@@ -817,7 +1163,7 @@ Repository 'DUMMY' not found by its alias, number, or URI.
@@ -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(
@ -769,6 +769,6 @@ index 0ba5595d65..78fe226914 100644
def test_upgrade_available(self):
--
2.33.0
2.37.3

View File

@ -1,4 +1,4 @@
From c25ee8158000770cb667b914de62f802467c204e Mon Sep 17 00:00:00 2001
From f16fb8885eeddad179be9e2290d1523cb8f82641 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,20 +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/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 +++++++++++++++++++++++++++++
8 files changed, 839 insertions(+), 61 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 | 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(-)
create mode 100644 salt/cli/batch_async.py
create mode 100644 tests/unit/cli/test_batch_async.py
diff --git a/salt/auth/__init__.py b/salt/auth/__init__.py
index 3b73c2ec08..6f300fe7c4 100644
index 0c64755235..8dc096d9c5 100644
--- a/salt/auth/__init__.py
+++ b/salt/auth/__init__.py
@@ -49,6 +49,8 @@ AUTH_INTERNAL_KEYWORDS = frozenset(
@ -97,7 +98,7 @@ index 3b73c2ec08..6f300fe7c4 100644
)
diff --git a/salt/cli/batch.py b/salt/cli/batch.py
index 2a692e13f8..828a1ded5b 100644
index 8e1547c61d..fcd3f571d5 100644
--- a/salt/cli/batch.py
+++ b/salt/cli/batch.py
@@ -13,9 +13,88 @@ import salt.exceptions
@ -568,11 +569,22 @@ index 0000000000..09aa85258b
+ self.event = None
+ self.ioloop = None
+ gc.collect()
diff --git a/salt/cli/support/profiles/__init__.py b/salt/cli/support/profiles/__init__.py
index b86aef30b8..4ae6d07b13 100644
--- a/salt/cli/support/profiles/__init__.py
+++ b/salt/cli/support/profiles/__init__.py
@@ -1,4 +1,3 @@
-# coding=utf-8
-'''
+"""
Profiles for salt-support.
-'''
+"""
diff --git a/salt/client/__init__.py b/salt/client/__init__.py
index 8ea8818d01..482d3ac7bd 100644
index eaf156e060..2427516ca1 100644
--- a/salt/client/__init__.py
+++ b/salt/client/__init__.py
@@ -584,47 +584,23 @@ class LocalClient:
@@ -586,47 +586,23 @@ class LocalClient:
{'dave': {...}}
{'stewart': {...}}
"""
@ -631,9 +643,9 @@ index 8ea8818d01..482d3ac7bd 100644
- if key not in opts:
- opts[key] = val
batch = salt.cli.batch.Batch(opts, eauth=eauth, quiet=True)
for ret in batch.run():
for ret, _ in batch.run():
yield ret
@@ -1812,6 +1788,7 @@ class LocalClient:
@@ -1819,6 +1795,7 @@ class LocalClient:
"key": self.key,
"tgt_type": tgt_type,
"ret": ret,
@ -642,18 +654,18 @@ index 8ea8818d01..482d3ac7bd 100644
}
diff --git a/salt/master.py b/salt/master.py
index 37fe52159f..795aeef647 100644
index 9c06a52c1c..705a1bc2fb 100644
--- a/salt/master.py
+++ b/salt/master.py
@@ -19,6 +19,7 @@ import time
import salt.acl
import salt.auth
import salt.channel.server
+import salt.cli.batch_async
import salt.client
import salt.client.ssh.client
import salt.crypt
@@ -2167,6 +2168,22 @@ class ClearFuncs(TransportMethods):
@@ -2145,6 +2146,22 @@ class ClearFuncs(TransportMethods):
return False
return self.loadauth.get_tok(clear_load["token"])
@ -676,7 +688,7 @@ index 37fe52159f..795aeef647 100644
def publish(self, clear_load):
"""
This method sends out publications to the minions, it can only be used
@@ -2284,6 +2301,9 @@ class ClearFuncs(TransportMethods):
@@ -2264,6 +2281,9 @@ class ClearFuncs(TransportMethods):
),
},
}
@ -687,10 +699,10 @@ index 37fe52159f..795aeef647 100644
if jid is None:
return {"enc": "clear", "load": {"error": "Master failed to assign jid"}}
diff --git a/salt/transport/ipc.py b/salt/transport/ipc.py
index 29210d7522..3f430ba796 100644
index ca13a498e3..3a3f0c7a5f 100644
--- a/salt/transport/ipc.py
+++ b/salt/transport/ipc.py
@@ -650,6 +650,7 @@ class IPCMessageSubscriber(IPCClient):
@@ -659,6 +659,7 @@ class IPCMessageSubscriber(IPCClient):
self._read_stream_future = None
self._saved_data = []
self._read_in_progress = Lock()
@ -698,7 +710,7 @@ index 29210d7522..3f430ba796 100644
@salt.ext.tornado.gen.coroutine
def _read(self, timeout, callback=None):
@@ -749,8 +750,12 @@ class IPCMessageSubscriber(IPCClient):
@@ -764,8 +765,12 @@ class IPCMessageSubscriber(IPCClient):
return self._saved_data.pop(0)
return self.io_loop.run_sync(lambda: self._read(timeout))
@ -712,7 +724,7 @@ index 29210d7522..3f430ba796 100644
"""
Asynchronously read messages and invoke a callback when they are ready.
@@ -768,7 +773,7 @@ class IPCMessageSubscriber(IPCClient):
@@ -783,7 +788,7 @@ class IPCMessageSubscriber(IPCClient):
except Exception as exc: # pylint: disable=broad-except
log.error("Exception occurred while Subscriber connecting: %s", exc)
yield salt.ext.tornado.gen.sleep(1)
@ -722,10 +734,10 @@ index 29210d7522..3f430ba796 100644
def close(self):
"""
diff --git a/salt/utils/event.py b/salt/utils/event.py
index 3c91daa2b4..fd23197747 100644
index d14b9ada40..e8d1aaa5f5 100644
--- a/salt/utils/event.py
+++ b/salt/utils/event.py
@@ -920,6 +920,10 @@ class SaltEvent:
@@ -944,6 +944,10 @@ class SaltEvent:
# Minion fired a bad retcode, fire an event
self._fire_ret_load_specific_fun(load)
@ -736,7 +748,7 @@ index 3c91daa2b4..fd23197747 100644
def set_event_handler(self, event_handler):
"""
Invoke the event_handler callback each time an event arrives.
@@ -928,8 +932,10 @@ class SaltEvent:
@@ -952,8 +956,10 @@ class SaltEvent:
if not self.cpub:
self.connect_pub()
@ -1141,6 +1153,6 @@ index 0000000000..c0b708de76
+ self.batch.schedule_next()
+ self.assertEqual(len(self.batch.event.io_loop.spawn_callback.mock_calls), 0)
--
2.33.0
2.37.3

View File

@ -1,4 +1,4 @@
From 3c83bab3da101223c99af1f9ee2f3bf5e97be3f8 Mon Sep 17 00:00:00 2001
From 100bf2d977c15fda21de7d1d5da2f2c61bed2afd 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)
@ -21,6 +21,6 @@ index 2e418094ed..73a91ebd62 100755
/usr/bin/salt-daemon-watcher --with-init & disown
fi
--
2.29.2
2.37.3

View File

@ -1,355 +0,0 @@
From 54ab69e74beb83710d0bf6049039d13e260d5517 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 13 Sep 2022 11:26:21 +0200
Subject: [PATCH] Backport Syndic auth fixes
[3004.2] Syndic Fixes
(cherry picked from commit 643bd4b572ca97466e085ecd1d84da45b1684332)
Co-authored-by: Megan Wilhite <megan.wilhite@gmail.com>
---
changelog/61868.fixed | 1 +
salt/transport/mixins/auth.py | 2 +-
salt/transport/tcp.py | 2 +-
salt/transport/zeromq.py | 2 +-
tests/pytests/unit/transport/test_tcp.py | 149 +++++++++++++++++++-
tests/pytests/unit/transport/test_zeromq.py | 73 +++++++++-
6 files changed, 224 insertions(+), 5 deletions(-)
create mode 100644 changelog/61868.fixed
diff --git a/changelog/61868.fixed b/changelog/61868.fixed
new file mode 100644
index 0000000000..0169c48e99
--- /dev/null
+++ b/changelog/61868.fixed
@@ -0,0 +1 @@
+Make sure the correct key is being used when verifying or validating communication, eg. when a Salt syndic is involved use syndic_master.pub and when a Salt minion is involved use minion_master.pub.
diff --git a/salt/transport/mixins/auth.py b/salt/transport/mixins/auth.py
index 1e2e8e6b7b..e5c6a5345f 100644
--- a/salt/transport/mixins/auth.py
+++ b/salt/transport/mixins/auth.py
@@ -43,7 +43,7 @@ class AESPubClientMixin:
)
# Verify that the signature is valid
- master_pubkey_path = os.path.join(self.opts["pki_dir"], "minion_master.pub")
+ master_pubkey_path = os.path.join(self.opts["pki_dir"], self.auth.mpub)
if not salt.crypt.verify_signature(
master_pubkey_path, payload["load"], payload.get("sig")
):
diff --git a/salt/transport/tcp.py b/salt/transport/tcp.py
index f00b3c40eb..2821be82c7 100644
--- a/salt/transport/tcp.py
+++ b/salt/transport/tcp.py
@@ -295,7 +295,7 @@ class AsyncTCPReqChannel(salt.transport.client.ReqChannel):
signed_msg = pcrypt.loads(ret[dictkey])
# Validate the master's signature.
- master_pubkey_path = os.path.join(self.opts["pki_dir"], "minion_master.pub")
+ master_pubkey_path = os.path.join(self.opts["pki_dir"], self.auth.mpub)
if not salt.crypt.verify_signature(
master_pubkey_path, signed_msg["data"], signed_msg["sig"]
):
diff --git a/salt/transport/zeromq.py b/salt/transport/zeromq.py
index aa06298ee1..8199378239 100644
--- a/salt/transport/zeromq.py
+++ b/salt/transport/zeromq.py
@@ -255,7 +255,7 @@ class AsyncZeroMQReqChannel(salt.transport.client.ReqChannel):
signed_msg = pcrypt.loads(ret[dictkey])
# Validate the master's signature.
- master_pubkey_path = os.path.join(self.opts["pki_dir"], "minion_master.pub")
+ master_pubkey_path = os.path.join(self.opts["pki_dir"], self.auth.mpub)
if not salt.crypt.verify_signature(
master_pubkey_path, signed_msg["data"], signed_msg["sig"]
):
diff --git a/tests/pytests/unit/transport/test_tcp.py b/tests/pytests/unit/transport/test_tcp.py
index 3b6e175472..e41edcc37e 100644
--- a/tests/pytests/unit/transport/test_tcp.py
+++ b/tests/pytests/unit/transport/test_tcp.py
@@ -1,13 +1,53 @@
import contextlib
+import os
import socket
import attr
import pytest
import salt.exceptions
+import salt.transport.mixins.auth
import salt.transport.tcp
from salt.ext.tornado import concurrent, gen, ioloop
from saltfactories.utils.ports import get_unused_localhost_port
-from tests.support.mock import MagicMock, patch
+from tests.support.mock import MagicMock, PropertyMock, create_autospec, patch
+
+
+@pytest.fixture
+def fake_keys():
+ with patch("salt.crypt.AsyncAuth.get_keys", autospec=True):
+ yield
+
+
+@pytest.fixture
+def fake_crypto():
+ with patch("salt.transport.tcp.PKCS1_OAEP", create=True) as fake_crypto:
+ yield fake_crypto
+
+
+@pytest.fixture
+def fake_authd():
+ @salt.ext.tornado.gen.coroutine
+ def return_nothing():
+ raise salt.ext.tornado.gen.Return()
+
+ with patch(
+ "salt.crypt.AsyncAuth.authenticated", new_callable=PropertyMock
+ ) as mock_authed, patch(
+ "salt.crypt.AsyncAuth.authenticate",
+ autospec=True,
+ return_value=return_nothing(),
+ ), patch(
+ "salt.crypt.AsyncAuth.gen_token", autospec=True, return_value=42
+ ):
+ mock_authed.return_value = False
+ yield
+
+
+@pytest.fixture
+def fake_crypticle():
+ with patch("salt.crypt.Crypticle") as fake_crypticle:
+ fake_crypticle.generate_key_string.return_value = "fakey fake"
+ yield fake_crypticle
@pytest.fixture
@@ -405,3 +445,110 @@ def test_client_reconnect_backoff(client_socket):
client.io_loop.run_sync(client._connect)
finally:
client.close()
+
+
+async def test_when_async_req_channel_with_syndic_role_should_use_syndic_master_pub_file_to_verify_master_sig(
+ fake_keys, fake_crypto, fake_crypticle
+):
+ # Syndics use the minion pki dir, but they also create a syndic_master.pub
+ # file for comms with the Salt master
+ expected_pubkey_path = os.path.join("/etc/salt/pki/minion", "syndic_master.pub")
+ fake_crypto.new.return_value.decrypt.return_value = "decrypted_return_value"
+ mockloop = MagicMock()
+ opts = {
+ "master_uri": "tcp://127.0.0.1:4506",
+ "interface": "127.0.0.1",
+ "ret_port": 4506,
+ "ipv6": False,
+ "sock_dir": ".",
+ "pki_dir": "/etc/salt/pki/minion",
+ "id": "syndic",
+ "__role": "syndic",
+ "keysize": 4096,
+ }
+ client = salt.transport.tcp.AsyncTCPReqChannel(opts, io_loop=mockloop)
+
+ dictkey = "pillar"
+ target = "minion"
+
+ # Mock auth and message client.
+ client.auth._authenticate_future = MagicMock()
+ client.auth._authenticate_future.done.return_value = True
+ client.auth._authenticate_future.exception.return_value = None
+ client.auth._crypticle = MagicMock()
+ client.message_client = create_autospec(client.message_client)
+
+ @salt.ext.tornado.gen.coroutine
+ def mocksend(msg, timeout=60, tries=3):
+ raise salt.ext.tornado.gen.Return({"pillar": "data", "key": "value"})
+
+ client.message_client.send = mocksend
+
+ # Note the 'ver' value in 'load' does not represent the the 'version' sent
+ # in the top level of the transport's message.
+ load = {
+ "id": target,
+ "grains": {},
+ "saltenv": "base",
+ "pillarenv": "base",
+ "pillar_override": True,
+ "extra_minion_data": {},
+ "ver": "2",
+ "cmd": "_pillar",
+ }
+ fake_nonce = 42
+ with patch(
+ "salt.crypt.verify_signature", autospec=True, return_value=True
+ ) as fake_verify, patch(
+ "salt.payload.loads",
+ autospec=True,
+ return_value={"key": "value", "nonce": fake_nonce, "pillar": "data"},
+ ), patch(
+ "uuid.uuid4", autospec=True
+ ) as fake_uuid:
+ fake_uuid.return_value.hex = fake_nonce
+ ret = await client.crypted_transfer_decode_dictentry(
+ load,
+ dictkey="pillar",
+ )
+
+ assert fake_verify.mock_calls[0].args[0] == expected_pubkey_path
+
+
+async def test_mixin_should_use_correct_path_when_syndic(
+ fake_keys, fake_authd, fake_crypticle
+):
+ mockloop = MagicMock()
+ expected_pubkey_path = os.path.join("/etc/salt/pki/minion", "syndic_master.pub")
+ opts = {
+ "master_uri": "tcp://127.0.0.1:4506",
+ "interface": "127.0.0.1",
+ "ret_port": 4506,
+ "ipv6": False,
+ "sock_dir": ".",
+ "pki_dir": "/etc/salt/pki/minion",
+ "id": "syndic",
+ "__role": "syndic",
+ "keysize": 4096,
+ "sign_pub_messages": True,
+ }
+
+ with patch(
+ "salt.crypt.verify_signature", autospec=True, return_value=True
+ ) as fake_verify, patch(
+ "salt.utils.msgpack.loads",
+ autospec=True,
+ return_value={"enc": "aes", "load": "", "sig": "fake_signature"},
+ ):
+ client = salt.transport.tcp.AsyncTCPPubChannel(opts, io_loop=mockloop)
+ client.message_client = MagicMock()
+ client.message_client.on_recv.side_effect = lambda x: x(b"some_data")
+ await client.connect()
+ client.auth._crypticle = fake_crypticle
+
+ @client.on_recv
+ def test_recv_function(*args, **kwargs):
+ ...
+
+ await test_recv_function
+ assert fake_verify.mock_calls[0].args[0] == expected_pubkey_path
diff --git a/tests/pytests/unit/transport/test_zeromq.py b/tests/pytests/unit/transport/test_zeromq.py
index 1f0515c91a..c3093f4b19 100644
--- a/tests/pytests/unit/transport/test_zeromq.py
+++ b/tests/pytests/unit/transport/test_zeromq.py
@@ -23,7 +23,7 @@ import salt.utils.process
import salt.utils.stringutils
from salt.master import SMaster
from salt.transport.zeromq import AsyncReqMessageClientPool
-from tests.support.mock import MagicMock, patch
+from tests.support.mock import MagicMock, create_autospec, patch
try:
from M2Crypto import RSA
@@ -608,6 +608,7 @@ async def test_req_chan_decode_data_dict_entry_v2(pki_dir):
auth = client.auth
auth._crypticle = salt.crypt.Crypticle(opts, AES_KEY)
client.auth = MagicMock()
+ client.auth.mpub = auth.mpub
client.auth.authenticated = True
client.auth.get_keys = auth.get_keys
client.auth.crypticle.dumps = auth.crypticle.dumps
@@ -672,6 +673,7 @@ async def test_req_chan_decode_data_dict_entry_v2_bad_nonce(pki_dir):
auth = client.auth
auth._crypticle = salt.crypt.Crypticle(opts, AES_KEY)
client.auth = MagicMock()
+ client.auth.mpub = auth.mpub
client.auth.authenticated = True
client.auth.get_keys = auth.get_keys
client.auth.crypticle.dumps = auth.crypticle.dumps
@@ -735,6 +737,7 @@ async def test_req_chan_decode_data_dict_entry_v2_bad_signature(pki_dir):
auth = client.auth
auth._crypticle = salt.crypt.Crypticle(opts, AES_KEY)
client.auth = MagicMock()
+ client.auth.mpub = auth.mpub
client.auth.authenticated = True
client.auth.get_keys = auth.get_keys
client.auth.crypticle.dumps = auth.crypticle.dumps
@@ -814,6 +817,7 @@ async def test_req_chan_decode_data_dict_entry_v2_bad_key(pki_dir):
auth = client.auth
auth._crypticle = salt.crypt.Crypticle(opts, AES_KEY)
client.auth = MagicMock()
+ client.auth.mpub = auth.mpub
client.auth.authenticated = True
client.auth.get_keys = auth.get_keys
client.auth.crypticle.dumps = auth.crypticle.dumps
@@ -1273,3 +1277,70 @@ async def test_req_chan_auth_v2_new_minion_without_master_pub(pki_dir, io_loop):
assert "sig" in ret
ret = client.auth.handle_signin_response(signin_payload, ret)
assert ret == "retry"
+
+
+async def test_when_async_req_channel_with_syndic_role_should_use_syndic_master_pub_file_to_verify_master_sig(
+ pki_dir,
+):
+ # Syndics use the minion pki dir, but they also create a syndic_master.pub
+ # file for comms with the Salt master
+ expected_pubkey_path = str(pki_dir.join("minion").join("syndic_master.pub"))
+ mockloop = MagicMock()
+ opts = {
+ "master_uri": "tcp://127.0.0.1:4506",
+ "interface": "127.0.0.1",
+ "ret_port": 4506,
+ "ipv6": False,
+ "sock_dir": ".",
+ "pki_dir": str(pki_dir.join("minion")),
+ "id": "syndic",
+ "__role": "syndic",
+ "keysize": 4096,
+ }
+ master_opts = dict(opts, pki_dir=str(pki_dir.join("master")))
+ server = salt.transport.zeromq.ZeroMQReqServerChannel(master_opts)
+ client = salt.transport.zeromq.AsyncZeroMQReqChannel(opts, io_loop=mockloop)
+
+ dictkey = "pillar"
+ target = "minion"
+ pillar_data = {"pillar1": "data1"}
+
+ # Mock auth and message client.
+ client.auth._authenticate_future = MagicMock()
+ client.auth._authenticate_future.done.return_value = True
+ client.auth._authenticate_future.exception.return_value = None
+ client.auth._crypticle = salt.crypt.Crypticle(opts, AES_KEY)
+ client.message_client = create_autospec(client.message_client)
+
+ @salt.ext.tornado.gen.coroutine
+ def mocksend(msg, timeout=60, tries=3):
+ client.message_client.msg = msg
+ load = client.auth.crypticle.loads(msg["load"])
+ ret = server._encrypt_private(
+ pillar_data, dictkey, target, nonce=load["nonce"], sign_messages=True
+ )
+ raise salt.ext.tornado.gen.Return(ret)
+
+ client.message_client.send = mocksend
+
+ # Note the 'ver' value in 'load' does not represent the the 'version' sent
+ # in the top level of the transport's message.
+ load = {
+ "id": target,
+ "grains": {},
+ "saltenv": "base",
+ "pillarenv": "base",
+ "pillar_override": True,
+ "extra_minion_data": {},
+ "ver": "2",
+ "cmd": "_pillar",
+ }
+ with patch(
+ "salt.crypt.verify_signature", autospec=True, return_value=True
+ ) as fake_verify:
+ ret = await client.crypted_transfer_decode_dictentry(
+ load,
+ dictkey="pillar",
+ )
+
+ assert fake_verify.mock_calls[0].args[0] == expected_pubkey_path
--
2.37.3

View File

@ -1,46 +0,0 @@
From 03f0aa44f6963e09a92dd3ea2090ef9ee463cb94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Wed, 5 Jun 2019 15:15:04 +0100
Subject: [PATCH] batch.py: avoid exception when minion does not
respond (bsc#1135507)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
We have several issues reporting that salt is throwing exception when
the minion does not respond. This change avoid the exception adding a
default data to the minion when it fails to respond. This patch based
on the patch suggested by @roskens.
Issues #46876 #48509 #50238
bsc#1135507
Signed-off-by: José Guilherme Vanz <jguilhermevanz@suse.com>
---
salt/cli/batch.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/salt/cli/batch.py b/salt/cli/batch.py
index 2bc5444aef..6285a45434 100644
--- a/salt/cli/batch.py
+++ b/salt/cli/batch.py
@@ -348,6 +348,14 @@ class Batch:
if self.opts.get("failhard") and data["retcode"] > 0:
failhard = True
+ # avoid an exception if the minion does not respond.
+ if data.get("failed") is True:
+ log.debug("Minion %s failed to respond: data=%s", minion, data)
+ data = {
+ "ret": "Minion did not return. [Failed]",
+ "retcode": salt.defaults.exitcodes.EX_GENERIC,
+ }
+
if self.opts.get("raw"):
ret[minion] = data
yield data
--
2.29.2

View File

@ -1,4 +1,4 @@
From 60b8f6cdaab10a12973a074678608b86a34e23b7 Mon Sep 17 00:00:00 2001
From 58329533d8b3239d978c15ecb76934987880897f 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
@ -17,10 +17,10 @@ Co-authored-by: Victor Zhestkov <vzhestkov@vz-thinkpad.vzhestkov.net>
2 files changed, 27 insertions(+), 11 deletions(-)
diff --git a/salt/modules/file.py b/salt/modules/file.py
index 989a7ad92d..b830b390d3 100644
index 95bd69a588..d475e3c2e3 100644
--- a/salt/modules/file.py
+++ b/salt/modules/file.py
@@ -252,7 +252,7 @@ def group_to_gid(group):
@@ -247,7 +247,7 @@ def group_to_gid(group):
try:
if isinstance(group, int):
return group
@ -29,7 +29,7 @@ index 989a7ad92d..b830b390d3 100644
except KeyError:
return ""
@@ -344,7 +344,7 @@ def user_to_uid(user):
@@ -338,7 +338,7 @@ def user_to_uid(user):
try:
if isinstance(user, int):
return user
@ -38,7 +38,7 @@ index 989a7ad92d..b830b390d3 100644
except KeyError:
return ""
@@ -4977,7 +4977,10 @@ def check_perms(
@@ -5043,7 +5043,10 @@ def check_perms(
if (
salt.utils.platform.is_windows()
and user_to_uid(user) != user_to_uid(perms["luser"])
@ -50,7 +50,7 @@ index 989a7ad92d..b830b390d3 100644
perms["cuser"] = user
if group:
@@ -4986,7 +4989,10 @@ def check_perms(
@@ -5052,7 +5055,10 @@ def check_perms(
if (
salt.utils.platform.is_windows()
and group_to_gid(group) != group_to_gid(perms["lgroup"])
@ -62,7 +62,7 @@ index 989a7ad92d..b830b390d3 100644
perms["cgroup"] = group
if "cuser" in perms or "cgroup" in perms:
@@ -5017,7 +5023,8 @@ def check_perms(
@@ -5083,7 +5089,8 @@ def check_perms(
and user != ""
) or (
not salt.utils.platform.is_windows()
@ -72,7 +72,7 @@ index 989a7ad92d..b830b390d3 100644
and user != ""
):
if __opts__["test"] is True:
@@ -5035,18 +5042,19 @@ def check_perms(
@@ -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))
@ -97,10 +97,10 @@ index 989a7ad92d..b830b390d3 100644
# Mode changes if needed
diff --git a/salt/states/file.py b/salt/states/file.py
index 9e24e389d8..89c70eb454 100644
index 9f33a8de23..50ceef1158 100644
--- a/salt/states/file.py
+++ b/salt/states/file.py
@@ -989,9 +989,17 @@ def _check_dir_meta(name, user, group, mode, follow_symlinks=False):
@@ -863,9 +863,17 @@ def _check_dir_meta(name, user, group, mode, follow_symlinks=False):
if not stats:
changes["directory"] = "new"
return changes
@ -121,6 +121,6 @@ index 9e24e389d8..89c70eb454 100644
# Normalize the dir mode
smode = salt.utils.files.normalize_mode(stats["mode"])
--
2.29.2
2.37.3

View File

@ -1,8 +1,8 @@
From e28385eb37932809a11ec81c81834a51e094f507 Mon Sep 17 00:00:00 2001
From e011015f0eaa8e6453b57c208ab2a43a15824e36 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 some packages with dpkg_lowpkg
Subject: [PATCH] Change the delimeters to prevent possible tracebacks on
some packages with dpkg_lowpkg
* Use another separator on query to dpkg-query
@ -75,6 +75,6 @@ index d00fc46c66..a97519f489 100644
),
}
--
2.37.2
2.37.3

View File

@ -1,23 +0,0 @@
From b477b00447b49fc2f221cfb6d2c491bcd1970119 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
Date: Tue, 1 Jun 2021 13:04:43 +0300
Subject: [PATCH] Check if dpkgnotify is executable (bsc#1186674)
(#376)
It prevents fails on removing salt-minion package
when the dpkg configuration is still active
---
scripts/suse/dpkg/99dpkgnotify | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/suse/dpkg/99dpkgnotify b/scripts/suse/dpkg/99dpkgnotify
index 8013387a57..f89815f605 100644
--- a/scripts/suse/dpkg/99dpkgnotify
+++ b/scripts/suse/dpkg/99dpkgnotify
@@ -1 +1 @@
-DPkg::Post-Invoke {"/usr/bin/dpkgnotify";};
+DPkg::Post-Invoke {"if [ -x /usr/bin/dpkgnotify ]; then /usr/bin/dpkgnotify; fi;";};
--
2.31.1

View File

@ -0,0 +1,51 @@
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 7720401d74ed6eafe860aab297aee0c8e22bc00f Mon Sep 17 00:00:00 2001
From 8cd50907edeb4a1128681c30e52b2b30cf7f937d 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)
@ -61,10 +61,10 @@ https://github.com/openSUSE/salt/commit/d0ef24d113bdaaa29f180031b5da384cffe08c64
3 files changed, 166 insertions(+), 18 deletions(-)
diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py
index 8d9f1b9f52..3c3fbf4970 100644
index 0cbd611b71..4a2281c47f 100644
--- a/salt/modules/aptpkg.py
+++ b/salt/modules/aptpkg.py
@@ -3035,6 +3035,15 @@ def info_installed(*names, **kwargs):
@@ -3458,6 +3458,15 @@ def info_installed(*names, **kwargs):
.. versionadded:: 2016.11.3
@ -80,7 +80,7 @@ index 8d9f1b9f52..3c3fbf4970 100644
CLI Example:
.. code-block:: bash
@@ -3045,11 +3054,19 @@ def info_installed(*names, **kwargs):
@@ -3468,11 +3477,19 @@ def info_installed(*names, **kwargs):
"""
kwargs = salt.utils.args.clean_kwargs(**kwargs)
failhard = kwargs.pop("failhard", True)
@ -101,7 +101,7 @@ index 8d9f1b9f52..3c3fbf4970 100644
t_nfo = dict()
if pkg_nfo.get("status", "ii")[1] != "i":
continue # return only packages that are really installed
@@ -3070,7 +3087,10 @@ def info_installed(*names, **kwargs):
@@ -3493,7 +3510,10 @@ def info_installed(*names, **kwargs):
else:
t_nfo[key] = value
@ -281,10 +281,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 6c5ed29848..51b7ffbe4d 100644
index 6ef27e2d29..8e404a673c 100644
--- a/tests/pytests/unit/modules/test_aptpkg.py
+++ b/tests/pytests/unit/modules/test_aptpkg.py
@@ -336,6 +336,58 @@ def test_info_installed(lowpkg_info_var):
@@ -359,6 +359,58 @@ def test_info_installed(lowpkg_info_var):
assert len(aptpkg.info_installed()) == 1
@ -344,6 +344,6 @@ index 6c5ed29848..51b7ffbe4d 100644
"""
Test - Return the name of the package that owns the file.
--
2.34.1
2.37.3

View File

@ -0,0 +1,28 @@
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 b1c213f171538890b3b61def25e4777bccfa64fe Mon Sep 17 00:00:00 2001
From e7bc5c7fc89877e9cbf203d8fb70855df0b626e1 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.33.1
2.37.3

View File

@ -1,79 +0,0 @@
From b151f2c1c6b6599b6387ec6e2d32a56e031e3d48 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 19:12:25 +0100
Subject: [PATCH] Do not crash when unexpected cmd output at listing
patches (bsc#1181290)
Add unit tests to cover unexpected output when listing patches
---
tests/pytests/unit/modules/test_yumpkg.py | 53 +++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/tests/pytests/unit/modules/test_yumpkg.py b/tests/pytests/unit/modules/test_yumpkg.py
index 475e1d6094..3b35272550 100644
--- a/tests/pytests/unit/modules/test_yumpkg.py
+++ b/tests/pytests/unit/modules/test_yumpkg.py
@@ -433,6 +433,59 @@ def test_list_patches():
assert _patch in patches["my-fake-patch-installed-1234"]["summary"]
+def test_list_patches_with_unexpected_output():
+ """
+ Test patches listin with unexpected output from updateinfo list
+
+ :return:
+ """
+ yum_out = [
+ "Update notice RHBA-2014:0722 (from rhel7-dev-rhel7-rpm-x86_64) is broken, or a bad duplicate, skipping.",
+ "You should report this problem to the owner of the rhel7-dev-rhel7-rpm-x86_64 repository.",
+ 'To help pinpoint the issue, please attach the output of "yum updateinfo --verbose" to the report.',
+ "Update notice RHSA-2014:1971 (from rhel7-dev-rhel7-rpm-x86_64) is broken, or a bad duplicate, skipping.",
+ "Update notice RHSA-2015:1981 (from rhel7-dev-rhel7-rpm-x86_64) is broken, or a bad duplicate, skipping.",
+ "Update notice RHSA-2015:0067 (from rhel7-dev-rhel7-rpm-x86_64) is broken, or a bad duplicate, skipping",
+ "i my-fake-patch-not-installed-1234 recommended spacewalk-usix-2.7.5.2-2.2.noarch",
+ " my-fake-patch-not-installed-1234 recommended spacewalksd-5.0.26.2-21.2.x86_64",
+ "i my-fake-patch-not-installed-1234 recommended suseRegisterInfo-3.1.1-18.2.x86_64",
+ "i my-fake-patch-installed-1234 recommended my-package-one-1.1-0.1.x86_64",
+ "i my-fake-patch-installed-1234 recommended my-package-two-1.1-0.1.x86_64",
+ ]
+
+ expected_patches = {
+ "my-fake-patch-not-installed-1234": {
+ "installed": False,
+ "summary": [
+ "spacewalk-usix-2.7.5.2-2.2.noarch",
+ "spacewalksd-5.0.26.2-21.2.x86_64",
+ "suseRegisterInfo-3.1.1-18.2.x86_64",
+ ],
+ },
+ "my-fake-patch-installed-1234": {
+ "installed": True,
+ "summary": [
+ "my-package-one-1.1-0.1.x86_64",
+ "my-package-two-1.1-0.1.x86_64",
+ ],
+ },
+ }
+
+ with patch.dict(yumpkg.__grains__, {"osarch": "x86_64"}), patch.dict(
+ yumpkg.__salt__,
+ {"cmd.run_stdout": MagicMock(return_value=os.linesep.join(yum_out))},
+ ):
+ patches = yumpkg.list_patches()
+ assert not patches["my-fake-patch-not-installed-1234"]["installed"]
+ assert len(patches["my-fake-patch-not-installed-1234"]["summary"]) == 3
+ for _patch in expected_patches["my-fake-patch-not-installed-1234"]["summary"]:
+ assert _patch in patches["my-fake-patch-not-installed-1234"]["summary"]
+ assert patches["my-fake-patch-installed-1234"]["installed"]
+ assert len(patches["my-fake-patch-installed-1234"]["summary"]) == 2
+ for _patch in expected_patches["my-fake-patch-installed-1234"]["summary"]:
+ assert _patch in patches["my-fake-patch-installed-1234"]["summary"]
+
+
def test_latest_version_with_options():
with patch.object(yumpkg, "list_pkgs", MagicMock(return_value={})):
--
2.34.1

View File

@ -1,4 +1,4 @@
From e0b91c626c10b29d328fa92415393cd57bb4c962 Mon Sep 17 00:00:00 2001
From d97cbae7eb3cb0030d355a4ae3fb35745fed5da0 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 f68cafaeaf..14cfafed4b 100644
index 7135a9145f..da26416662 100644
--- a/salt/modules/pip.py
+++ b/salt/modules/pip.py
@@ -96,6 +96,12 @@ import salt.utils.url
@ -26,7 +26,7 @@ index f68cafaeaf..14cfafed4b 100644
# This needs to be named logger so we don't shadow it in pip.install
logger = logging.getLogger(__name__) # pylint: disable=invalid-name
@@ -113,7 +119,12 @@ def __virtual__():
@@ -114,7 +120,12 @@ def __virtual__():
entire filesystem. If it's not installed in a conventional location, the
user is required to provide the location of pip each time it is used.
"""
@ -41,6 +41,6 @@ index f68cafaeaf..14cfafed4b 100644
def _pip_bin_env(cwd, bin_env):
--
2.33.0
2.37.3

View File

@ -1,4 +1,4 @@
From 9a8ca020a3cacbcfbbc33f209cd0ea6c3da3f788 Mon Sep 17 00:00:00 2001
From 009f51315366827653011d2e9b80aa88416a8bf0 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,10 +13,10 @@ Fixes: bsc#1188259
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/salt/state.py b/salt/state.py
index 64c5225728..c6742101b2 100644
index 2385975b42..db228228a7 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -889,9 +889,14 @@ class State:
@@ -921,9 +921,14 @@ class State:
cmd_opts[run_cmd_arg] = low_data.get(run_cmd_arg)
if "shell" in low_data:
@ -34,6 +34,6 @@ index 64c5225728..c6742101b2 100644
if "onlyif" in low_data:
_ret = self._run_check_onlyif(low_data, cmd_opts)
--
2.32.0
2.37.3

View File

@ -1,4 +1,4 @@
From f6ad8b59662333327b04aa8f6465f6f3bceaa152 Mon Sep 17 00:00:00 2001
From d4c70bdcb8d871bf3a7e15299b69b9687b7d0d94 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.34.1
2.37.3

View File

@ -1,4 +1,4 @@
From f24c61d3c1ede64c0ef5c11efeb7d2293e714550 Mon Sep 17 00:00:00 2001
From 3ccce128163f6cd9a9360d3b28729702a5d260c1 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
@ -561,10 +561,10 @@ Check last function by full name
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 43dfb700f9..73958181dd 100644
index fef851215a..a36ab6b2e9 100644
--- a/doc/ref/modules/all/index.rst
+++ b/doc/ref/modules/all/index.rst
@@ -415,6 +415,7 @@ execution modules
@@ -416,6 +416,7 @@ execution modules
salt_version
saltcheck
saltcloudmod
@ -573,10 +573,10 @@ index 43dfb700f9..73958181dd 100644
schedule
scp_mod
diff --git a/doc/ref/states/all/index.rst b/doc/ref/states/all/index.rst
index 914b63d0fb..e40b32a6e8 100644
index da7be43039..c968315970 100644
--- a/doc/ref/states/all/index.rst
+++ b/doc/ref/states/all/index.rst
@@ -280,6 +280,7 @@ state modules
@@ -282,6 +282,7 @@ state modules
rvm
salt_proxy
saltmod
@ -1740,13 +1740,13 @@ index 0000000000..391acdb606
+ info: List of all available groups
+ output: table
diff --git a/salt/loader/lazy.py b/salt/loader/lazy.py
index 48c70d01c0..220641059c 100644
index 8a5d0dd267..e7d692859c 100644
--- a/salt/loader/lazy.py
+++ b/salt/loader/lazy.py
@@ -950,8 +950,10 @@ class LazyLoader(salt.utils.lazy.LazyDict):
@@ -968,8 +968,10 @@ class LazyLoader(salt.utils.lazy.LazyDict):
mod_names = [module_name] + list(virtual_aliases)
for attr in getattr(mod, "__load__", dir(mod)):
for attr in funcs_to_load:
- if attr.startswith("_"):
- # private functions are skipped
+ if attr.startswith("_") and attr != "__call__":
@ -2168,10 +2168,10 @@ index 0000000000..e800e3bf1f
+
+ return __virtualname__
diff --git a/salt/scripts.py b/salt/scripts.py
index 93eab0f702..b1fea566a9 100644
index 7f6d80de59..1276d2c8b2 100644
--- a/salt/scripts.py
+++ b/salt/scripts.py
@@ -574,3 +574,18 @@ def salt_unity():
@@ -583,3 +583,18 @@ def salt_unity():
sys.argv.pop(1)
s_fun = getattr(sys.modules[__name__], "salt_{}".format(cmd))
s_fun()
@ -2191,10 +2191,10 @@ index 93eab0f702..b1fea566a9 100644
+ _install_signal_handlers(client)
+ client.run()
diff --git a/salt/state.py b/salt/state.py
index 91927d9ec6..fa5a578dc6 100644
index d6d2c90168..3196f3c635 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -1577,7 +1577,9 @@ class State:
@@ -1592,7 +1592,9 @@ class State:
names = []
if state.startswith("__"):
continue
@ -2205,7 +2205,7 @@ index 91927d9ec6..fa5a578dc6 100644
if orchestration_jid is not None:
chunk["__orchestration_jid__"] = orchestration_jid
if "__sls__" in body:
@@ -2176,9 +2178,16 @@ class State:
@@ -2273,9 +2275,16 @@ class State:
ret = self.call_parallel(cdata, low)
else:
self.format_slots(cdata)
@ -2225,7 +2225,7 @@ index 91927d9ec6..fa5a578dc6 100644
self.states.inject_globals = {}
if (
"check_cmd" in low
@@ -3252,10 +3261,31 @@ class State:
@@ -3362,10 +3371,31 @@ class State:
running.update(errors)
return running
@ -2489,7 +2489,7 @@ index 0000000000..fb0c9e0372
+ """
+ return __virtualname__
diff --git a/salt/utils/args.py b/salt/utils/args.py
index ba50aff126..4e5ca0eedf 100644
index 536aea3816..04a8a14054 100644
--- a/salt/utils/args.py
+++ b/salt/utils/args.py
@@ -15,6 +15,7 @@ import salt.utils.jid
@ -2500,7 +2500,7 @@ index ba50aff126..4e5ca0eedf 100644
log = logging.getLogger(__name__)
@@ -437,7 +438,7 @@ def format_call(
@@ -399,7 +400,7 @@ def format_call(
ret = initial_ret is not None and initial_ret or {}
ret["args"] = []
@ -2510,10 +2510,10 @@ index ba50aff126..4e5ca0eedf 100644
aspec = get_function_argspec(fun, is_class_method=is_class_method)
diff --git a/salt/utils/decorators/__init__.py b/salt/utils/decorators/__init__.py
index 20803771ed..0aba77e194 100644
index 1f62d5f3d6..1906cc2ecc 100644
--- a/salt/utils/decorators/__init__.py
+++ b/salt/utils/decorators/__init__.py
@@ -867,3 +867,27 @@ def ensure_unicode_args(function):
@@ -866,3 +866,27 @@ def ensure_unicode_args(function):
return function(*args, **kwargs)
return wrapped
@ -2542,7 +2542,7 @@ index 20803771ed..0aba77e194 100644
+
+ return f
diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py
index 28660397d4..c0820e5df0 100644
index 911b2cbb04..dc125de7d7 100644
--- a/salt/utils/parsers.py
+++ b/salt/utils/parsers.py
@@ -17,6 +17,7 @@ import optparse
@ -2561,7 +2561,7 @@ index 28660397d4..c0820e5df0 100644
import salt.utils.platform
import salt.utils.process
import salt.utils.stringutils
@@ -2088,6 +2090,118 @@ class SyndicOptionParser(
@@ -2026,6 +2028,118 @@ class SyndicOptionParser(
return opts
@ -2698,25 +2698,25 @@ index 0000000000..4e0e79f3ea
+if __name__ == "__main__":
+ salt_support()
diff --git a/setup.py b/setup.py
index af8e448007..2f6dfd6064 100755
index bd11ff95f7..d633af35ec 100755
--- a/setup.py
+++ b/setup.py
@@ -1253,6 +1253,7 @@ class SaltDistribution(distutils.dist.Distribution):
@@ -1165,6 +1165,7 @@ class SaltDistribution(distutils.dist.Distribution):
"scripts/salt-master",
"scripts/salt-minion",
"scripts/salt-proxy",
+ "scripts/salt-support",
"scripts/salt-ssh",
"scripts/salt-syndic",
"scripts/salt-unity",
@@ -1299,6 +1300,7 @@ class SaltDistribution(distutils.dist.Distribution):
"scripts/spm",
@@ -1216,6 +1217,7 @@ class SaltDistribution(distutils.dist.Distribution):
"salt-key = salt.scripts:salt_key",
"salt-master = salt.scripts:salt_master",
"salt-minion = salt.scripts:salt_minion",
+ "salt-support = salt.scripts:salt_support",
"salt-ssh = salt.scripts:salt_ssh",
"salt-syndic = salt.scripts:salt_syndic",
"salt-unity = salt.scripts:salt_unity",
"spm = salt.scripts:salt_spm",
diff --git a/tests/unit/cli/test_support.py b/tests/unit/cli/test_support.py
new file mode 100644
index 0000000000..dc0e99bb3d
@ -3779,6 +3779,6 @@ index 0000000000..f9ce7be29a
+ "00:00:00.000 - The real TTYs became " "pseudo TTYs and vice versa"
+ ]
--
2.34.1
2.37.3

View File

@ -1,4 +1,4 @@
From c8f4092f117bd93293e0957422555d3ae7bae999 Mon Sep 17 00:00:00 2001
From 465ea094039e771ea2b4ccda012d0dc12f7aa022 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
@ -63,6 +63,6 @@ index 6fd4fdef2c..7a7e9a3284 100644
try:
--
2.34.1
2.37.3

View File

@ -1,30 +0,0 @@
From cde0f9385e1afb9fa97fe2c86cfa77ae3b899aa0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Fri, 18 Jun 2021 13:09:22 +0100
Subject: [PATCH] Enhance logging when inotify beacon is missing
pyinotify (bsc#1186310)
---
salt/beacons/inotify.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/salt/beacons/inotify.py b/salt/beacons/inotify.py
index fa2f73c35f..a6b7548f97 100644
--- a/salt/beacons/inotify.py
+++ b/salt/beacons/inotify.py
@@ -49,7 +49,9 @@ log = logging.getLogger(__name__)
def __virtual__():
if HAS_PYINOTIFY:
return __virtualname__
- return False
+ err_msg = "pyinotify library is missing"
+ log.error("Unable to load inotify beacon: {}".format(err_msg))
+ return False, err_msg
def _get_mask(mask):
--
2.31.1

View File

@ -1,4 +1,4 @@
From 933345d049a0207e730ca518dc5f016b0c05d761 Mon Sep 17 00:00:00 2001
From 93d7bdab18bdc657c8103a7b5f569458a97c8ca0 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.34.1
2.37.3

View File

@ -1,35 +0,0 @@
From df474d3cc0a5f02591fea093f9efc324c6feef46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Thu, 7 Jul 2022 11:38:09 +0100
Subject: [PATCH] Fix #62092: Catch zmq.error.ZMQError to set HWM for
zmq >= 3 (#543)
It looks like before release 23.0.0, when trying to access zmq.HWM it
was raising ``AttributeError``, which is now wrapped under pyzmq's own
``zmq.error.ZMQError``.
Simply caching that, should then set the HWM correctly for zmq >= 3
and therefore fix #62092.
Co-authored-by: Mircea Ulinic <mulinic@digitalocean.com>
---
salt/transport/zeromq.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/salt/transport/zeromq.py b/salt/transport/zeromq.py
index 9e61b23255..aa06298ee1 100644
--- a/salt/transport/zeromq.py
+++ b/salt/transport/zeromq.py
@@ -898,7 +898,7 @@ class ZeroMQPubServerChannel(salt.transport.server.PubServerChannel):
try:
pub_sock.setsockopt(zmq.HWM, self.opts.get("pub_hwm", 1000))
# in zmq >= 3.0, there are separate send and receive HWM settings
- except AttributeError:
+ except (AttributeError, zmq.error.ZMQError):
# Set the High Water Marks. For more information on HWM, see:
# http://api.zeromq.org/4-1:zmq-setsockopt
pub_sock.setsockopt(zmq.SNDHWM, self.opts.get("pub_hwm", 1000))
--
2.36.1

View File

@ -1,4 +1,4 @@
From 22fe4809712dbc59ba2d8c3c2045f531f81bc517 Mon Sep 17 00:00:00 2001
From 559920223a010b70a4e469143b3390d8d3a7a4e2 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
@ -8,7 +8,7 @@ Subject: [PATCH] Fix bsc#1065792
1 file changed, 1 insertion(+)
diff --git a/salt/states/service.py b/salt/states/service.py
index 536e64a430..27595f7703 100644
index 93c7c4fb07..0d8a4efa03 100644
--- a/salt/states/service.py
+++ b/salt/states/service.py
@@ -78,6 +78,7 @@ def __virtual__():
@ -20,6 +20,6 @@ index 536e64a430..27595f7703 100644
return __virtualname__
else:
--
2.33.0
2.37.3

View File

@ -1,81 +0,0 @@
From 3ecb98a9bd7a8d35cff6d0a5f34b7fea96f89da7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Fri, 8 Oct 2021 12:47:53 +0100
Subject: [PATCH] Fix crash when calling manage.not_alive runners
Fix unit tests for netlink_tool_remote_on
Drop wrong test
---
salt/utils/network.py | 1 +
tests/unit/utils/test_network.py | 17 ++++-------------
2 files changed, 5 insertions(+), 13 deletions(-)
diff --git a/salt/utils/network.py b/salt/utils/network.py
index 0dd20c5599..f0f5f1e8ce 100644
--- a/salt/utils/network.py
+++ b/salt/utils/network.py
@@ -1701,6 +1701,7 @@ def _netlink_tool_remote_on(port, which_end):
elif "ESTAB" not in line:
continue
chunks = line.split()
+ local_host, local_port = chunks[3].rsplit(":", 1)
remote_host, remote_port = chunks[4].rsplit(":", 1)
if which_end == "remote_port" and int(remote_port) != int(port):
diff --git a/tests/unit/utils/test_network.py b/tests/unit/utils/test_network.py
index 637d5e9811..3060aba0aa 100644
--- a/tests/unit/utils/test_network.py
+++ b/tests/unit/utils/test_network.py
@@ -110,18 +110,14 @@ USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
salt-master python2.781106 35 tcp4 127.0.0.1:61115 127.0.0.1:4506
"""
-NETLINK_SS = """
-State Recv-Q Send-Q Local Address:Port Peer Address:Port
-ESTAB 0 0 127.0.0.1:56726 127.0.0.1:4505
-ESTAB 0 0 ::ffff:1.2.3.4:5678 ::ffff:1.2.3.4:4505
-"""
-
LINUX_NETLINK_SS_OUTPUT = """\
State Recv-Q Send-Q Local Address:Port Peer Address:Port
TIME-WAIT 0 0 [::1]:8009 [::1]:40368
LISTEN 0 128 127.0.0.1:5903 0.0.0.0:*
ESTAB 0 0 [::ffff:127.0.0.1]:4506 [::ffff:127.0.0.1]:32315
ESTAB 0 0 192.168.122.1:4506 192.168.122.177:24545
+ESTAB 0 0 127.0.0.1:56726 127.0.0.1:4505
+ESTAB 0 0 ::ffff:1.2.3.4:5678 ::ffff:1.2.3.4:4505
"""
IPV4_SUBNETS = {
@@ -633,11 +629,11 @@ class NetworkTestCase(TestCase):
with patch(
"subprocess.check_output", return_value=LINUX_NETLINK_SS_OUTPUT
):
- remotes = network._netlink_tool_remote_on("4506", "local")
+ remotes = network._netlink_tool_remote_on("4506", "local_port")
self.assertEqual(remotes, {"192.168.122.177", "::ffff:127.0.0.1"})
def test_netlink_tool_remote_on_b(self):
- with patch("subprocess.check_output", return_value=NETLINK_SS):
+ with patch("subprocess.check_output", return_value=LINUX_NETLINK_SS_OUTPUT):
remotes = network._netlink_tool_remote_on("4505", "remote_port")
self.assertEqual(remotes, {"127.0.0.1", "::ffff:1.2.3.4"})
@@ -1274,11 +1270,6 @@ class NetworkTestCase(TestCase):
):
self.assertEqual(network.get_fqhostname(), host)
- def test_netlink_tool_remote_on(self):
- with patch("subprocess.check_output", return_value=NETLINK_SS):
- remotes = network._netlink_tool_remote_on("4505", "remote")
- self.assertEqual(remotes, {"127.0.0.1", "::ffff:1.2.3.4"})
-
def test_is_fqdn(self):
"""
Test is_fqdn function passes possible FQDN names.
--
2.33.0

View File

@ -1,76 +0,0 @@
From 40d9cde9b90965e60520f36dbe189fb64d15559d Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <35733135+vzhestkov@users.noreply.github.com>
Date: Thu, 24 Jun 2021 13:17:13 +0300
Subject: [PATCH] Fix exception in yumpkg.remove for not installed
package (#380)
---
salt/modules/yumpkg.py | 2 ++
tests/pytests/unit/modules/test_yumpkg.py | 37 +++++++++++++++++++++++
2 files changed, 39 insertions(+)
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
index 9737508377..9f8f548e5f 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -2123,6 +2123,8 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
pkg_params.update(pkg_matches)
for target in pkg_params:
+ if target not in old:
+ continue
version_to_remove = pkg_params[target]
# Check if package version set to be removed is actually installed:
diff --git a/tests/pytests/unit/modules/test_yumpkg.py b/tests/pytests/unit/modules/test_yumpkg.py
index 3b35272550..c3456f7e29 100644
--- a/tests/pytests/unit/modules/test_yumpkg.py
+++ b/tests/pytests/unit/modules/test_yumpkg.py
@@ -1284,6 +1284,43 @@ def test_install_error_reporting():
assert exc_info.value.info == expected, exc_info.value.info
+def test_remove_not_installed():
+ """
+ Tests that no exception raised on removing not installed package
+ """
+ name = "foo"
+ list_pkgs_mock = MagicMock(return_value={})
+ cmd_mock = MagicMock(
+ return_value={"pid": 12345, "retcode": 0, "stdout": "", "stderr": ""}
+ )
+ salt_mock = {
+ "cmd.run_all": cmd_mock,
+ "lowpkg.version_cmp": rpm.version_cmp,
+ "pkg_resource.parse_targets": MagicMock(
+ return_value=({name: None}, "repository")
+ ),
+ }
+ with patch.object(yumpkg, "list_pkgs", list_pkgs_mock), patch(
+ "salt.utils.systemd.has_scope", MagicMock(return_value=False)
+ ), patch.dict(yumpkg.__salt__, salt_mock):
+
+ # Test yum
+ with patch.dict(yumpkg.__context__, {"yum_bin": "yum"}), patch.dict(
+ yumpkg.__grains__, {"os": "CentOS", "osrelease": 7}
+ ):
+ yumpkg.remove(name)
+ cmd_mock.assert_not_called()
+
+ # Test dnf
+ yumpkg.__context__.pop("yum_bin")
+ cmd_mock.reset_mock()
+ with patch.dict(yumpkg.__context__, {"yum_bin": "dnf"}), patch.dict(
+ yumpkg.__grains__, {"os": "Fedora", "osrelease": 27}
+ ):
+ yumpkg.remove(name)
+ cmd_mock.assert_not_called()
+
+
def test_upgrade_with_options():
with patch.object(yumpkg, "list_pkgs", MagicMock(return_value={})), patch(
"salt.utils.systemd.has_scope", MagicMock(return_value=False)
--
2.34.1

View File

@ -1,75 +0,0 @@
From a9c292fdf9ae53b86109337165214d8aadb155e7 Mon Sep 17 00:00:00 2001
From: Wayne Werner <wwerner@vmware.com>
Date: Fri, 1 Apr 2022 14:21:57 -0500
Subject: [PATCH] Fix for CVE-2022-22967 (bsc#1200566)
---
changelog/pam_auth.security | 1 +
salt/auth/pam.py | 2 +-
tests/pytests/unit/auth/test_pam.py | 32 +++++++++++++++++++++++++++++
3 files changed, 34 insertions(+), 1 deletion(-)
create mode 100644 changelog/pam_auth.security
create mode 100644 tests/pytests/unit/auth/test_pam.py
diff --git a/changelog/pam_auth.security b/changelog/pam_auth.security
new file mode 100644
index 0000000000..52943680f4
--- /dev/null
+++ b/changelog/pam_auth.security
@@ -0,0 +1 @@
+Fixed PAM auth to reject auth attempt if user account is locked.
diff --git a/salt/auth/pam.py b/salt/auth/pam.py
index a9dde95149..d91883b743 100644
--- a/salt/auth/pam.py
+++ b/salt/auth/pam.py
@@ -209,7 +209,7 @@ def authenticate(username, password):
retval = PAM_AUTHENTICATE(handle, 0)
if retval == 0:
- PAM_ACCT_MGMT(handle, 0)
+ retval = PAM_ACCT_MGMT(handle, 0)
PAM_END(handle, 0)
return retval == 0
diff --git a/tests/pytests/unit/auth/test_pam.py b/tests/pytests/unit/auth/test_pam.py
new file mode 100644
index 0000000000..f5f49e65d8
--- /dev/null
+++ b/tests/pytests/unit/auth/test_pam.py
@@ -0,0 +1,32 @@
+import pytest
+import salt.auth.pam
+from tests.support.mock import patch
+
+
+@pytest.fixture
+def configure_loader_modules():
+ return {salt.auth.pam: {}}
+
+
+@pytest.fixture
+def mock_pam():
+ with patch("salt.auth.pam.CALLOC", autospec=True), patch(
+ "salt.auth.pam.pointer", autospec=True
+ ), patch("salt.auth.pam.PamHandle", autospec=True), patch(
+ "salt.auth.pam.PAM_START", autospec=True, return_value=0
+ ), patch(
+ "salt.auth.pam.PAM_AUTHENTICATE", autospec=True, return_value=0
+ ), patch(
+ "salt.auth.pam.PAM_END", autospec=True
+ ):
+ yield
+
+
+def test_cve_if_pam_acct_mgmt_returns_nonzero_authenticate_should_be_false(mock_pam):
+ with patch("salt.auth.pam.PAM_ACCT_MGMT", autospec=True, return_value=42):
+ assert salt.auth.pam.authenticate(username="fnord", password="fnord") is False
+
+
+def test_if_pam_acct_mgmt_returns_zero_authenticate_should_be_true(mock_pam):
+ with patch("salt.auth.pam.PAM_ACCT_MGMT", autospec=True, return_value=0):
+ assert salt.auth.pam.authenticate(username="fnord", password="fnord") is True
--
2.36.1

View File

@ -1,4 +1,4 @@
From 369a732537937dd6865152a87f04777539b27fcd Mon Sep 17 00:00:00 2001
From 51bcdcfdec73368d1517150eafda21e4af51dd7a 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,10 +14,10 @@ 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 436c058eb6..00bd0565bf 100644
index debbeb257d..b55ab4e472 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -1990,6 +1990,15 @@ def os_data():
@@ -2058,6 +2058,15 @@ def os_data():
log.trace("Parsing distrib info from /etc/centos-release")
# CentOS Linux
grains["lsb_distrib_id"] = "CentOS"
@ -34,6 +34,6 @@ index 436c058eb6..00bd0565bf 100644
for line in ifile:
# Need to pull out the version and codename
--
2.29.2
2.37.3

View File

@ -1,68 +0,0 @@
From 554b13dec6a9770b7fbf287b3bf9af91a2cdabde Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Fri, 28 Jan 2022 16:44:25 +0300
Subject: [PATCH] Fix inspector module export function (bsc#1097531)
(#481)
---
salt/modules/inspectlib/fsdb.py | 8 ++++----
salt/modules/inspectlib/query.py | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/salt/modules/inspectlib/fsdb.py b/salt/modules/inspectlib/fsdb.py
index 489fde5684..b834b8f678 100644
--- a/salt/modules/inspectlib/fsdb.py
+++ b/salt/modules/inspectlib/fsdb.py
@@ -137,7 +137,7 @@ class CsvDB:
return self._tables.keys()
def _load_table(self, table_name):
- with gzip.open(os.path.join(self.db_path, table_name), "rb") as table:
+ with gzip.open(os.path.join(self.db_path, table_name), "rt") as table:
return OrderedDict(
[tuple(elm.split(":")) for elm in next(csv.reader(table))]
)
@@ -184,7 +184,7 @@ class CsvDB:
"""
get_type = lambda item: str(type(item)).split("'")[1]
if not os.path.exists(os.path.join(self.db_path, obj._TABLE)):
- with gzip.open(os.path.join(self.db_path, obj._TABLE), "wb") as table_file:
+ with gzip.open(os.path.join(self.db_path, obj._TABLE), "wt") as table_file:
csv.writer(table_file).writerow(
[
"{col}:{type}".format(col=elm[0], type=get_type(elm[1]))
@@ -212,7 +212,7 @@ class CsvDB:
db_obj = self.get(obj.__class__, eq=fields)
if db_obj and distinct:
raise Exception("Object already in the database.")
- with gzip.open(os.path.join(self.db_path, obj._TABLE), "a") as table:
+ with gzip.open(os.path.join(self.db_path, obj._TABLE), "at") as table:
csv.writer(table).writerow(self._validate_object(obj))
def update(self, obj, matches=None, mt=None, lt=None, eq=None):
@@ -318,7 +318,7 @@ class CsvDB:
:return:
"""
objects = []
- with gzip.open(os.path.join(self.db_path, obj._TABLE), "rb") as table:
+ with gzip.open(os.path.join(self.db_path, obj._TABLE), "rt") as table:
header = None
for data in csv.reader(table):
if not header:
diff --git a/salt/modules/inspectlib/query.py b/salt/modules/inspectlib/query.py
index 079cc29172..8027176a13 100644
--- a/salt/modules/inspectlib/query.py
+++ b/salt/modules/inspectlib/query.py
@@ -74,7 +74,7 @@ class SysInfo:
for dev, dev_data in salt.utils.fsutils._blkid().items():
dev = self._get_disk_size(dev)
device = dev.pop("device")
- dev["type"] = dev_data["type"]
+ dev["type"] = dev_data.get("type", "UNKNOWN")
data[device] = dev
return data
--
2.34.1

View File

@ -1,32 +0,0 @@
From 0571b8a6d0f4728e604bab9a8ef6f2123546671b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Fri, 15 Oct 2021 13:08:53 +0100
Subject: [PATCH] Fix ip6_interface grain to not leak secondary IPv4
addrs
---
salt/grains/core.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/salt/grains/core.py b/salt/grains/core.py
index f79110124f..88f1d2c053 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -2537,7 +2537,11 @@ def ip6_interfaces():
iface_ips.append(inet["address"])
for secondary in ifaces[face].get("secondary", []):
if "address" in secondary:
- iface_ips.append(secondary["address"])
+ try:
+ socket.inet_pton(socket.AF_INET6, secondary["address"])
+ iface_ips.append(secondary["address"])
+ except OSError:
+ pass
ret[face] = iface_ips
return {"ip6_interfaces": ret}
--
2.33.0

View File

@ -1,4 +1,4 @@
From db77ad3e24daf3bc014dc3d85a49aa1bb33ae1ae Mon Sep 17 00:00:00 2001
From f87d92122cb141e8f6f4d1c5a6ed5685e1b3900c 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 b1bce4e0cd..cc6db7e1b2 100644
index 3196f3c635..2385975b42 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 b1bce4e0cd..cc6db7e1b2 100644
import copy
import datetime
import fnmatch
@@ -3206,16 +3207,18 @@ class State:
@@ -3380,16 +3381,18 @@ class State:
"""
for chunk in high:
state = high[chunk]
@ -47,6 +47,6 @@ index b1bce4e0cd..cc6db7e1b2 100644
def call_high(self, high, orchestration_jid=None):
"""
--
2.29.2
2.37.3

View File

@ -1,24 +0,0 @@
From a268bfee70fabffc6d8fb6c297cd255fb3483ae1 Mon Sep 17 00:00:00 2001
From: "Daniel A. Wozniak" <dwozniak@saltstack.com>
Date: Thu, 7 Oct 2021 17:22:37 -0700
Subject: [PATCH] Fix issues with salt-ssh's extra-filerefs
Verify salt-ssh can import from map files in states
Add changelog for 60003.fixed
---
changelog/60003.fixed | 1 +
1 file changed, 1 insertion(+)
create mode 100644 changelog/60003.fixed
diff --git a/changelog/60003.fixed b/changelog/60003.fixed
new file mode 100644
index 0000000000..6fafbf5108
--- /dev/null
+++ b/changelog/60003.fixed
@@ -0,0 +1 @@
+Validate we can import map files in states
--
2.34.1

View File

@ -1,83 +0,0 @@
From 65494338f5a9bdaa0be27afab3da3a03a92d8cda Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Fri, 8 Jul 2022 13:35:50 +0100
Subject: [PATCH] fix: jinja2 contextfuntion base on version
(bsc#1198744) (#520)
---
salt/utils/jinja.py | 16 ++++++++++++++--
tests/unit/utils/test_jinja.py | 8 +++++++-
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/salt/utils/jinja.py b/salt/utils/jinja.py
index 0cb70bf64a..6b5b0d4e81 100644
--- a/salt/utils/jinja.py
+++ b/salt/utils/jinja.py
@@ -25,7 +25,7 @@ import salt.utils.json
import salt.utils.stringutils
import salt.utils.url
import salt.utils.yaml
-from jinja2 import BaseLoader, Markup, TemplateNotFound, nodes
+from jinja2 import BaseLoader, TemplateNotFound, nodes
from jinja2.environment import TemplateModule
from jinja2.exceptions import TemplateRuntimeError
from jinja2.ext import Extension
@@ -34,6 +34,12 @@ from salt.utils.decorators.jinja import jinja_filter, jinja_global, jinja_test
from salt.utils.odict import OrderedDict
from salt.utils.versions import LooseVersion
+try:
+ from markupsafe import Markup
+except ImportError:
+ # jinja < 3.1
+ from jinja2 import Markup
+
log = logging.getLogger(__name__)
__all__ = ["SaltCacheLoader", "SerializerExtension"]
@@ -706,7 +712,13 @@ def method_call(obj, f_name, *f_args, **f_kwargs):
return getattr(obj, f_name, lambda *args, **kwargs: None)(*f_args, **f_kwargs)
-@jinja2.contextfunction
+try:
+ contextfunction = jinja2.contextfunction
+except AttributeError:
+ contextfunction = jinja2.pass_context
+
+
+@contextfunction
def show_full_context(ctx):
return salt.utils.data.simple_types_filter(
{key: value for key, value in ctx.items()}
diff --git a/tests/unit/utils/test_jinja.py b/tests/unit/utils/test_jinja.py
index 6502831aff..6bbcf9ef6f 100644
--- a/tests/unit/utils/test_jinja.py
+++ b/tests/unit/utils/test_jinja.py
@@ -22,7 +22,7 @@ import salt.utils.files
import salt.utils.json
import salt.utils.stringutils
import salt.utils.yaml
-from jinja2 import DictLoader, Environment, Markup, exceptions
+from jinja2 import DictLoader, Environment, exceptions
from salt.exceptions import SaltRenderError
from salt.utils.decorators.jinja import JinjaFilter
from salt.utils.jinja import (
@@ -46,6 +46,12 @@ try:
except ImportError:
HAS_TIMELIB = False
+try:
+ from markupsafe import Markup
+except ImportError:
+ # jinja < 3.1
+ from jinja2 import Markup
+
BLINESEP = salt.utils.stringutils.to_bytes(os.linesep)
--
2.36.1

View File

@ -1,4 +1,4 @@
From 83fbfcbf49c98624029f1d215b7ad4d247128d39 Mon Sep 17 00:00:00 2001
From 3ed9869ee6847472846072d62cbc57dcb9104c90 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 ddb437604b..78f4d99e84 100644
index 2427516ca1..86888adc19 100644
--- a/salt/client/__init__.py
+++ b/salt/client/__init__.py
@@ -920,7 +920,7 @@ class LocalClient:
@@ -972,7 +972,7 @@ class LocalClient:
self._clean_up_subscriptions(pub_data["jid"])
finally:
@ -25,6 +25,6 @@ index ddb437604b..78f4d99e84 100644
def cmd_full_return(
--
2.31.1
2.37.3

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
From 34a81d88db3862bcc03cdda4974e576723af7643 Mon Sep 17 00:00:00 2001
From 7ac8c79f38960c787f6b5324e347707325c65e79 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.36.1
2.37.3

View File

@ -1,4 +1,4 @@
From 0c4a71224d49e778b4a2c683c63de52a0876de69 Mon Sep 17 00:00:00 2001
From 6e0e6c26f4ec0955b55937ae3b58ca485b99facd 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 6d24d8d716..396f9457f2 100644
index fe1213b723..1b76a38e0b 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -12,7 +12,6 @@ import hashlib
@ -20,7 +20,7 @@ index 6d24d8d716..396f9457f2 100644
import queue
import re
import shlex
@@ -407,6 +406,16 @@ class SSH:
@@ -420,6 +419,16 @@ class SSH(MultiprocessingStateMixin):
self.__parsed_rosters[self.ROSTER_UPDATE_FLAG] = False
return
@ -37,7 +37,7 @@ index 6d24d8d716..396f9457f2 100644
def _update_roster(self, hostname=None, user=None):
"""
Update default flat roster with the passed in information.
@@ -626,7 +635,8 @@ class SSH:
@@ -639,7 +648,8 @@ class SSH(MultiprocessingStateMixin):
pid_running = (
False
if cached_session["pid"] == 0
@ -48,6 +48,6 @@ index 6d24d8d716..396f9457f2 100644
if (
pid_running and prev_session_running < self.max_pid_wait
--
2.35.1
2.37.3

View File

@ -1,70 +0,0 @@
From 245bd5f2aab798f7f647ad2d2307c0dd1381c1c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= <cbosdonnat@suse.com>
Date: Thu, 18 Nov 2021 14:46:25 +0100
Subject: [PATCH] Fix salt-call event.send call with grains and pillar
---
changelog/61252.fixed | 1 +
salt/modules/event.py | 4 ++--
tests/pytests/integration/modules/test_event.py | 12 +++++++++++-
3 files changed, 14 insertions(+), 3 deletions(-)
create mode 100644 changelog/61252.fixed
diff --git a/changelog/61252.fixed b/changelog/61252.fixed
new file mode 100644
index 0000000000..2692f9b7b7
--- /dev/null
+++ b/changelog/61252.fixed
@@ -0,0 +1 @@
+Fix salt-call event.event with pillar or grains
diff --git a/salt/modules/event.py b/salt/modules/event.py
index 03dad5e614..7fe701708b 100644
--- a/salt/modules/event.py
+++ b/salt/modules/event.py
@@ -216,13 +216,13 @@ def send(
if isinstance(with_grains, list):
data_dict["grains"] = _dict_subset(with_grains, __grains__)
else:
- data_dict["grains"] = __grains__
+ data_dict["grains"] = __grains__.value()
if with_pillar:
if isinstance(with_pillar, list):
data_dict["pillar"] = _dict_subset(with_pillar, __pillar__)
else:
- data_dict["pillar"] = __pillar__
+ data_dict["pillar"] = __pillar__.value()
if with_env_opts:
data_dict["saltenv"] = __opts__.get("saltenv", "base")
diff --git a/tests/pytests/integration/modules/test_event.py b/tests/pytests/integration/modules/test_event.py
index 54087b1b65..8912c1e807 100644
--- a/tests/pytests/integration/modules/test_event.py
+++ b/tests/pytests/integration/modules/test_event.py
@@ -68,7 +68,14 @@ def test_send(event_listener, salt_master, salt_minion, salt_call_cli):
event_tag = random_string("salt/test/event/")
data = {"event.fire": "just test it!!!!"}
start_time = time.time()
- ret = salt_call_cli.run("event.send", event_tag, data=data)
+ ret = salt_call_cli.run(
+ "event.send",
+ event_tag,
+ data=data,
+ with_grains=True,
+ with_pillar=True,
+ preload={"foo": "bar"},
+ )
assert ret.exitcode == 0
assert ret.json
assert ret.json is True
@@ -82,3 +89,6 @@ def test_send(event_listener, salt_master, salt_minion, salt_call_cli):
assert event.data["id"] == salt_minion.id
assert event.data["cmd"] == "_minion_event"
assert "event.fire" in event.data["data"]
+ assert event.data["foo"] == "bar"
+ assert event.data["data"]["grains"]["test_grain"] == "cheese"
+ assert event.data["data"]["pillar"]["ext_spam"] == "eggs"
--
2.34.1

View File

@ -1,4 +1,4 @@
From 7096332546a65c0c507fbd4bccbf7062e7c3c9c7 Mon Sep 17 00:00:00 2001
From 59200b4a4578c96dcffc0584725d8cba40c20ff7 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,19 +14,19 @@ 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 3e032c7197..bc77eb700e 100644
index 6db2dfcbb0..8ae417f575 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -340,7 +340,7 @@ class SSH:
@@ -338,7 +338,7 @@ class SSH(MultiprocessingStateMixin):
self.session_flock_file = os.path.join(
self.opts["cachedir"], "salt-ssh.session.lock"
)
- self.ssh_session_grace_time = int(self.opts.get("ssh_session_grace_time", 3))
+ self.ssh_session_grace_time = int(self.opts.get("ssh_session_grace_time", 1))
@property
def parse_tgt(self):
@@ -558,7 +558,6 @@ class SSH:
# __setstate__ and __getstate__ are only used on spawning platforms.
def __setstate__(self, state):
@@ -571,7 +571,6 @@ class SSH(MultiprocessingStateMixin):
"""
LOG_LOCK.release()
salt.loader.LOAD_LOCK.release()
@ -34,7 +34,7 @@ index 3e032c7197..bc77eb700e 100644
single = Single(
opts,
opts["argv"],
@@ -595,6 +594,7 @@ class SSH:
@@ -608,6 +607,7 @@ class SSH(MultiprocessingStateMixin):
Spin up the needed threads or processes and execute the subsequent
routines
"""
@ -42,7 +42,7 @@ index 3e032c7197..bc77eb700e 100644
que = multiprocessing.Queue()
running = {}
targets_queue = deque(self.targets.keys())
@@ -605,7 +605,7 @@ class SSH:
@@ -618,7 +618,7 @@ class SSH(MultiprocessingStateMixin):
if not self.targets:
log.error("No matching targets found in roster.")
break
@ -51,7 +51,7 @@ index 3e032c7197..bc77eb700e 100644
if targets_queue:
host = targets_queue.popleft()
else:
@@ -623,7 +623,7 @@ class SSH:
@@ -636,7 +636,7 @@ class SSH(MultiprocessingStateMixin):
pid_running = (
False
if cached_session["pid"] == 0
@ -60,7 +60,7 @@ index 3e032c7197..bc77eb700e 100644
)
if (
pid_running and prev_session_running < self.max_pid_wait
@@ -638,9 +638,10 @@ class SSH:
@@ -651,9 +651,10 @@ class SSH(MultiprocessingStateMixin):
"salt-ssh/session",
host,
{
@ -72,7 +72,7 @@ index 3e032c7197..bc77eb700e 100644
},
)
for default in self.defaults:
@@ -668,7 +669,7 @@ class SSH:
@@ -681,7 +682,7 @@ class SSH(MultiprocessingStateMixin):
continue
args = (
que,
@ -81,7 +81,7 @@ index 3e032c7197..bc77eb700e 100644
host,
self.targets[host],
mine,
@@ -704,6 +705,7 @@ class SSH:
@@ -717,6 +718,7 @@ class SSH(MultiprocessingStateMixin):
"pid": routine.pid,
"master_id": self.master_id,
"ts": time.time(),
@ -89,7 +89,7 @@ index 3e032c7197..bc77eb700e 100644
},
)
continue
@@ -755,12 +757,13 @@ class SSH:
@@ -768,12 +770,13 @@ class SSH(MultiprocessingStateMixin):
"pid": 0,
"master_id": self.master_id,
"ts": time.time(),
@ -105,10 +105,10 @@ index 3e032c7197..bc77eb700e 100644
) >= len(running):
time.sleep(0.1)
diff --git a/salt/loader/__init__.py b/salt/loader/__init__.py
index a0f2220476..bc3634bb7f 100644
index 32f8a7702c..bbe4269839 100644
--- a/salt/loader/__init__.py
+++ b/salt/loader/__init__.py
@@ -622,7 +622,12 @@ def roster(opts, runner=None, utils=None, whitelist=None, context=None):
@@ -757,7 +757,12 @@ def roster(opts, runner=None, utils=None, whitelist=None, loaded_base_name=None,
opts,
tag="roster",
whitelist=whitelist,
@ -120,9 +120,9 @@ index a0f2220476..bc3634bb7f 100644
+ "__opts__": opts,
+ },
extra_module_dirs=utils.module_dirs if utils else None,
loaded_base_name=loaded_base_name,
)
--
2.35.1
2.37.3

View File

@ -1,8 +1,8 @@
From 10705d922a11e5f2654d26e83e9f302862fafb18 Mon Sep 17 00:00:00 2001
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)
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:
@ -33,13 +33,9 @@ Fixes #62066.
[Cherry-picked from upstream commit
95bfbe31a2dc54723af3f1783d40de152760fe1a.]
---
changelog/62066.fixed | 1 +
salt/modules/file.py | 27 +++-
salt/states/file.py | 1 +
.../unit/modules/file/test_file_check.py | 144 ++++++++++++++++++
4 files changed, 172 insertions(+), 1 deletion(-)
changelog/62066.fixed | 1 +
1 file changed, 1 insertion(+)
create mode 100644 changelog/62066.fixed
create mode 100644 tests/pytests/unit/modules/file/test_file_check.py
diff --git a/changelog/62066.fixed b/changelog/62066.fixed
new file mode 100644
@ -48,261 +44,7 @@ index 0000000000..68216a03c1
+++ b/changelog/62066.fixed
@@ -0,0 +1 @@
+Fixed salt.states.file.managed() for follow_symlinks=True and test=True
diff --git a/salt/modules/file.py b/salt/modules/file.py
index 73619064ef..40c07455e3 100644
--- a/salt/modules/file.py
+++ b/salt/modules/file.py
@@ -5281,11 +5281,18 @@ def check_managed(
serole=None,
setype=None,
serange=None,
+ follow_symlinks=False,
**kwargs
):
"""
Check to see what changes need to be made for a file
+ follow_symlinks
+ If the desired path is a symlink, follow it and check the permissions
+ of the file to which the symlink points.
+
+ .. versionadded:: 3005
+
CLI Example:
.. code-block:: bash
@@ -5336,6 +5343,7 @@ def check_managed(
serole=serole,
setype=setype,
serange=serange,
+ follow_symlinks=follow_symlinks,
)
# Ignore permission for files written temporary directories
# Files in any path will still be set correctly using get_managed()
@@ -5372,6 +5380,7 @@ def check_managed_changes(
setype=None,
serange=None,
verify_ssl=True,
+ follow_symlinks=False,
**kwargs
):
"""
@@ -5387,6 +5396,12 @@ def check_managed_changes(
.. versionadded:: 3002
+ follow_symlinks
+ If the desired path is a symlink, follow it and check the permissions
+ of the file to which the symlink points.
+
+ .. versionadded:: 3005
+
CLI Example:
.. code-block:: bash
@@ -5456,6 +5471,7 @@ def check_managed_changes(
serole=serole,
setype=setype,
serange=serange,
+ follow_symlinks=follow_symlinks,
)
__clean_tmp(sfn)
return changes
@@ -5477,6 +5493,7 @@ def check_file_meta(
setype=None,
serange=None,
verify_ssl=True,
+ follow_symlinks=False,
):
"""
Check for the changes in the file metadata.
@@ -5553,6 +5570,12 @@ def check_file_meta(
will not attempt to validate the servers certificate. Default is True.
.. versionadded:: 3002
+
+ follow_symlinks
+ If the desired path is a symlink, follow it and check the permissions
+ of the file to which the symlink points.
+
+ .. versionadded:: 3005
"""
changes = {}
if not source_sum:
@@ -5560,7 +5583,9 @@ def check_file_meta(
try:
lstats = stats(
- name, hash_type=source_sum.get("hash_type", None), follow_symlinks=False
+ name,
+ hash_type=source_sum.get("hash_type", None),
+ follow_symlinks=follow_symlinks,
)
except CommandExecutionError:
lstats = {}
diff --git a/salt/states/file.py b/salt/states/file.py
index 54e7decf86..a6288025e5 100644
--- a/salt/states/file.py
+++ b/salt/states/file.py
@@ -3038,6 +3038,7 @@ def managed(
setype=setype,
serange=serange,
verify_ssl=verify_ssl,
+ follow_symlinks=follow_symlinks,
**kwargs
)
diff --git a/tests/pytests/unit/modules/file/test_file_check.py b/tests/pytests/unit/modules/file/test_file_check.py
new file mode 100644
index 0000000000..bd0379ddae
--- /dev/null
+++ b/tests/pytests/unit/modules/file/test_file_check.py
@@ -0,0 +1,144 @@
+import getpass
+import logging
+import os
+
+import pytest
+import salt.modules.file as filemod
+import salt.utils.files
+import salt.utils.platform
+
+log = logging.getLogger(__name__)
+
+
+@pytest.fixture
+def configure_loader_modules():
+ return {filemod: {"__context__": {}}}
+
+
+@pytest.fixture
+def tfile(tmp_path):
+ filename = str(tmp_path / "file-check-test-file")
+
+ with salt.utils.files.fopen(filename, "w") as fp:
+ fp.write("Hi hello! I am a file.")
+ os.chmod(filename, 0o644)
+
+ yield filename
+
+ os.remove(filename)
+
+
+@pytest.fixture
+def a_link(tmp_path, tfile):
+ linkname = str(tmp_path / "a_link")
+ os.symlink(tfile, linkname)
+
+ yield linkname
+
+ os.remove(linkname)
+
+
+def get_link_perms():
+ if salt.utils.platform.is_linux():
+ return "0777"
+ return "0755"
+
+
+@pytest.mark.skip_on_windows(reason="os.symlink is not available on Windows")
+def test_check_file_meta_follow_symlinks(a_link, tfile):
+ user = getpass.getuser()
+ lperms = get_link_perms()
+
+ # follow_symlinks=False (default)
+ ret = filemod.check_file_meta(
+ a_link, tfile, None, None, user, None, lperms, None, None
+ )
+ assert ret == {}
+
+ ret = filemod.check_file_meta(
+ a_link, tfile, None, None, user, None, "0644", None, None
+ )
+ assert ret == {"mode": "0644"}
+
+ # follow_symlinks=True
+ ret = filemod.check_file_meta(
+ a_link, tfile, None, None, user, None, "0644", None, None, follow_symlinks=True
+ )
+ assert ret == {}
+
+
+@pytest.mark.skip_on_windows(reason="os.symlink is not available on Windows")
+def test_check_managed_follow_symlinks(a_link, tfile):
+ user = getpass.getuser()
+ lperms = get_link_perms()
+
+ # Function check_managed() ignores mode changes for files in the temp directory.
+ # Trick it to not recognize a_link as such.
+ a_link = "/" + a_link
+
+ # follow_symlinks=False (default)
+ ret, comments = filemod.check_managed(
+ a_link, tfile, None, None, user, None, lperms, None, None, None, None, None
+ )
+ assert ret is True
+ assert comments == "The file {} is in the correct state".format(a_link)
+
+ ret, comments = filemod.check_managed(
+ a_link, tfile, None, None, user, None, "0644", None, None, None, None, None
+ )
+ assert ret is None
+ assert comments == "The following values are set to be changed:\nmode: 0644\n"
+
+ # follow_symlinks=True
+ ret, comments = filemod.check_managed(
+ a_link,
+ tfile,
+ None,
+ None,
+ user,
+ None,
+ "0644",
+ None,
+ None,
+ None,
+ None,
+ None,
+ follow_symlinks=True,
+ )
+ assert ret is True
+ assert comments == "The file {} is in the correct state".format(a_link)
+
+
+@pytest.mark.skip_on_windows(reason="os.symlink is not available on Windows")
+def test_check_managed_changes_follow_symlinks(a_link, tfile):
+ user = getpass.getuser()
+ lperms = get_link_perms()
+
+ # follow_symlinks=False (default)
+ ret = filemod.check_managed_changes(
+ a_link, tfile, None, None, user, None, lperms, None, None, None, None, None
+ )
+ assert ret == {}
+
+ ret = filemod.check_managed_changes(
+ a_link, tfile, None, None, user, None, "0644", None, None, None, None, None
+ )
+ assert ret == {"mode": "0644"}
+
+ # follow_symlinks=True
+ ret = filemod.check_managed_changes(
+ a_link,
+ tfile,
+ None,
+ None,
+ user,
+ None,
+ "0644",
+ None,
+ None,
+ None,
+ None,
+ None,
+ follow_symlinks=True,
+ )
+ assert ret == {}
--
2.36.1
2.37.3

View File

@ -1,4 +1,4 @@
From 435d9fbee299b06e1c58cdc0574b6a1975841879 Mon Sep 17 00:00:00 2001
From f348f291093ea3f7c841b03a975ae81b40963842 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
@ -10,10 +10,10 @@ Subject: [PATCH] Fix salt.utils.stringutils.to_str calls to make it
2 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/salt/modules/file.py b/salt/modules/file.py
index b830b390d3..b9744393d7 100644
index d475e3c2e3..d3de4da467 100644
--- a/salt/modules/file.py
+++ b/salt/modules/file.py
@@ -4970,6 +4970,12 @@ def check_perms(
@@ -5036,6 +5036,12 @@ def check_perms(
is_dir = os.path.isdir(name)
is_link = os.path.islink(name)
@ -26,7 +26,7 @@ index b830b390d3..b9744393d7 100644
# user/group changes if needed, then check if it worked
if user:
if isinstance(user, int):
@@ -4979,7 +4985,7 @@ def check_perms(
@@ -5045,7 +5051,7 @@ def check_perms(
and user_to_uid(user) != user_to_uid(perms["luser"])
) or (
not salt.utils.platform.is_windows()
@ -35,7 +35,7 @@ index b830b390d3..b9744393d7 100644
):
perms["cuser"] = user
@@ -4991,7 +4997,7 @@ def check_perms(
@@ -5057,7 +5063,7 @@ def check_perms(
and group_to_gid(group) != group_to_gid(perms["lgroup"])
) or (
not salt.utils.platform.is_windows()
@ -44,7 +44,7 @@ index b830b390d3..b9744393d7 100644
):
perms["cgroup"] = group
@@ -5023,8 +5029,7 @@ def check_perms(
@@ -5089,8 +5095,7 @@ def check_perms(
and user != ""
) or (
not salt.utils.platform.is_windows()
@ -54,7 +54,7 @@ index b830b390d3..b9744393d7 100644
and user != ""
):
if __opts__["test"] is True:
@@ -5045,8 +5050,7 @@ def check_perms(
@@ -5111,8 +5116,7 @@ def check_perms(
and group != ""
) or (
not salt.utils.platform.is_windows()
@ -65,10 +65,10 @@ index b830b390d3..b9744393d7 100644
):
if __opts__["test"] is True:
diff --git a/salt/states/file.py b/salt/states/file.py
index 89c70eb454..fd8ffde757 100644
index 50ceef1158..1083bb46d6 100644
--- a/salt/states/file.py
+++ b/salt/states/file.py
@@ -989,15 +989,22 @@ def _check_dir_meta(name, user, group, mode, follow_symlinks=False):
@@ -863,15 +863,22 @@ def _check_dir_meta(name, user, group, mode, follow_symlinks=False):
if not stats:
changes["directory"] = "new"
return changes
@ -94,6 +94,6 @@ index 89c70eb454..fd8ffde757 100644
):
changes["group"] = group
--
2.29.2
2.37.3

View File

@ -1,8 +1,8 @@
From ed567e5f339f7bf95d4361ac47e67427db71714c Mon Sep 17 00:00:00 2001
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)
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
@ -15,12 +15,11 @@ Co-authored-by: nicholasmhughes <nicholasmhughes@gmail.com>
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_directory.py | 55 +++++++++++++++++++
.../unit/states/file/test_filestate.py | 42 ++++++++++++++
.../pytests/unit/states/file/test_managed.py | 31 +++++++++++
6 files changed, 169 insertions(+)
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
@ -31,7 +30,7 @@ index 0000000000..c4024efe9f
@@ -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 a6288025e5..39cf83b78e 100644
index 1083bb46d6..5cb58f5454 100644
--- a/salt/states/file.py
+++ b/salt/states/file.py
@@ -379,6 +379,11 @@ def _check_user(user, group):
@ -89,69 +88,6 @@ index ce7161f02d..a11adf5ae0 100644
+ )
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
diff --git a/tests/pytests/unit/states/file/test_directory.py b/tests/pytests/unit/states/file/test_directory.py
index 0e15e1d3ca..1287609c6a 100644
--- a/tests/pytests/unit/states/file/test_directory.py
+++ b/tests/pytests/unit/states/file/test_directory.py
@@ -291,3 +291,58 @@ def test_directory():
assert (
filestate.directory(name, user=user, group=group) == ret
)
+
+
+def test_directory_test_mode_user_group_not_present():
+ name = "/etc/testdir"
+ user = "salt"
+ group = "saltstack"
+ if salt.utils.platform.is_windows():
+ name = name.replace("/", "\\")
+
+ ret = {
+ "name": name,
+ "result": None,
+ "comment": "",
+ "changes": {name: {"directory": "new"}},
+ }
+
+ if salt.utils.platform.is_windows():
+ comt = 'The directory "{}" will be changed' "".format(name)
+ else:
+ comt = "The following files will be changed:\n{}:" " directory - new\n".format(
+ name
+ )
+ ret["comment"] = comt
+
+ mock_f = MagicMock(return_value=False)
+ mock_uid = MagicMock(
+ side_effect=[
+ "",
+ "U12",
+ "",
+ ]
+ )
+ mock_gid = MagicMock(
+ side_effect=[
+ "G12",
+ "",
+ "",
+ ]
+ )
+ mock_error = CommandExecutionError
+ with patch.dict(
+ filestate.__salt__,
+ {
+ "file.user_to_uid": mock_uid,
+ "file.group_to_gid": mock_gid,
+ "file.stats": mock_f,
+ },
+ ), patch("salt.utils.win_dacl.get_sid", mock_error), patch.object(
+ os.path, "isdir", mock_f
+ ), patch.dict(
+ filestate.__opts__, {"test": True}
+ ):
+ assert filestate.directory(name, user=user, group=group) == ret
+ assert filestate.directory(name, user=user, group=group) == ret
+ assert filestate.directory(name, user=user, group=group) == ret
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
@ -242,6 +178,6 @@ index 9d9fb17717..0b341e09a9 100644
+ assert ret["result"] is not False
+ assert "is not available" not in ret["comment"]
--
2.37.2
2.37.3

View File

@ -1,4 +1,4 @@
From 61d9b5e4ceaa0f5feb7fc364c9089cb624006812 Mon Sep 17 00:00:00 2001
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
@ -8,10 +8,10 @@ Subject: [PATCH] Fix test_ipc unit tests
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tests/unit/transport/test_ipc.py b/tests/unit/transport/test_ipc.py
index 79b49f9406..7177b7f6c4 100644
index 4a0a7c29e2..af001d9650 100644
--- a/tests/unit/transport/test_ipc.py
+++ b/tests/unit/transport/test_ipc.py
@@ -107,8 +107,8 @@ class IPCMessagePubSubCase(salt.ext.tornado.testing.AsyncTestCase):
@@ -105,8 +105,8 @@ class IPCMessagePubSubCase(salt.ext.tornado.testing.AsyncTestCase):
self.stop()
# Now let both waiting data at once
@ -22,7 +22,7 @@ index 79b49f9406..7177b7f6c4 100644
self.pub_channel.publish("TEST")
self.wait()
self.assertEqual(len(call_cnt), 2)
@@ -150,7 +150,7 @@ class IPCMessagePubSubCase(salt.ext.tornado.testing.AsyncTestCase):
@@ -148,7 +148,7 @@ class IPCMessagePubSubCase(salt.ext.tornado.testing.AsyncTestCase):
pass
try:
@ -32,6 +32,6 @@ index 79b49f9406..7177b7f6c4 100644
except StreamClosedError as ex:
assert False, "StreamClosedError was raised inside the Future"
--
2.36.1
2.37.3

View File

@ -1,4 +1,4 @@
From a33a7b2e8e477912548cfd24c0dff2c38c44eae8 Mon Sep 17 00:00:00 2001
From 48a924bfad537f236593395a9d4cf108d6e9a03f 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.33.1
2.37.3

View File

@ -1,820 +0,0 @@
From 7803275a8aaeedf2124706f51b6a54cfcfb2d032 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <Victor.Zhestkov@suse.com>
Date: Thu, 1 Sep 2022 14:45:13 +0300
Subject: [PATCH] Fix the regression in schedule module releasded in
3004 (bsc#1202631)
Co-authored-by: Gareth J. Greenaway <gareth@saltstack.com>
---
changelog/61324.changed | 1 +
salt/modules/schedule.py | 449 ++++++++++++++------
tests/pytests/unit/modules/test_schedule.py | 138 +++++-
3 files changed, 442 insertions(+), 146 deletions(-)
create mode 100644 changelog/61324.changed
diff --git a/changelog/61324.changed b/changelog/61324.changed
new file mode 100644
index 0000000000..d67051a8da
--- /dev/null
+++ b/changelog/61324.changed
@@ -0,0 +1 @@
+Adding the ability to add, delete, purge, and modify Salt scheduler jobs when the Salt minion is not running.
diff --git a/salt/modules/schedule.py b/salt/modules/schedule.py
index bcd64f2851..913a101ea6 100644
--- a/salt/modules/schedule.py
+++ b/salt/modules/schedule.py
@@ -15,6 +15,7 @@ import salt.utils.event
import salt.utils.files
import salt.utils.odict
import salt.utils.yaml
+import yaml
try:
import dateutil.parser as dateutil_parser
@@ -64,7 +65,35 @@ SCHEDULE_CONF = [
]
-def list_(show_all=False, show_disabled=True, where=None, return_yaml=True):
+def _get_schedule_config_file():
+ """
+ Return the minion schedule configuration file
+ """
+ config_dir = __opts__.get("conf_dir", None)
+ if config_dir is None and "conf_file" in __opts__:
+ config_dir = os.path.dirname(__opts__["conf_file"])
+ if config_dir is None:
+ config_dir = salt.syspaths.CONFIG_DIR
+
+ minion_d_dir = os.path.join(
+ config_dir,
+ os.path.dirname(
+ __opts__.get(
+ "default_include",
+ salt.config.DEFAULT_MINION_OPTS["default_include"],
+ )
+ ),
+ )
+
+ if not os.path.isdir(minion_d_dir):
+ os.makedirs(minion_d_dir)
+
+ return os.path.join(minion_d_dir, "_schedule.conf")
+
+
+def list_(
+ show_all=False, show_disabled=True, where=None, return_yaml=True, offline=False
+):
"""
List the jobs currently scheduled on the minion
@@ -83,24 +112,33 @@ def list_(show_all=False, show_disabled=True, where=None, return_yaml=True):
"""
schedule = {}
- try:
- with salt.utils.event.get_event("minion", opts=__opts__) as event_bus:
- res = __salt__["event.fire"](
- {"func": "list", "where": where}, "manage_schedule"
- )
- if res:
- event_ret = event_bus.get_event(
- tag="/salt/minion/minion_schedule_list_complete", wait=30
+ if offline:
+ schedule_config = _get_schedule_config_file()
+ if os.path.exists(schedule_config):
+ with salt.utils.files.fopen(schedule_config) as fp_:
+ schedule_yaml = fp_.read()
+ if schedule_yaml:
+ schedule_contents = yaml.safe_load(schedule_yaml)
+ schedule = schedule_contents.get("schedule", {})
+ else:
+ try:
+ with salt.utils.event.get_event("minion", opts=__opts__) as event_bus:
+ res = __salt__["event.fire"](
+ {"func": "list", "where": where}, "manage_schedule"
)
- if event_ret and event_ret["complete"]:
- schedule = event_ret["schedule"]
- except KeyError:
- # Effectively a no-op, since we can't really return without an event system
- ret = {}
- ret["comment"] = "Event module not available. Schedule list failed."
- ret["result"] = True
- log.debug("Event module not available. Schedule list failed.")
- return ret
+ if res:
+ event_ret = event_bus.get_event(
+ tag="/salt/minion/minion_schedule_list_complete", wait=30
+ )
+ if event_ret and event_ret["complete"]:
+ schedule = event_ret["schedule"]
+ except KeyError:
+ # Effectively a no-op, since we can't really return without an event system
+ ret = {}
+ ret["comment"] = "Event module not available. Schedule list failed."
+ ret["result"] = True
+ log.debug("Event module not available. Schedule list failed.")
+ return ret
_hidden = ["enabled", "skip_function", "skip_during_range"]
for job in list(schedule.keys()): # iterate over a copy since we will mutate it
@@ -139,14 +177,11 @@ def list_(show_all=False, show_disabled=True, where=None, return_yaml=True):
# remove _seconds from the listing
del schedule[job]["_seconds"]
- if schedule:
- if return_yaml:
- tmp = {"schedule": schedule}
- return salt.utils.yaml.safe_dump(tmp, default_flow_style=False)
- else:
- return schedule
+ if return_yaml:
+ tmp = {"schedule": schedule}
+ return salt.utils.yaml.safe_dump(tmp, default_flow_style=False)
else:
- return {"schedule": {}}
+ return schedule
def is_enabled(name=None):
@@ -186,11 +221,18 @@ def purge(**kwargs):
.. code-block:: bash
salt '*' schedule.purge
+
+ # Purge jobs on Salt minion
+ salt '*' schedule.purge
+
"""
- ret = {"comment": [], "result": True}
+ ret = {"comment": [], "changes": {}, "result": True}
- for name in list_(show_all=True, return_yaml=False):
+ current_schedule = list_(
+ show_all=True, return_yaml=False, offline=kwargs.get("offline")
+ )
+ for name in pycopy.deepcopy(current_schedule):
if name == "enabled":
continue
if name.startswith("__"):
@@ -202,37 +244,65 @@ def purge(**kwargs):
"Job: {} would be deleted from schedule.".format(name)
)
else:
- persist = kwargs.get("persist", True)
+ if kwargs.get("offline"):
+ del current_schedule[name]
- try:
- with salt.utils.event.get_event("minion", opts=__opts__) as event_bus:
- res = __salt__["event.fire"](
- {"name": name, "func": "delete", "persist": persist},
- "manage_schedule",
- )
- if res:
- event_ret = event_bus.get_event(
- tag="/salt/minion/minion_schedule_delete_complete", wait=30
+ ret["comment"].append("Deleted job: {} from schedule.".format(name))
+ ret["changes"][name] = "removed"
+
+ else:
+ persist = kwargs.get("persist", True)
+ try:
+ with salt.utils.event.get_event(
+ "minion", opts=__opts__
+ ) as event_bus:
+ res = __salt__["event.fire"](
+ {"name": name, "func": "delete", "persist": persist},
+ "manage_schedule",
)
- if event_ret and event_ret["complete"]:
- _schedule_ret = event_ret["schedule"]
- if name not in _schedule_ret:
- ret["result"] = True
- ret["comment"].append(
- "Deleted job: {} from schedule.".format(name)
- )
- else:
- ret["comment"].append(
- "Failed to delete job {} from schedule.".format(
- name
+ if res:
+ event_ret = event_bus.get_event(
+ tag="/salt/minion/minion_schedule_delete_complete",
+ wait=30,
+ )
+ if event_ret and event_ret["complete"]:
+ _schedule_ret = event_ret["schedule"]
+ if name not in _schedule_ret:
+ ret["result"] = True
+ ret["changes"][name] = "removed"
+ ret["comment"].append(
+ "Deleted job: {} from schedule.".format(name)
)
- )
- ret["result"] = True
+ else:
+ ret["comment"].append(
+ "Failed to delete job {} from schedule.".format(
+ name
+ )
+ )
+ ret["result"] = True
+
+ except KeyError:
+ # Effectively a no-op, since we can't really return without an event system
+ ret["comment"] = "Event module not available. Schedule add failed."
+ ret["result"] = True
+
+ # wait until the end to write file in offline mode
+ if kwargs.get("offline"):
+ schedule_conf = _get_schedule_config_file()
+
+ try:
+ with salt.utils.files.fopen(schedule_conf, "wb+") as fp_:
+ fp_.write(
+ salt.utils.stringutils.to_bytes(
+ salt.utils.yaml.safe_dump({"schedule": current_schedule})
+ )
+ )
+ except OSError:
+ log.error(
+ "Failed to persist the updated schedule",
+ exc_info_on_loglevel=logging.DEBUG,
+ )
- except KeyError:
- # Effectively a no-op, since we can't really return without an event system
- ret["comment"] = "Event module not available. Schedule add failed."
- ret["result"] = True
return ret
@@ -245,6 +315,10 @@ def delete(name, **kwargs):
.. code-block:: bash
salt '*' schedule.delete job1
+
+ # Delete job on Salt minion when the Salt minion is not running
+ salt '*' schedule.delete job1
+
"""
ret = {
@@ -260,45 +334,86 @@ def delete(name, **kwargs):
ret["comment"] = "Job: {} would be deleted from schedule.".format(name)
ret["result"] = True
else:
- persist = kwargs.get("persist", True)
+ if kwargs.get("offline"):
+ current_schedule = list_(
+ show_all=True,
+ where="opts",
+ return_yaml=False,
+ offline=kwargs.get("offline"),
+ )
- if name in list_(show_all=True, where="opts", return_yaml=False):
- event_data = {"name": name, "func": "delete", "persist": persist}
- elif name in list_(show_all=True, where="pillar", return_yaml=False):
- event_data = {
- "name": name,
- "where": "pillar",
- "func": "delete",
- "persist": False,
- }
- else:
- ret["comment"] = "Job {} does not exist.".format(name)
- return ret
+ del current_schedule[name]
- try:
- with salt.utils.event.get_event("minion", opts=__opts__) as event_bus:
- res = __salt__["event.fire"](event_data, "manage_schedule")
- if res:
- event_ret = event_bus.get_event(
- tag="/salt/minion/minion_schedule_delete_complete",
- wait=30,
+ schedule_conf = _get_schedule_config_file()
+
+ try:
+ with salt.utils.files.fopen(schedule_conf, "wb+") as fp_:
+ fp_.write(
+ salt.utils.stringutils.to_bytes(
+ salt.utils.yaml.safe_dump({"schedule": current_schedule})
+ )
)
- if event_ret and event_ret["complete"]:
- schedule = event_ret["schedule"]
- if name not in schedule:
- ret["result"] = True
- ret["comment"] = "Deleted Job {} from schedule.".format(
- name
- )
- ret["changes"][name] = "removed"
- else:
- ret[
- "comment"
- ] = "Failed to delete job {} from schedule.".format(name)
- return ret
- except KeyError:
- # Effectively a no-op, since we can't really return without an event system
- ret["comment"] = "Event module not available. Schedule add failed."
+ except OSError:
+ log.error(
+ "Failed to persist the updated schedule",
+ exc_info_on_loglevel=logging.DEBUG,
+ )
+
+ ret["result"] = True
+ ret["comment"] = "Deleted Job {} from schedule.".format(name)
+ ret["changes"][name] = "removed"
+ else:
+ persist = kwargs.get("persist", True)
+
+ if name in list_(
+ show_all=True,
+ where="opts",
+ return_yaml=False,
+ offline=kwargs.get("offline"),
+ ):
+ event_data = {"name": name, "func": "delete", "persist": persist}
+ elif name in list_(
+ show_all=True,
+ where="pillar",
+ return_yaml=False,
+ offline=kwargs.get("offline"),
+ ):
+ event_data = {
+ "name": name,
+ "where": "pillar",
+ "func": "delete",
+ "persist": False,
+ }
+ else:
+ ret["comment"] = "Job {} does not exist.".format(name)
+ return ret
+
+ try:
+ with salt.utils.event.get_event("minion", opts=__opts__) as event_bus:
+ res = __salt__["event.fire"](event_data, "manage_schedule")
+ if res:
+ event_ret = event_bus.get_event(
+ tag="/salt/minion/minion_schedule_delete_complete",
+ wait=30,
+ )
+ if event_ret and event_ret["complete"]:
+ schedule = event_ret["schedule"]
+ if name not in schedule:
+ ret["result"] = True
+ ret["comment"] = "Deleted Job {} from schedule.".format(
+ name
+ )
+ ret["changes"][name] = "removed"
+ else:
+ ret[
+ "comment"
+ ] = "Failed to delete job {} from schedule.".format(
+ name
+ )
+ return ret
+ except KeyError:
+ # Effectively a no-op, since we can't really return without an event system
+ ret["comment"] = "Event module not available. Schedule add failed."
return ret
@@ -438,6 +553,10 @@ def add(name, **kwargs):
salt '*' schedule.add job1 function='test.ping' seconds=3600
# If function have some arguments, use job_args
salt '*' schedule.add job2 function='cmd.run' job_args="['date >> /tmp/date.log']" seconds=60
+
+ # Add job to Salt minion when the Salt minion is not running
+ salt '*' schedule.add job1 function='test.ping' seconds=3600 offline=True
+
"""
ret = {
@@ -445,8 +564,11 @@ def add(name, **kwargs):
"result": False,
"changes": {},
}
+ current_schedule = list_(
+ show_all=True, return_yaml=False, offline=kwargs.get("offline")
+ )
- if name in list_(show_all=True, return_yaml=False):
+ if name in current_schedule:
ret["comment"] = "Job {} already exists in schedule.".format(name)
ret["result"] = False
return ret
@@ -486,32 +608,56 @@ def add(name, **kwargs):
ret["comment"] = "Job: {} would be added to schedule.".format(name)
ret["result"] = True
else:
- try:
- with salt.utils.event.get_event("minion", opts=__opts__) as event_bus:
- res = __salt__["event.fire"](
- {
- "name": name,
- "schedule": schedule_data,
- "func": "add",
- "persist": persist,
- },
- "manage_schedule",
+ if kwargs.get("offline"):
+ current_schedule.update(schedule_data)
+
+ schedule_conf = _get_schedule_config_file()
+
+ try:
+ with salt.utils.files.fopen(schedule_conf, "wb+") as fp_:
+ fp_.write(
+ salt.utils.stringutils.to_bytes(
+ salt.utils.yaml.safe_dump({"schedule": current_schedule})
+ )
+ )
+ except OSError:
+ log.error(
+ "Failed to persist the updated schedule",
+ exc_info_on_loglevel=logging.DEBUG,
)
- if res:
- event_ret = event_bus.get_event(
- tag="/salt/minion/minion_schedule_add_complete",
- wait=30,
+
+ ret["result"] = True
+ ret["comment"] = "Added job: {} to schedule.".format(name)
+ ret["changes"][name] = "added"
+ else:
+ try:
+ with salt.utils.event.get_event("minion", opts=__opts__) as event_bus:
+ res = __salt__["event.fire"](
+ {
+ "name": name,
+ "schedule": schedule_data,
+ "func": "add",
+ "persist": persist,
+ },
+ "manage_schedule",
)
- if event_ret and event_ret["complete"]:
- schedule = event_ret["schedule"]
- if name in schedule:
- ret["result"] = True
- ret["comment"] = "Added job: {} to schedule.".format(name)
- ret["changes"][name] = "added"
- return ret
- except KeyError:
- # Effectively a no-op, since we can't really return without an event system
- ret["comment"] = "Event module not available. Schedule add failed."
+ if res:
+ event_ret = event_bus.get_event(
+ tag="/salt/minion/minion_schedule_add_complete",
+ wait=30,
+ )
+ if event_ret and event_ret["complete"]:
+ schedule = event_ret["schedule"]
+ if name in schedule:
+ ret["result"] = True
+ ret["comment"] = "Added job: {} to schedule.".format(
+ name
+ )
+ ret["changes"][name] = "added"
+ return ret
+ except KeyError:
+ # Effectively a no-op, since we can't really return without an event system
+ ret["comment"] = "Event module not available. Schedule add failed."
return ret
@@ -524,6 +670,10 @@ def modify(name, **kwargs):
.. code-block:: bash
salt '*' schedule.modify job1 function='test.ping' seconds=3600
+
+ # Modify job on Salt minion when the Salt minion is not running
+ salt '*' schedule.modify job1 function='test.ping' seconds=3600 offline=True
+
"""
ret = {"comment": "", "changes": {}, "result": True}
@@ -549,7 +699,9 @@ def modify(name, **kwargs):
ret["comment"] = 'Unable to use "when" and "cron" options together. Ignoring.'
return ret
- current_schedule = list_(show_all=True, return_yaml=False)
+ current_schedule = list_(
+ show_all=True, return_yaml=False, offline=kwargs.get("offline")
+ )
if name not in current_schedule:
ret["comment"] = "Job {} does not exist in schedule.".format(name)
@@ -566,8 +718,7 @@ def modify(name, **kwargs):
_current["seconds"] = _current.pop("_seconds")
# Copy _current _new, then update values from kwargs
- _new = pycopy.deepcopy(_current)
- _new.update(kwargs)
+ _new = build_schedule_item(name, **kwargs)
# Remove test from kwargs, it's not a valid schedule option
_new.pop("test", None)
@@ -587,29 +738,51 @@ def modify(name, **kwargs):
if "test" in kwargs and kwargs["test"]:
ret["comment"] = "Job: {} would be modified in schedule.".format(name)
else:
- persist = kwargs.get("persist", True)
- if name in list_(show_all=True, where="opts", return_yaml=False):
- event_data = {
- "name": name,
- "schedule": _new,
- "func": "modify",
- "persist": persist,
- }
- elif name in list_(show_all=True, where="pillar", return_yaml=False):
- event_data = {
- "name": name,
- "schedule": _new,
- "where": "pillar",
- "func": "modify",
- "persist": False,
- }
+ if kwargs.get("offline"):
+ current_schedule[name].update(_new)
- out = __salt__["event.fire"](event_data, "manage_schedule")
- if out:
+ schedule_conf = _get_schedule_config_file()
+
+ try:
+ with salt.utils.files.fopen(schedule_conf, "wb+") as fp_:
+ fp_.write(
+ salt.utils.stringutils.to_bytes(
+ salt.utils.yaml.safe_dump({"schedule": current_schedule})
+ )
+ )
+ except OSError:
+ log.error(
+ "Failed to persist the updated schedule",
+ exc_info_on_loglevel=logging.DEBUG,
+ )
+
+ ret["result"] = True
ret["comment"] = "Modified job: {} in schedule.".format(name)
+
else:
- ret["comment"] = "Failed to modify job {} in schedule.".format(name)
- ret["result"] = False
+ persist = kwargs.get("persist", True)
+ if name in list_(show_all=True, where="opts", return_yaml=False):
+ event_data = {
+ "name": name,
+ "schedule": _new,
+ "func": "modify",
+ "persist": persist,
+ }
+ elif name in list_(show_all=True, where="pillar", return_yaml=False):
+ event_data = {
+ "name": name,
+ "schedule": _new,
+ "where": "pillar",
+ "func": "modify",
+ "persist": False,
+ }
+
+ out = __salt__["event.fire"](event_data, "manage_schedule")
+ if out:
+ ret["comment"] = "Modified job: {} in schedule.".format(name)
+ else:
+ ret["comment"] = "Failed to modify job {} in schedule.".format(name)
+ ret["result"] = False
return ret
diff --git a/tests/pytests/unit/modules/test_schedule.py b/tests/pytests/unit/modules/test_schedule.py
index e6cb134982..02914be82f 100644
--- a/tests/pytests/unit/modules/test_schedule.py
+++ b/tests/pytests/unit/modules/test_schedule.py
@@ -8,7 +8,8 @@ import pytest
import salt.modules.schedule as schedule
import salt.utils.odict
from salt.utils.event import SaltEvent
-from tests.support.mock import MagicMock, patch
+from salt.utils.odict import OrderedDict
+from tests.support.mock import MagicMock, call, mock_open, patch
log = logging.getLogger(__name__)
@@ -29,6 +30,11 @@ def sock_dir(tmp_path):
return str(tmp_path / "test-socks")
+@pytest.fixture
+def schedule_config_file(tmp_path):
+ return "/etc/salt/minion.d/_schedule.conf"
+
+
@pytest.fixture
def configure_loader_modules():
return {schedule: {}}
@@ -36,24 +42,56 @@ def configure_loader_modules():
# 'purge' function tests: 1
@pytest.mark.slow_test
-def test_purge(sock_dir):
+def test_purge(sock_dir, job1, schedule_config_file):
"""
Test if it purge all the jobs currently scheduled on the minion.
"""
+ _schedule_data = {"job1": job1}
with patch.dict(schedule.__opts__, {"schedule": {}, "sock_dir": sock_dir}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {"event.fire": mock}):
_ret_value = {"complete": True, "schedule": {}}
with patch.object(SaltEvent, "get_event", return_value=_ret_value):
- assert schedule.purge() == {
- "comment": ["Deleted job: schedule from schedule."],
+ with patch.object(
+ schedule, "list_", MagicMock(return_value=_schedule_data)
+ ):
+ assert schedule.purge() == {
+ "comment": ["Deleted job: job1 from schedule."],
+ "changes": {"job1": "removed"},
+ "result": True,
+ }
+
+ _schedule_data = {"job1": job1, "job2": job1, "job3": job1}
+ comm = [
+ "Deleted job: job1 from schedule.",
+ "Deleted job: job2 from schedule.",
+ "Deleted job: job3 from schedule.",
+ ]
+
+ changes = {"job1": "removed", "job2": "removed", "job3": "removed"}
+
+ with patch.dict(
+ schedule.__opts__, {"schedule": {"job1": "salt"}, "sock_dir": sock_dir}
+ ):
+ with patch("salt.utils.files.fopen", mock_open(read_data="")) as fopen_mock:
+ with patch.object(
+ schedule, "list_", MagicMock(return_value=_schedule_data)
+ ):
+ assert schedule.purge(offline=True) == {
+ "comment": comm,
+ "changes": changes,
"result": True,
}
+ _call = call(b"schedule: {}\n")
+ write_calls = fopen_mock.filehandles[schedule_config_file][
+ 0
+ ].write._mock_mock_calls
+ assert _call in write_calls
# 'delete' function tests: 1
@pytest.mark.slow_test
-def test_delete(sock_dir):
+def test_delete(sock_dir, job1, schedule_config_file):
"""
Test if it delete a job from the minion's schedule.
"""
@@ -68,6 +106,28 @@ def test_delete(sock_dir):
"result": False,
}
+ _schedule_data = {"job1": job1}
+ comm = "Deleted Job job1 from schedule."
+ changes = {"job1": "removed"}
+ with patch.dict(
+ schedule.__opts__, {"schedule": {"job1": "salt"}, "sock_dir": sock_dir}
+ ):
+ with patch("salt.utils.files.fopen", mock_open(read_data="")) as fopen_mock:
+ with patch.object(
+ schedule, "list_", MagicMock(return_value=_schedule_data)
+ ):
+ assert schedule.delete("job1", offline="True") == {
+ "comment": comm,
+ "changes": changes,
+ "result": True,
+ }
+
+ _call = call(b"schedule: {}\n")
+ write_calls = fopen_mock.filehandles[schedule_config_file][
+ 0
+ ].write._mock_mock_calls
+ assert _call in write_calls
+
# 'build_schedule_item' function tests: 1
def test_build_schedule_item(sock_dir):
@@ -120,7 +180,7 @@ def test_build_schedule_item_invalid_when(sock_dir):
@pytest.mark.slow_test
-def test_add(sock_dir):
+def test_add(sock_dir, schedule_config_file):
"""
Test if it add a job to the schedule.
"""
@@ -163,6 +223,24 @@ def test_add(sock_dir):
"result": True,
}
+ comm1 = "Added job: job3 to schedule."
+ changes1 = {"job3": "added"}
+ with patch.dict(
+ schedule.__opts__, {"schedule": {"job1": "salt"}, "sock_dir": sock_dir}
+ ):
+ with patch("salt.utils.files.fopen", mock_open(read_data="")) as fopen_mock:
+ assert schedule.add(
+ "job3", function="test.ping", seconds=3600, offline="True"
+ ) == {"comment": comm1, "changes": changes1, "result": True}
+
+ _call = call(
+ b"schedule:\n job3: {function: test.ping, seconds: 3600, maxrunning: 1, name: job3, enabled: true,\n jid_include: true}\n"
+ )
+ write_calls = fopen_mock.filehandles[schedule_config_file][
+ 1
+ ].write._mock_mock_calls
+ assert _call in write_calls
+
# 'run_job' function tests: 1
@@ -444,7 +522,7 @@ def test_copy(sock_dir, job1):
@pytest.mark.slow_test
-def test_modify(sock_dir):
+def test_modify(sock_dir, job1, schedule_config_file):
"""
Test if modifying job to the schedule.
"""
@@ -564,7 +642,6 @@ def test_modify(sock_dir):
for key in [
"maxrunning",
"function",
- "seconds",
"jid_include",
"name",
"enabled",
@@ -586,6 +663,51 @@ def test_modify(sock_dir):
ret = schedule.modify("job2", function="test.version", test=True)
assert ret == expected5
+ _schedule_data = {"job1": job1}
+ comm = "Modified job: job1 in schedule."
+ changes = {"job1": "removed"}
+
+ changes = {
+ "job1": {
+ "new": OrderedDict(
+ [
+ ("function", "test.version"),
+ ("maxrunning", 1),
+ ("name", "job1"),
+ ("enabled", True),
+ ("jid_include", True),
+ ]
+ ),
+ "old": OrderedDict(
+ [
+ ("function", "test.ping"),
+ ("maxrunning", 1),
+ ("name", "job1"),
+ ("jid_include", True),
+ ("enabled", True),
+ ]
+ ),
+ }
+ }
+ with patch.dict(
+ schedule.__opts__, {"schedule": {"job1": "salt"}, "sock_dir": sock_dir}
+ ):
+ with patch("salt.utils.files.fopen", mock_open(read_data="")) as fopen_mock:
+ with patch.object(
+ schedule, "list_", MagicMock(return_value=_schedule_data)
+ ):
+ assert schedule.modify(
+ "job1", function="test.version", offline="True"
+ ) == {"comment": comm, "changes": changes, "result": True}
+
+ _call = call(
+ b"schedule:\n job1: {enabled: true, function: test.version, jid_include: true, maxrunning: 1,\n name: job1}\n"
+ )
+ write_calls = fopen_mock.filehandles[schedule_config_file][
+ 0
+ ].write._mock_mock_calls
+ assert _call in write_calls
+
# 'is_enabled' function tests: 1
--
2.37.2

View File

@ -1,4 +1,4 @@
From 929942b15f377df21ae076ef9e25cf83639b1850 Mon Sep 17 00:00:00 2001
From 8b07b529458e1fc007c8ee848d66035b3403a22d 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 9f5be295be..1074a1989f 100644
index 93b8b3bd71..9531b6d2be 100644
--- a/tests/unit/states/test_pip_state.py
+++ b/tests/unit/states/test_pip_state.py
@@ -445,7 +445,7 @@ class PipStateInstallationErrorTest(TestCase):
@@ -441,7 +441,7 @@ class PipStateInstallationErrorTest(TestCase):
sys.stdout.flush()
sys.exit(2)
except Exception as exc:
@ -21,6 +21,6 @@ index 9f5be295be..1074a1989f 100644
sys.exit(3)
sys.exit(0)
--
2.34.1
2.37.3

View File

@ -1,82 +0,0 @@
From e3ef9165b66c3d74a3c3dbfe82ba58f7fa1613e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Thu, 12 Mar 2020 13:26:51 +0000
Subject: [PATCH] Fix wrong test_mod_del_repo_multiline_values test after
rebase
---
tests/integration/modules/test_pkg.py | 34 +++++++++++++++++++++------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/tests/integration/modules/test_pkg.py b/tests/integration/modules/test_pkg.py
index ccf69998fc..6a84ea0bc3 100644
--- a/tests/integration/modules/test_pkg.py
+++ b/tests/integration/modules/test_pkg.py
@@ -138,6 +138,10 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin):
self.run_function("pkg.del_repo", [repo])
@pytest.mark.slow_test
+ @pytest.mark.destructive_test
+ @pytest.mark.requires_salt_modules("pkg.mod_repo", "pkg.del_repo", "pkg.get_repo")
+ @pytest.mark.requires_network()
+ @requires_system_grains
def test_mod_del_repo_multiline_values(self):
"""
test modifying and deleting a software repository defined with multiline values
@@ -145,10 +149,13 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin):
os_grain = self.run_function("grains.item", ["os"])["os"]
repo = None
try:
- if os_grain in ["CentOS", "RedHat", "VMware Photon OS"]:
+ if os_grain in ["CentOS", "RedHat", "VMware Photon OS", "SUSE"]:
my_baseurl = (
"http://my.fake.repo/foo/bar/\n http://my.fake.repo.alt/foo/bar/"
)
+ expected_get_repo_baseurl_zypp = (
+ "http://my.fake.repo/foo/bar/%0A%20http://my.fake.repo.alt/foo/bar/"
+ )
expected_get_repo_baseurl = (
"http://my.fake.repo/foo/bar/\nhttp://my.fake.repo.alt/foo/bar/"
)
@@ -174,17 +181,30 @@ class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin):
enabled=enabled,
failovermethod=failovermethod,
)
- # return data from pkg.mod_repo contains the file modified at
- # the top level, so use next(iter(ret)) to get that key
self.assertNotEqual(ret, {})
- repo_info = ret[next(iter(ret))]
+ repo_info = {repo: ret}
self.assertIn(repo, repo_info)
- self.assertEqual(repo_info[repo]["baseurl"], my_baseurl)
+ if os_grain == "SUSE":
+ self.assertEqual(
+ repo_info[repo]["baseurl"], expected_get_repo_baseurl_zypp
+ )
+ else:
+ self.assertEqual(repo_info[repo]["baseurl"], my_baseurl)
ret = self.run_function("pkg.get_repo", [repo])
- self.assertEqual(ret["baseurl"], expected_get_repo_baseurl)
+ if os_grain == "SUSE":
+ self.assertEqual(
+ repo_info[repo]["baseurl"], expected_get_repo_baseurl_zypp
+ )
+ else:
+ self.assertEqual(ret["baseurl"], expected_get_repo_baseurl)
self.run_function("pkg.mod_repo", [repo])
ret = self.run_function("pkg.get_repo", [repo])
- self.assertEqual(ret["baseurl"], expected_get_repo_baseurl)
+ if os_grain == "SUSE":
+ self.assertEqual(
+ repo_info[repo]["baseurl"], expected_get_repo_baseurl_zypp
+ )
+ else:
+ self.assertEqual(ret["baseurl"], expected_get_repo_baseurl)
finally:
if repo is not None:
self.run_function("pkg.del_repo", [repo])
--
2.33.0

View File

@ -1,63 +0,0 @@
From 0def15837c3470f20ce85ec81e2c1d42cd933c23 Mon Sep 17 00:00:00 2001
From: nicholasmhughes <nicholasmhughes@gmail.com>
Date: Fri, 14 Feb 2020 22:03:42 -0500
Subject: [PATCH] fixes #56144 to enable hotadd profile support
---
doc/topics/cloud/vmware.rst | 8 ++++++++
salt/cloud/clouds/vmware.py | 12 ++++++++++++
2 files changed, 20 insertions(+)
diff --git a/doc/topics/cloud/vmware.rst b/doc/topics/cloud/vmware.rst
index bbc5cdff11..1a18ebf226 100644
--- a/doc/topics/cloud/vmware.rst
+++ b/doc/topics/cloud/vmware.rst
@@ -457,6 +457,14 @@ Set up an initial profile at ``/etc/salt/cloud.profiles`` or
Specifies whether the new virtual machine should be powered on or not. If
``template: True`` is set, this field is ignored. Default is ``power_on: True``.
+``cpu_hot_add``
+ Boolean value that enables hot-add support for modifying CPU resources while
+ the guest is powered on.
+
+``mem_hot_add``
+ Boolean value that enables hot-add support for modifying memory resources while
+ the guest is powered on.
+
``extra_config``
Specifies the additional configuration information for the virtual machine. This
describes a set of modifications to the additional options. If the key is already
diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py
index 1e9943ad78..4999ca089f 100644
--- a/salt/cloud/clouds/vmware.py
+++ b/salt/cloud/clouds/vmware.py
@@ -2821,6 +2821,12 @@ def create(vm_):
win_run_once = config.get_cloud_config_value(
"win_run_once", vm_, __opts__, search_global=False, default=None
)
+ cpu_hot_add = config.get_cloud_config_value(
+ 'cpu_hot_add', vm_, __opts__, search_global=False, default=None
+ )
+ mem_hot_add = config.get_cloud_config_value(
+ 'mem_hot_add', vm_, __opts__, search_global=False, default=None
+ )
# Get service instance object
si = _get_si()
@@ -3039,6 +3045,12 @@ def create(vm_):
)
config_spec.deviceChange = specs["device_specs"]
+ if cpu_hot_add and hasattr(config_spec, 'cpuHotAddEnabled'):
+ config_spec.cpuHotAddEnabled = bool(cpu_hot_add)
+
+ if mem_hot_add and hasattr(config_spec, 'memoryHotAddEnabled'):
+ config_spec.memoryHotAddEnabled = bool(mem_hot_add)
+
if extra_config:
for key, value in extra_config.items():
option = vim.option.OptionValue(key=key, value=value)
--
2.33.0

View File

@ -1,65 +1,15 @@
From efcf52ad6b7edf64e6a2eaead99c8df5894ab613 Mon Sep 17 00:00:00 2001
From d5fae6bd4a4f243115ee220393e05440f0d48b5a 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)
* Fix _compat.py importlib logic for Python 3.10
Use the same logic in _compat.py and entrypoints.py to load
the same importlib.metadata. Python's built in implementation for
Python >= 3.10 and the Salt one for others.
* Use collections.abc.Mapping instead collections.Mapping in state
Co-authored-by: piterpunk <piterpunk@slackware.com>
---
salt/_compat.py | 30 +++++++++++++++++-------------
salt/state.py | 5 +++--
2 files changed, 20 insertions(+), 15 deletions(-)
salt/state.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/salt/_compat.py b/salt/_compat.py
index 8149657bea..a402f17a3c 100644
--- a/salt/_compat.py
+++ b/salt/_compat.py
@@ -11,19 +11,23 @@ if sys.version_info >= (3, 9, 5):
else:
import salt.ext.ipaddress as ipaddress
+if sys.version_info >= (3, 10):
+ # Python 3.10 will include a fix in importlib.metadata which allows us to
+ # get the distribution of a loaded entry-point
+ import importlib.metadata # pylint: disable=no-member,no-name-in-module
+else:
+ # importlib_metadata before version 3.3.0 does not include the functionality we need.
+ try:
+ import importlib_metadata
-# importlib_metadata before version 3.3.0 does not include the functionality we need.
-try:
- import importlib_metadata
-
- importlib_metadata_version = [
- int(part)
- for part in importlib_metadata.version("importlib_metadata").split(".")
- if part.isdigit()
- ]
- if tuple(importlib_metadata_version) < (3, 3, 0):
+ importlib_metadata_version = [
+ int(part)
+ for part in importlib_metadata.version("importlib_metadata").split(".")
+ if part.isdigit()
+ ]
+ if tuple(importlib_metadata_version) < (3, 3, 0):
+ # Use the vendored importlib_metadata
+ import salt.ext.importlib_metadata as importlib_metadata
+ except ImportError:
# Use the vendored importlib_metadata
import salt.ext.importlib_metadata as importlib_metadata
-except ImportError:
- # Use the vendored importlib_metadata
- import salt.ext.importlib_metadata as importlib_metadata
diff --git a/salt/state.py b/salt/state.py
index 3361a537cd..b759c8e0ee 100644
index f5579fbb69..61519d5042 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -12,7 +12,6 @@ The data sent to the state calls is as follows:
@ -76,10 +26,10 @@ index 3361a537cd..b759c8e0ee 100644
+from collections.abc import Mapping
+
import salt.channel.client
import salt.fileclient
import salt.loader
import salt.minion
@@ -3276,7 +3277,7 @@ class State:
@@ -3405,7 +3406,7 @@ class State:
"""
for chunk in high:
state = high[chunk]
@ -89,6 +39,6 @@ index 3361a537cd..b759c8e0ee 100644
for state_ref in state:
needs_default = True
--
2.35.1
2.37.3

View File

@ -1,9 +1,8 @@
From 6c1c81aba71711632a14b725426077f9183065e9 Mon Sep 17 00:00:00 2001
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)
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

View File

@ -1,29 +0,0 @@
From 36b107fb5108fe4e52e9ef522765d6ada588c50d Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Wed, 9 Dec 2020 14:58:55 +0300
Subject: [PATCH] Force zyppnotify to prefer Packages.db than Packages
if it exists
---
scripts/suse/zypper/plugins/commit/zyppnotify | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/scripts/suse/zypper/plugins/commit/zyppnotify b/scripts/suse/zypper/plugins/commit/zyppnotify
index 51ac02254e..d6a1bef42b 100755
--- a/scripts/suse/zypper/plugins/commit/zyppnotify
+++ b/scripts/suse/zypper/plugins/commit/zyppnotify
@@ -20,7 +20,9 @@ class DriftDetector(Plugin):
def __init__(self):
Plugin.__init__(self)
self.ck_path = "/var/cache/salt/minion/rpmdb.cookie"
- self.rpm_path = "/var/lib/rpm/Packages"
+ self.rpm_path = "/var/lib/rpm/Packages.db"
+ if not os.path.exists(self.rpm_path):
+ self.rpm_path = "/var/lib/rpm/Packages"
def _get_mtime(self):
"""
--
2.29.2

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2b1610ccab5866f29f7d1934f315006954ba60a31bbc3c60c07b44a5ea018a06
size 10429711
oid sha256:82795a90cebe98e39a7fc513144a45686bcbe13806c1ad233cb371c120af2bc7
size 10525087

View File

@ -1,4 +1,4 @@
From 90d0e3ce40e46a9bff3e477b61e02cf3e87e8b9f Mon Sep 17 00:00:00 2001
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
@ -51,6 +51,6 @@ index 0000000000..1a89660c02
+ assert license_read_mock.calls[0].args[0] == "/usr/share/doc/bash/copyright"
+ assert license_read_mock.calls[0].kwargs["errors"] == "ignore"
--
2.36.1
2.37.3

View File

@ -0,0 +1,250 @@
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,4 +1,4 @@
From b4945a0608b3d8996e8b5593dcc458c15b11d6ba Mon Sep 17 00:00:00 2001
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
@ -32,10 +32,10 @@ index 0000000000..1ab74f9122
@@ -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 9530a43fc5..b543144da2 100644
index 047c33ffd3..76f3767ddf 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -1093,7 +1093,9 @@ def _virtual(osdata):
@@ -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:
@ -46,7 +46,7 @@ index 9530a43fc5..b543144da2 100644
fhr_contents = fhr.read()
if "container=lxc" in fhr_contents:
grains["virtual"] = "container"
@@ -1911,7 +1913,9 @@ def os_data():
@@ -1909,7 +1911,9 @@ def os_data():
grains["init"] = "systemd"
except OSError:
try:
@ -57,7 +57,7 @@ index 9530a43fc5..b543144da2 100644
init_cmdline = fhr.read().replace("\x00", " ").split()
except OSError:
pass
@@ -3160,7 +3164,9 @@ def kernelparams():
@@ -3154,7 +3158,9 @@ def kernelparams():
return {}
else:
try:
@ -69,7 +69,7 @@ index 9530a43fc5..b543144da2 100644
grains = {"kernelparams": []}
for data in [
diff --git a/tests/pytests/unit/grains/test_core.py b/tests/pytests/unit/grains/test_core.py
index 84dd97d62f..e640a07f76 100644
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
@ -80,7 +80,7 @@ index 84dd97d62f..e640a07f76 100644
import textwrap
from collections import namedtuple
@@ -2635,6 +2636,38 @@ def test_kernelparams_return_linux(cmdline, expectation):
@@ -2738,6 +2739,38 @@ def test_kernelparams_return_linux(cmdline, expectation):
assert core.kernelparams() == expectation
@ -119,7 +119,7 @@ index 84dd97d62f..e640a07f76 100644
def test_linux_gpus():
"""
Test GPU detection on Linux systems
@@ -2837,3 +2870,88 @@ def test_virtual_set_virtual_ec2():
@@ -2940,3 +2973,88 @@ def test_virtual_set_virtual_ec2():
assert virtual_grains["virtual"] == "kvm"
assert "virtual_subtype" not in virtual_grains
@ -211,3 +211,4 @@ index 84dd97d62f..e640a07f76 100644
--
2.37.3

View File

@ -1,813 +0,0 @@
From 8e5295ef9047a9afdd2323508c633ab0356ef603 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Wed, 19 Jan 2022 15:34:24 +0100
Subject: [PATCH] Implementation of held/unheld functions for state pkg
(#387)
* Implementation of held/unheld functions for state pkg
---
salt/modules/zypperpkg.py | 119 ++++++-
salt/states/pkg.py | 310 +++++++++++++++++++
tests/pytests/unit/modules/test_zypperpkg.py | 133 ++++++++
tests/pytests/unit/states/test_pkg.py | 137 ++++++++
4 files changed, 686 insertions(+), 13 deletions(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index 4fc045c313..ac6c36a09f 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -2103,6 +2103,76 @@ def purge(
return _uninstall(inclusion_detection, name=name, pkgs=pkgs, root=root)
+def list_holds(pattern=None, full=True, root=None, **kwargs):
+ """
+ List information on locked packages.
+
+ .. note::
+ This function returns the computed output of ``list_locks``
+ to show exact locked packages.
+
+ pattern
+ Regular expression used to match the package name
+
+ full : True
+ Show the full hold definition including version and epoch. Set to
+ ``False`` to return just the name of the package(s) being held.
+
+ root
+ Operate on a different root directory.
+
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt '*' pkg.list_holds
+ salt '*' pkg.list_holds full=False
+ """
+ locks = list_locks(root=root)
+ ret = []
+ inst_pkgs = {}
+ for solv_name, lock in locks.items():
+ if lock.get("type", "package") != "package":
+ continue
+ try:
+ found_pkgs = search(
+ solv_name,
+ root=root,
+ match=None if "*" in solv_name else "exact",
+ case_sensitive=(lock.get("case_sensitive", "on") == "on"),
+ installed_only=True,
+ details=True,
+ all_versions=True,
+ ignore_no_matching_item=True,
+ )
+ except CommandExecutionError:
+ continue
+ if found_pkgs:
+ for pkg in found_pkgs:
+ if pkg not in inst_pkgs:
+ inst_pkgs.update(
+ info_installed(
+ pkg, root=root, attr="edition,epoch", all_versions=True
+ )
+ )
+
+ ptrn_re = re.compile(r"{}-\S+".format(pattern)) if pattern else None
+ for pkg_name, pkg_editions in inst_pkgs.items():
+ for pkg_info in pkg_editions:
+ pkg_ret = (
+ "{}-{}:{}.*".format(
+ pkg_name, pkg_info.get("epoch", 0), pkg_info.get("edition")
+ )
+ if full
+ else pkg_name
+ )
+ if pkg_ret not in ret and (not ptrn_re or ptrn_re.match(pkg_ret)):
+ ret.append(pkg_ret)
+
+ return ret
+
+
def list_locks(root=None):
"""
List current package locks.
@@ -2173,7 +2243,7 @@ def clean_locks(root=None):
return out
-def unhold(name=None, pkgs=None, **kwargs):
+def unhold(name=None, pkgs=None, root=None, **kwargs):
"""
.. versionadded:: 3003
@@ -2187,6 +2257,9 @@ def unhold(name=None, pkgs=None, **kwargs):
A list of packages to unhold. The ``name`` parameter will be ignored if
this option is passed.
+ root
+ Operate on a different root directory.
+
CLI Example:
.. code-block:: bash
@@ -2201,24 +2274,38 @@ def unhold(name=None, pkgs=None, **kwargs):
targets = []
if pkgs:
- for pkg in salt.utils.data.repack_dictlist(pkgs):
- targets.append(pkg)
+ targets.extend(pkgs)
else:
targets.append(name)
locks = list_locks()
removed = []
- missing = []
for target in targets:
+ version = None
+ if isinstance(target, dict):
+ (target, version) = next(iter(target.items()))
ret[target] = {"name": target, "changes": {}, "result": True, "comment": ""}
if locks.get(target):
- removed.append(target)
- ret[target]["changes"]["new"] = ""
- ret[target]["changes"]["old"] = "hold"
- ret[target]["comment"] = "Package {} is no longer held.".format(target)
+ lock_ver = None
+ if "version" in locks.get(target):
+ lock_ver = locks.get(target)["version"]
+ lock_ver = lock_ver.lstrip("= ")
+ if version and lock_ver != version:
+ ret[target]["result"] = False
+ ret[target][
+ "comment"
+ ] = "Unable to unhold package {} as it is held with the other version.".format(
+ target
+ )
+ else:
+ removed.append(
+ target if not lock_ver else "{}={}".format(target, lock_ver)
+ )
+ ret[target]["changes"]["new"] = ""
+ ret[target]["changes"]["old"] = "hold"
+ ret[target]["comment"] = "Package {} is no longer held.".format(target)
else:
- missing.append(target)
ret[target]["comment"] = "Package {} was already unheld.".format(target)
if removed:
@@ -2271,7 +2358,7 @@ def remove_lock(name, root=None, **kwargs):
return {"removed": len(removed), "not_found": missing}
-def hold(name=None, pkgs=None, **kwargs):
+def hold(name=None, pkgs=None, root=None, **kwargs):
"""
.. versionadded:: 3003
@@ -2285,6 +2372,10 @@ def hold(name=None, pkgs=None, **kwargs):
A list of packages to hold. The ``name`` parameter will be ignored if
this option is passed.
+ root
+ Operate on a different root directory.
+
+
CLI Example:
.. code-block:: bash
@@ -2299,8 +2390,7 @@ def hold(name=None, pkgs=None, **kwargs):
targets = []
if pkgs:
- for pkg in salt.utils.data.repack_dictlist(pkgs):
- targets.append(pkg)
+ targets.extend(pkgs)
else:
targets.append(name)
@@ -2308,9 +2398,12 @@ def hold(name=None, pkgs=None, **kwargs):
added = []
for target in targets:
+ version = None
+ if isinstance(target, dict):
+ (target, version) = next(iter(target.items()))
ret[target] = {"name": target, "changes": {}, "result": True, "comment": ""}
if not locks.get(target):
- added.append(target)
+ added.append(target if not version else "{}={}".format(target, version))
ret[target]["changes"]["new"] = "hold"
ret[target]["changes"]["old"] = ""
ret[target]["comment"] = "Package {} is now being held.".format(target)
diff --git a/salt/states/pkg.py b/salt/states/pkg.py
index f71f61e720..0d601e1aaf 100644
--- a/salt/states/pkg.py
+++ b/salt/states/pkg.py
@@ -3644,3 +3644,313 @@ def mod_beacon(name, **kwargs):
),
"result": False,
}
+
+
+def held(name, version=None, pkgs=None, replace=False, **kwargs):
+ """
+ Set package in 'hold' state, meaning it will not be changed.
+
+ :param str name:
+ The name of the package to be held. This parameter is ignored
+ if ``pkgs`` is used.
+
+ :param str version:
+ Hold a specific version of a package.
+ Full description of this parameter is in `installed` function.
+
+ .. note::
+
+ This parameter make sense for Zypper-based systems.
+ Ignored for YUM/DNF and APT
+
+ :param list pkgs:
+ A list of packages to be held. All packages listed under ``pkgs``
+ will be held.
+
+ .. code-block:: yaml
+
+ mypkgs:
+ pkg.held:
+ - pkgs:
+ - foo
+ - bar: 1.2.3-4
+ - baz
+
+ .. note::
+
+ For Zypper-based systems the package could be held for
+ the version specified. YUM/DNF and APT ingore it.
+
+ :param bool replace:
+ Force replacement of existings holds with specified.
+ By default, this parameter is set to ``False``.
+ """
+
+ if isinstance(pkgs, list) and len(pkgs) == 0 and not replace:
+ return {
+ "name": name,
+ "changes": {},
+ "result": True,
+ "comment": "No packages to be held provided",
+ }
+
+ # If just a name (and optionally a version) is passed, just pack them into
+ # the pkgs argument.
+ if name and pkgs is None:
+ if version:
+ pkgs = [{name: version}]
+ version = None
+ else:
+ pkgs = [name]
+
+ locks = {}
+ vr_lock = False
+ if "pkg.list_locks" in __salt__:
+ locks = __salt__["pkg.list_locks"]()
+ vr_lock = True
+ elif "pkg.list_holds" in __salt__:
+ _locks = __salt__["pkg.list_holds"](full=True)
+ lock_re = re.compile(r"^(.+)-(\d+):(.*)\.\*")
+ for lock in _locks:
+ match = lock_re.match(lock)
+ if match:
+ epoch = match.group(2)
+ if epoch == "0":
+ epoch = ""
+ else:
+ epoch = "{}:".format(epoch)
+ locks.update(
+ {match.group(1): {"version": "{}{}".format(epoch, match.group(3))}}
+ )
+ else:
+ locks.update({lock: {}})
+ elif "pkg.get_selections" in __salt__:
+ _locks = __salt__["pkg.get_selections"](state="hold")
+ for lock in _locks.get("hold", []):
+ locks.update({lock: {}})
+ else:
+ return {
+ "name": name,
+ "changes": {},
+ "result": False,
+ "comment": "No any function to get the list of held packages available.\n"
+ "Check if the package manager supports package locking.",
+ }
+
+ if "pkg.hold" not in __salt__:
+ return {
+ "name": name,
+ "changes": {},
+ "result": False,
+ "comment": "`hold` function is not implemented for the package manager.",
+ }
+
+ ret = {"name": name, "changes": {}, "result": True, "comment": ""}
+ comments = []
+
+ held_pkgs = set()
+ for pkg in pkgs:
+ if isinstance(pkg, dict):
+ (pkg_name, pkg_ver) = next(iter(pkg.items()))
+ else:
+ pkg_name = pkg
+ pkg_ver = None
+ lock_ver = None
+ if pkg_name in locks and "version" in locks[pkg_name]:
+ lock_ver = locks[pkg_name]["version"]
+ lock_ver = lock_ver.lstrip("= ")
+ held_pkgs.add(pkg_name)
+ if pkg_name not in locks or (vr_lock and lock_ver != pkg_ver):
+ if __opts__["test"]:
+ if pkg_name in locks:
+ comments.append(
+ "The following package's hold rule would be updated: {}{}".format(
+ pkg_name,
+ "" if not pkg_ver else " (version = {})".format(pkg_ver),
+ )
+ )
+ else:
+ comments.append(
+ "The following package would be held: {}{}".format(
+ pkg_name,
+ "" if not pkg_ver else " (version = {})".format(pkg_ver),
+ )
+ )
+ else:
+ unhold_ret = None
+ if pkg_name in locks:
+ unhold_ret = __salt__["pkg.unhold"](name=name, pkgs=[pkg_name])
+ hold_ret = __salt__["pkg.hold"](name=name, pkgs=[pkg])
+ if not hold_ret.get(pkg_name, {}).get("result", False):
+ ret["result"] = False
+ if (
+ unhold_ret
+ and unhold_ret.get(pkg_name, {}).get("result", False)
+ and hold_ret
+ and hold_ret.get(pkg_name, {}).get("result", False)
+ ):
+ comments.append(
+ "Package {} was updated with hold rule".format(pkg_name)
+ )
+ elif hold_ret and hold_ret.get(pkg_name, {}).get("result", False):
+ comments.append("Package {} is now being held".format(pkg_name))
+ else:
+ comments.append("Package {} was not held".format(pkg_name))
+ ret["changes"].update(hold_ret)
+
+ if replace:
+ for pkg_name in locks:
+ if locks[pkg_name].get("type", "package") != "package":
+ continue
+ if __opts__["test"]:
+ if pkg_name not in held_pkgs:
+ comments.append(
+ "The following package would be unheld: {}".format(pkg_name)
+ )
+ else:
+ if pkg_name not in held_pkgs:
+ unhold_ret = __salt__["pkg.unhold"](name=name, pkgs=[pkg_name])
+ if not unhold_ret.get(pkg_name, {}).get("result", False):
+ ret["result"] = False
+ if unhold_ret and unhold_ret.get(pkg_name, {}).get("comment"):
+ comments.append(unhold_ret.get(pkg_name).get("comment"))
+ ret["changes"].update(unhold_ret)
+
+ ret["comment"] = "\n".join(comments)
+ if not (ret["changes"] or ret["comment"]):
+ ret["comment"] = "No changes made"
+
+ return ret
+
+
+def unheld(name, version=None, pkgs=None, all=False, **kwargs):
+ """
+ Unset package from 'hold' state, to allow operations with the package.
+
+ :param str name:
+ The name of the package to be unheld. This parameter is ignored if "pkgs"
+ is used.
+
+ :param str version:
+ Unhold a specific version of a package.
+ Full description of this parameter is in `installed` function.
+
+ .. note::
+
+ This parameter make sense for Zypper-based systems.
+ Ignored for YUM/DNF and APT.
+
+ :param list pkgs:
+ A list of packages to be unheld. All packages listed under ``pkgs``
+ will be unheld.
+
+ .. code-block:: yaml
+
+ mypkgs:
+ pkg.unheld:
+ - pkgs:
+ - foo
+ - bar: 1.2.3-4
+ - baz
+
+ .. note::
+
+ For Zypper-based systems the package could be held for
+ the version specified. YUM/DNF and APT ingore it.
+ For ``unheld`` there is no need to specify the exact version
+ to be unheld.
+
+ :param bool all:
+ Force removing of all existings locks.
+ By default, this parameter is set to ``False``.
+ """
+
+ if isinstance(pkgs, list) and len(pkgs) == 0 and not all:
+ return {
+ "name": name,
+ "changes": {},
+ "result": True,
+ "comment": "No packages to be unheld provided",
+ }
+
+ # If just a name (and optionally a version) is passed, just pack them into
+ # the pkgs argument.
+ if name and pkgs is None:
+ pkgs = [{name: version}]
+ version = None
+
+ locks = {}
+ vr_lock = False
+ if "pkg.list_locks" in __salt__:
+ locks = __salt__["pkg.list_locks"]()
+ vr_lock = True
+ elif "pkg.list_holds" in __salt__:
+ _locks = __salt__["pkg.list_holds"](full=True)
+ lock_re = re.compile(r"^(.+)-(\d+):(.*)\.\*")
+ for lock in _locks:
+ match = lock_re.match(lock)
+ if match:
+ epoch = match.group(2)
+ if epoch == "0":
+ epoch = ""
+ else:
+ epoch = "{}:".format(epoch)
+ locks.update(
+ {match.group(1): {"version": "{}{}".format(epoch, match.group(3))}}
+ )
+ else:
+ locks.update({lock: {}})
+ elif "pkg.get_selections" in __salt__:
+ _locks = __salt__["pkg.get_selections"](state="hold")
+ for lock in _locks.get("hold", []):
+ locks.update({lock: {}})
+ else:
+ return {
+ "name": name,
+ "changes": {},
+ "result": False,
+ "comment": "No any function to get the list of held packages available.\n"
+ "Check if the package manager supports package locking.",
+ }
+
+ dpkgs = {}
+ for pkg in pkgs:
+ if isinstance(pkg, dict):
+ (pkg_name, pkg_ver) = next(iter(pkg.items()))
+ dpkgs.update({pkg_name: pkg_ver})
+ else:
+ dpkgs.update({pkg: None})
+
+ ret = {"name": name, "changes": {}, "result": True, "comment": ""}
+ comments = []
+
+ for pkg_name in locks:
+ if locks[pkg_name].get("type", "package") != "package":
+ continue
+ lock_ver = None
+ if vr_lock and "version" in locks[pkg_name]:
+ lock_ver = locks[pkg_name]["version"]
+ lock_ver = lock_ver.lstrip("= ")
+ if all or (pkg_name in dpkgs and (not lock_ver or lock_ver == dpkgs[pkg_name])):
+ if __opts__["test"]:
+ comments.append(
+ "The following package would be unheld: {}{}".format(
+ pkg_name,
+ ""
+ if not dpkgs.get(pkg_name)
+ else " (version = {})".format(lock_ver),
+ )
+ )
+ else:
+ unhold_ret = __salt__["pkg.unhold"](name=name, pkgs=[pkg_name])
+ if not unhold_ret.get(pkg_name, {}).get("result", False):
+ ret["result"] = False
+ if unhold_ret and unhold_ret.get(pkg_name, {}).get("comment"):
+ comments.append(unhold_ret.get(pkg_name).get("comment"))
+ ret["changes"].update(unhold_ret)
+
+ ret["comment"] = "\n".join(comments)
+ if not (ret["changes"] or ret["comment"]):
+ ret["comment"] = "No changes made"
+
+ return ret
diff --git a/tests/pytests/unit/modules/test_zypperpkg.py b/tests/pytests/unit/modules/test_zypperpkg.py
index eb1e63f6d7..bfc1558c9a 100644
--- a/tests/pytests/unit/modules/test_zypperpkg.py
+++ b/tests/pytests/unit/modules/test_zypperpkg.py
@@ -121,3 +121,136 @@ 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")
+
+
+def test_pkg_hold():
+ """
+ Tests holding packages with Zypper
+ """
+
+ # Test openSUSE 15.3
+ list_locks_mock = {
+ "bar": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
+ "minimal_base": {
+ "type": "pattern",
+ "match_type": "glob",
+ "case_sensitive": "on",
+ },
+ "baz": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
+ }
+
+ cmd = MagicMock(
+ return_value={
+ "pid": 1234,
+ "retcode": 0,
+ "stdout": "Specified lock has been successfully added.",
+ "stderr": "",
+ }
+ )
+ with patch.object(
+ zypper, "list_locks", MagicMock(return_value=list_locks_mock)
+ ), patch.dict(zypper.__salt__, {"cmd.run_all": cmd}):
+ ret = zypper.hold("foo")
+ assert ret["foo"]["changes"]["old"] == ""
+ assert ret["foo"]["changes"]["new"] == "hold"
+ assert ret["foo"]["comment"] == "Package foo is now being held."
+ cmd.assert_called_once_with(
+ ["zypper", "--non-interactive", "--no-refresh", "al", "foo"],
+ env={},
+ output_loglevel="trace",
+ python_shell=False,
+ )
+ cmd.reset_mock()
+ ret = zypper.hold(pkgs=["foo", "bar"])
+ assert ret["foo"]["changes"]["old"] == ""
+ assert ret["foo"]["changes"]["new"] == "hold"
+ assert ret["foo"]["comment"] == "Package foo is now being held."
+ assert ret["bar"]["changes"] == {}
+ assert ret["bar"]["comment"] == "Package bar is already set to be held."
+ cmd.assert_called_once_with(
+ ["zypper", "--non-interactive", "--no-refresh", "al", "foo"],
+ env={},
+ output_loglevel="trace",
+ python_shell=False,
+ )
+
+
+def test_pkg_unhold():
+ """
+ Tests unholding packages with Zypper
+ """
+
+ # Test openSUSE 15.3
+ list_locks_mock = {
+ "bar": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
+ "minimal_base": {
+ "type": "pattern",
+ "match_type": "glob",
+ "case_sensitive": "on",
+ },
+ "baz": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
+ }
+
+ cmd = MagicMock(
+ return_value={
+ "pid": 1234,
+ "retcode": 0,
+ "stdout": "1 lock has been successfully removed.",
+ "stderr": "",
+ }
+ )
+ with patch.object(
+ zypper, "list_locks", MagicMock(return_value=list_locks_mock)
+ ), patch.dict(zypper.__salt__, {"cmd.run_all": cmd}):
+ ret = zypper.unhold("foo")
+ assert ret["foo"]["comment"] == "Package foo was already unheld."
+ cmd.assert_not_called()
+ cmd.reset_mock()
+ ret = zypper.unhold(pkgs=["foo", "bar"])
+ assert ret["foo"]["changes"] == {}
+ assert ret["foo"]["comment"] == "Package foo was already unheld."
+ assert ret["bar"]["changes"]["old"] == "hold"
+ assert ret["bar"]["changes"]["new"] == ""
+ assert ret["bar"]["comment"] == "Package bar is no longer held."
+ cmd.assert_called_once_with(
+ ["zypper", "--non-interactive", "--no-refresh", "rl", "bar"],
+ env={},
+ output_loglevel="trace",
+ python_shell=False,
+ )
+
+
+def test_pkg_list_holds():
+ """
+ Tests listing of calculated held packages with Zypper
+ """
+
+ # Test openSUSE 15.3
+ list_locks_mock = {
+ "bar": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
+ "minimal_base": {
+ "type": "pattern",
+ "match_type": "glob",
+ "case_sensitive": "on",
+ },
+ "baz": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
+ }
+ installed_pkgs = {
+ "foo": [{"edition": "1.2.3-1.1"}],
+ "bar": [{"edition": "2.3.4-2.1", "epoch": "2"}],
+ }
+
+ def zypper_search_mock(name, *_args, **_kwargs):
+ if name in installed_pkgs:
+ return {name: installed_pkgs.get(name)}
+
+ with patch.object(
+ zypper, "list_locks", MagicMock(return_value=list_locks_mock)
+ ), patch.object(
+ zypper, "search", MagicMock(side_effect=zypper_search_mock)
+ ), patch.object(
+ zypper, "info_installed", MagicMock(side_effect=zypper_search_mock)
+ ):
+ ret = zypper.list_holds()
+ assert len(ret) == 1
+ assert "bar-2:2.3.4-2.1.*" in ret
diff --git a/tests/pytests/unit/states/test_pkg.py b/tests/pytests/unit/states/test_pkg.py
index 7e667d36fd..17b91bcb39 100644
--- a/tests/pytests/unit/states/test_pkg.py
+++ b/tests/pytests/unit/states/test_pkg.py
@@ -578,3 +578,140 @@ def test_removed_purged_with_changes_test_true(list_pkgs, action):
ret = pkg_actions[action]("pkga", test=True)
assert ret["result"] is None
assert ret["changes"] == expected
+
+
+@pytest.mark.parametrize(
+ "package_manager", [("Zypper"), ("YUM/DNF"), ("APT")],
+)
+def test_held_unheld(package_manager):
+ """
+ Test pkg.held and pkg.unheld with Zypper, YUM/DNF and APT
+ """
+
+ if package_manager == "Zypper":
+ list_holds_func = "pkg.list_locks"
+ list_holds_mock = MagicMock(
+ return_value={
+ "bar": {
+ "type": "package",
+ "match_type": "glob",
+ "case_sensitive": "on",
+ },
+ "minimal_base": {
+ "type": "pattern",
+ "match_type": "glob",
+ "case_sensitive": "on",
+ },
+ "baz": {
+ "type": "package",
+ "match_type": "glob",
+ "case_sensitive": "on",
+ },
+ }
+ )
+ elif package_manager == "YUM/DNF":
+ list_holds_func = "pkg.list_holds"
+ list_holds_mock = MagicMock(
+ return_value=["bar-0:1.2.3-1.1.*", "baz-0:2.3.4-2.1.*"]
+ )
+ elif package_manager == "APT":
+ list_holds_func = "pkg.get_selections"
+ list_holds_mock = MagicMock(return_value={"hold": ["bar", "baz"]})
+
+ def pkg_hold(name, pkgs=None, *_args, **__kwargs):
+ if name and pkgs is None:
+ pkgs = [name]
+ ret = {}
+ for pkg in pkgs:
+ ret.update(
+ {
+ pkg: {
+ "name": pkg,
+ "changes": {"new": "hold", "old": ""},
+ "result": True,
+ "comment": "Package {} is now being held.".format(pkg),
+ }
+ }
+ )
+ return ret
+
+ def pkg_unhold(name, pkgs=None, *_args, **__kwargs):
+ if name and pkgs is None:
+ pkgs = [name]
+ ret = {}
+ for pkg in pkgs:
+ ret.update(
+ {
+ pkg: {
+ "name": pkg,
+ "changes": {"new": "", "old": "hold"},
+ "result": True,
+ "comment": "Package {} is no longer held.".format(pkg),
+ }
+ }
+ )
+ return ret
+
+ hold_mock = MagicMock(side_effect=pkg_hold)
+ unhold_mock = MagicMock(side_effect=pkg_unhold)
+
+ # Testing with Zypper
+ with patch.dict(
+ pkg.__salt__,
+ {
+ list_holds_func: list_holds_mock,
+ "pkg.hold": hold_mock,
+ "pkg.unhold": unhold_mock,
+ },
+ ):
+ # Holding one of two packages
+ ret = pkg.held("held-test", pkgs=["foo", "bar"])
+ assert "foo" in ret["changes"]
+ assert len(ret["changes"]) == 1
+ hold_mock.assert_called_once_with(name="held-test", pkgs=["foo"])
+ unhold_mock.assert_not_called()
+
+ hold_mock.reset_mock()
+ unhold_mock.reset_mock()
+
+ # Holding one of two packages and replacing all the rest held packages
+ ret = pkg.held("held-test", pkgs=["foo", "bar"], replace=True)
+ assert "foo" in ret["changes"]
+ assert "baz" in ret["changes"]
+ assert len(ret["changes"]) == 2
+ hold_mock.assert_called_once_with(name="held-test", pkgs=["foo"])
+ unhold_mock.assert_called_once_with(name="held-test", pkgs=["baz"])
+
+ hold_mock.reset_mock()
+ unhold_mock.reset_mock()
+
+ # Remove all holds
+ ret = pkg.held("held-test", pkgs=[], replace=True)
+ assert "bar" in ret["changes"]
+ assert "baz" in ret["changes"]
+ assert len(ret["changes"]) == 2
+ 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"])
+
+ hold_mock.reset_mock()
+ unhold_mock.reset_mock()
+
+ # Unolding one of two packages
+ ret = pkg.unheld("held-test", pkgs=["foo", "bar"])
+ assert "bar" in ret["changes"]
+ assert len(ret["changes"]) == 1
+ unhold_mock.assert_called_once_with(name="held-test", pkgs=["bar"])
+ hold_mock.assert_not_called()
+
+ hold_mock.reset_mock()
+ unhold_mock.reset_mock()
+
+ # Remove all holds
+ ret = pkg.unheld("held-test", all=True)
+ assert "bar" in ret["changes"]
+ assert "baz" in ret["changes"]
+ assert len(ret["changes"]) == 2
+ 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"])
--
2.34.1

File diff suppressed because it is too large Load Diff

View File

@ -1,556 +0,0 @@
From b58056da2f5a12e3d614650904039c0655ce1221 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Tue, 18 Jan 2022 19:41:03 +0100
Subject: [PATCH] Improvements on "ansiblegate" module (#354)
* Allow collecting Ansible Inventory from a minion
* Prevent crashing if ansible-playbook doesn't return JSON
* Add new 'ansible.discover_playbooks' method
* Include custom inventory when discovering Ansible playbooks
* Enhance 'ansible.discover_playbooks' to accept a list of locations
* Remove unused constants from Ansible utils
* Avoid string concatenation to calculate extra cmd args
* Add unit test for ansible.targets
* Improve Ansible roster targetting
* Add tests for new ansiblegate module functions
* Fix issue dealing with ungrouped targets on inventory
* Enable ansible utils for ansible roster tests
* Remove unnecessary code from Ansible utils
* Fix pylint issue
* Fix issue in documentation
Fix issue parsing errors in ansiblegate state module
---
salt/modules/ansiblegate.py | 167 +++++++++++++++++-
salt/roster/ansible.py | 17 +-
salt/states/ansiblegate.py | 12 +-
salt/utils/ansible.py | 41 +++++
.../pytests/unit/modules/test_ansiblegate.py | 99 ++++++++++-
.../example_playbooks/example-playbook2/hosts | 7 +
.../example-playbook2/site.yml | 28 +++
.../playbooks/example_playbooks/playbook1.yml | 5 +
tests/unit/roster/test_ansible.py | 2 +-
9 files changed, 367 insertions(+), 11 deletions(-)
create mode 100644 salt/utils/ansible.py
create mode 100644 tests/unit/files/playbooks/example_playbooks/example-playbook2/hosts
create mode 100644 tests/unit/files/playbooks/example_playbooks/example-playbook2/site.yml
create mode 100644 tests/unit/files/playbooks/example_playbooks/playbook1.yml
diff --git a/salt/modules/ansiblegate.py b/salt/modules/ansiblegate.py
index 328d9b7b0a..f33be6a00e 100644
--- a/salt/modules/ansiblegate.py
+++ b/salt/modules/ansiblegate.py
@@ -17,6 +17,7 @@ any Ansible module to respond.
import fnmatch
import json
import logging
+import os
import subprocess
import sys
from tempfile import NamedTemporaryFile
@@ -365,7 +366,171 @@ def playbooks(
}
ret = __salt__["cmd.run_all"](**cmd_kwargs)
log.debug("Ansible Playbook Return: %s", ret)
- retdata = json.loads(ret["stdout"])
+ try:
+ retdata = json.loads(ret["stdout"])
+ except ValueError:
+ retdata = ret
if "retcode" in ret:
__context__["retcode"] = retdata["retcode"] = ret["retcode"]
return retdata
+
+
+def targets(**kwargs):
+ """
+ Return the inventory from an Ansible inventory_file
+
+ :param inventory:
+ The inventory file to read the inventory from. Default: "/etc/ansible/hosts"
+
+ :param yaml:
+ Return the inventory as yaml output. Default: False
+
+ :param export:
+ Return inventory as export format. Default: False
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt 'ansiblehost' ansible.targets
+ salt 'ansiblehost' ansible.targets inventory=my_custom_inventory
+
+ """
+ return __utils__["ansible.targets"](**kwargs)
+
+
+def discover_playbooks(path=None,
+ locations=None,
+ playbook_extension=None,
+ hosts_filename=None,
+ syntax_check=False):
+ """
+ Discover Ansible playbooks stored under the given path or from multiple paths (locations)
+
+ This will search for files matching with the playbook file extension under the given
+ root path and will also look for files inside the first level of directories in this path.
+
+ The return of this function would be a dict like this:
+
+ .. code-block:: python
+
+ {
+ "/home/foobar/": {
+ "my_ansible_playbook.yml": {
+ "fullpath": "/home/foobar/playbooks/my_ansible_playbook.yml",
+ "custom_inventory": "/home/foobar/playbooks/hosts"
+ },
+ "another_playbook.yml": {
+ "fullpath": "/home/foobar/playbooks/another_playbook.yml",
+ "custom_inventory": "/home/foobar/playbooks/hosts"
+ },
+ "lamp_simple/site.yml": {
+ "fullpath": "/home/foobar/playbooks/lamp_simple/site.yml",
+ "custom_inventory": "/home/foobar/playbooks/lamp_simple/hosts"
+ },
+ "lamp_proxy/site.yml": {
+ "fullpath": "/home/foobar/playbooks/lamp_proxy/site.yml",
+ "custom_inventory": "/home/foobar/playbooks/lamp_proxy/hosts"
+ }
+ },
+ "/srv/playbooks/": {
+ "example_playbook/example.yml": {
+ "fullpath": "/srv/playbooks/example_playbook/example.yml",
+ "custom_inventory": "/srv/playbooks/example_playbook/hosts"
+ }
+ }
+ }
+
+ :param path:
+ Path to discover playbooks from.
+
+ :param locations:
+ List of paths to discover playbooks from.
+
+ :param playbook_extension:
+ File extension of playbooks file to search for. Default: "yml"
+
+ :param hosts_filename:
+ Filename of custom playbook inventory to search for. Default: "hosts"
+
+ :param syntax_check:
+ Skip playbooks that do not pass "ansible-playbook --syntax-check" validation. Default: False
+
+ :return:
+ The discovered playbooks under the given paths
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt 'ansiblehost' ansible.discover_playbooks path=/srv/playbooks/
+ salt 'ansiblehost' ansible.discover_playbooks locations='["/srv/playbooks/", "/srv/foobar"]'
+
+ """
+
+ if not path and not locations:
+ raise CommandExecutionError("You have to specify either 'path' or 'locations' arguments")
+
+ if path and locations:
+ raise CommandExecutionError("You cannot specify 'path' and 'locations' at the same time")
+
+ if not playbook_extension:
+ playbook_extension = "yml"
+ if not hosts_filename:
+ hosts_filename = "hosts"
+
+ if path:
+ if not os.path.isabs(path):
+ raise CommandExecutionError("The given path is not an absolute path: {}".format(path))
+ if not os.path.isdir(path):
+ raise CommandExecutionError("The given path is not a directory: {}".format(path))
+ return {path: _explore_path(path, playbook_extension, hosts_filename, syntax_check)}
+
+ if locations:
+ all_ret = {}
+ for location in locations:
+ all_ret[location] = _explore_path(location, playbook_extension, hosts_filename, syntax_check)
+ return all_ret
+
+
+def _explore_path(path, playbook_extension, hosts_filename, syntax_check):
+ ret = {}
+
+ if not os.path.isabs(path):
+ log.error("The given path is not an absolute path: {}".format(path))
+ return ret
+ if not os.path.isdir(path):
+ log.error("The given path is not a directory: {}".format(path))
+ return ret
+
+ try:
+ # Check files in the given path
+ for _f in os.listdir(path):
+ _path = os.path.join(path, _f)
+ if os.path.isfile(_path) and _path.endswith("." + playbook_extension):
+ ret[_f] = {"fullpath": _path}
+ # Check for custom inventory file
+ if os.path.isfile(os.path.join(path, hosts_filename)):
+ ret[_f].update({"custom_inventory": os.path.join(path, hosts_filename)})
+ elif os.path.isdir(_path):
+ # Check files in the 1st level of subdirectories
+ for _f2 in os.listdir(_path):
+ _path2 = os.path.join(_path, _f2)
+ if os.path.isfile(_path2) and _path2.endswith("." + playbook_extension):
+ ret[os.path.join(_f, _f2)] = {"fullpath": _path2}
+ # Check for custom inventory file
+ if os.path.isfile(os.path.join(_path, hosts_filename)):
+ ret[os.path.join(_f, _f2)].update({"custom_inventory": os.path.join(_path, hosts_filename)})
+ except Exception as exc:
+ raise CommandExecutionError("There was an exception while discovering playbooks: {}".format(exc))
+
+ # Run syntax check validation
+ if syntax_check:
+ check_command = ["ansible-playbook", "--syntax-check"]
+ try:
+ for pb in list(ret):
+ if __salt__["cmd.retcode"](check_command + [ret[pb]]):
+ del ret[pb]
+ except Exception as exc:
+ raise CommandExecutionError("There was an exception while checking syntax of playbooks: {}".format(exc))
+ return ret
diff --git a/salt/roster/ansible.py b/salt/roster/ansible.py
index 7beaaf2075..d3b352de27 100644
--- a/salt/roster/ansible.py
+++ b/salt/roster/ansible.py
@@ -117,27 +117,32 @@ def targets(tgt, tgt_type="glob", **kwargs):
Return the targets from the ansible inventory_file
Default: /etc/salt/roster
"""
- inventory = __runner__["salt.cmd"](
- "cmd.run", "ansible-inventory -i {} --list".format(get_roster_file(__opts__))
- )
- __context__["inventory"] = __utils__["json.loads"](
- __utils__["stringutils.to_str"](inventory)
+ __context__["inventory"] = __utils__["ansible.targets"](
+ inventory=get_roster_file(__opts__), **kwargs
)
if tgt_type == "glob":
hosts = [
host for host in _get_hosts_from_group("all") if fnmatch.fnmatch(host, tgt)
]
+ elif tgt_type == "list":
+ hosts = [host for host in _get_hosts_from_group("all") if host in tgt]
elif tgt_type == "nodegroup":
hosts = _get_hosts_from_group(tgt)
+ else:
+ hosts = []
+
return {host: _get_hostvars(host) for host in hosts}
def _get_hosts_from_group(group):
inventory = __context__["inventory"]
+ if group not in inventory:
+ return []
hosts = [host for host in inventory[group].get("hosts", [])]
for child in inventory[group].get("children", []):
- if child != "ungrouped":
+ child_info = _get_hosts_from_group(child)
+ if child_info not in hosts:
hosts.extend(_get_hosts_from_group(child))
return hosts
diff --git a/salt/states/ansiblegate.py b/salt/states/ansiblegate.py
index 4afe6a020d..af5cb0f0e5 100644
--- a/salt/states/ansiblegate.py
+++ b/salt/states/ansiblegate.py
@@ -184,7 +184,11 @@ def playbooks(name, rundir=None, git_repo=None, git_kwargs=None, ansible_kwargs=
checks = __salt__["ansible.playbooks"](
name, rundir=rundir, check=True, diff=True, **ansible_kwargs
)
- if all(
+ if "stats" not in checks:
+ ret["comment"] = checks.get("stderr", checks)
+ ret["result"] = False
+ ret["changes"] = {}
+ elif all(
not check["changed"]
and not check["failures"]
and not check["unreachable"]
@@ -213,7 +217,11 @@ def playbooks(name, rundir=None, git_repo=None, git_kwargs=None, ansible_kwargs=
results = __salt__["ansible.playbooks"](
name, rundir=rundir, diff=True, **ansible_kwargs
)
- if all(
+ if "stats" not in results:
+ ret["comment"] = results.get("stderr", results)
+ ret["result"] = False
+ ret["changes"] = {}
+ elif all(
not check["changed"]
and not check["failures"]
and not check["unreachable"]
diff --git a/salt/utils/ansible.py b/salt/utils/ansible.py
new file mode 100644
index 0000000000..1e14037fd3
--- /dev/null
+++ b/salt/utils/ansible.py
@@ -0,0 +1,41 @@
+import logging
+import os
+
+# Import Salt libs
+import salt.utils.json
+import salt.utils.path
+import salt.utils.stringutils
+import salt.modules.cmdmod
+from salt.exceptions import CommandExecutionError
+
+__virtualname__ = "ansible"
+
+log = logging.getLogger(__name__)
+
+
+def __virtual__(): # pylint: disable=expected-2-blank-lines-found-0
+ if salt.utils.path.which("ansible-inventory"):
+ return __virtualname__
+ return (False, "Install `ansible` to use inventory")
+
+
+def targets(inventory="/etc/ansible/hosts", **kwargs):
+ """
+ Return the targets from the ansible inventory_file
+ Default: /etc/salt/roster
+ """
+ if not os.path.isfile(inventory):
+ raise CommandExecutionError("Inventory file not found: {}".format(inventory))
+
+ extra_cmd = []
+ if "export" in kwargs:
+ extra_cmd.append("--export")
+ if "yaml" in kwargs:
+ extra_cmd.append("--yaml")
+ inv = salt.modules.cmdmod.run(
+ "ansible-inventory -i {} --list {}".format(inventory, " ".join(extra_cmd))
+ )
+ if kwargs.get("yaml", False):
+ return salt.utils.stringutils.to_str(inv)
+ else:
+ return salt.utils.json.loads(salt.utils.stringutils.to_str(inv))
diff --git a/tests/pytests/unit/modules/test_ansiblegate.py b/tests/pytests/unit/modules/test_ansiblegate.py
index 44c9b12acb..f357133000 100644
--- a/tests/pytests/unit/modules/test_ansiblegate.py
+++ b/tests/pytests/unit/modules/test_ansiblegate.py
@@ -1,9 +1,15 @@
# Author: Bo Maryniuk <bo@suse.de>
+import os
import pytest
+
+import salt.config
+import salt.loader
import salt.modules.ansiblegate as ansiblegate
import salt.utils.json
+import salt.utils.path
from tests.support.mock import ANY, MagicMock, patch
+from tests.support.runtests import RUNTIME_VARS
pytestmark = [
pytest.mark.skip_on_windows(reason="Not supported on Windows"),
@@ -12,7 +18,7 @@ pytestmark = [
@pytest.fixture
def configure_loader_modules():
- return {ansiblegate: {}}
+ return {ansiblegate: {"__utils__": {}}}
def test_ansible_module_help():
@@ -133,3 +139,94 @@ def test_ansible_playbooks_return_retcode():
):
ret = ansiblegate.playbooks("fake-playbook.yml")
assert "retcode" in ret
+
+
+def test_ansible_targets():
+ """
+ Test ansible.targets execution module function.
+ :return:
+ """
+ ansible_inventory_ret = """
+{
+ "_meta": {
+ "hostvars": {
+ "uyuni-stable-ansible-centos7-1.tf.local": {
+ "ansible_ssh_private_key_file": "/etc/ansible/my_ansible_private_key"
+ },
+ "uyuni-stable-ansible-centos7-2.tf.local": {
+ "ansible_ssh_private_key_file": "/etc/ansible/my_ansible_private_key"
+ }
+ }
+ },
+ "all": {
+ "children": [
+ "ungrouped"
+ ]
+ },
+ "ungrouped": {
+ "hosts": [
+ "uyuni-stable-ansible-centos7-1.tf.local",
+ "uyuni-stable-ansible-centos7-2.tf.local"
+ ]
+ }
+}
+ """
+ ansible_inventory_mock = MagicMock(return_value=ansible_inventory_ret)
+ with patch("salt.utils.path.which", MagicMock(return_value=True)):
+ opts = salt.config.DEFAULT_MINION_OPTS.copy()
+ utils = salt.loader.utils(opts, whitelist=["ansible"])
+ with patch("salt.modules.cmdmod.run", ansible_inventory_mock), patch.dict(
+ ansiblegate.__utils__, utils
+ ), patch("os.path.isfile", MagicMock(return_value=True)):
+ ret = ansiblegate.targets()
+ assert ansible_inventory_mock.call_args
+ assert "_meta" in ret
+ assert "uyuni-stable-ansible-centos7-1.tf.local" in ret["_meta"]["hostvars"]
+ assert (
+ "ansible_ssh_private_key_file"
+ in ret["_meta"]["hostvars"]["uyuni-stable-ansible-centos7-1.tf.local"]
+ )
+ assert "all" in ret
+ assert len(ret["ungrouped"]["hosts"]) == 2
+
+
+def test_ansible_discover_playbooks_single_path():
+ playbooks_dir = os.path.join(
+ RUNTIME_VARS.TESTS_DIR, "unit/files/playbooks/example_playbooks/"
+ )
+ ret = ansiblegate.discover_playbooks(playbooks_dir)
+ assert playbooks_dir in ret
+ assert ret[playbooks_dir]["playbook1.yml"] == {
+ "fullpath": os.path.join(playbooks_dir, "playbook1.yml")
+ }
+ assert ret[playbooks_dir]["example-playbook2/site.yml"] == {
+ "fullpath": os.path.join(playbooks_dir, "example-playbook2/site.yml"),
+ "custom_inventory": os.path.join(playbooks_dir, "example-playbook2/hosts"),
+ }
+
+
+def test_ansible_discover_playbooks_single_path_using_parameters():
+ playbooks_dir = os.path.join(
+ RUNTIME_VARS.TESTS_DIR, "unit/files/playbooks/example_playbooks/"
+ )
+ ret = ansiblegate.discover_playbooks(
+ playbooks_dir, playbook_extension="foobar", hosts_filename="deadbeaf"
+ )
+ assert playbooks_dir in ret
+ assert ret[playbooks_dir] == {}
+
+
+def test_ansible_discover_playbooks_multiple_locations():
+ playbooks_dir = os.path.join(
+ RUNTIME_VARS.TESTS_DIR, "unit/files/playbooks/example_playbooks/"
+ )
+ ret = ansiblegate.discover_playbooks(locations=[playbooks_dir, "/tmp/foobar"])
+ assert playbooks_dir in ret
+ assert "/tmp/foobar" in ret
+ assert ret[playbooks_dir]["playbook1.yml"] == {
+ "fullpath": os.path.join(playbooks_dir, "playbook1.yml")
+ }
+ assert ret[playbooks_dir]["example-playbook2/site.yml"] == {
+ "fullpath": os.path.join(playbooks_dir, "example-playbook2/site.yml"),
+ "custom_inventory": os.path.join(playbooks_dir, "example-playbook2/hosts"),
+ }
diff --git a/tests/unit/files/playbooks/example_playbooks/example-playbook2/hosts b/tests/unit/files/playbooks/example_playbooks/example-playbook2/hosts
new file mode 100644
index 0000000000..75783285f6
--- /dev/null
+++ b/tests/unit/files/playbooks/example_playbooks/example-playbook2/hosts
@@ -0,0 +1,7 @@
+[databases]
+host1
+host2
+
+[webservers]
+host3
+host4
diff --git a/tests/unit/files/playbooks/example_playbooks/example-playbook2/site.yml b/tests/unit/files/playbooks/example_playbooks/example-playbook2/site.yml
new file mode 100644
index 0000000000..a64ebd5e18
--- /dev/null
+++ b/tests/unit/files/playbooks/example_playbooks/example-playbook2/site.yml
@@ -0,0 +1,28 @@
+---
+- name: update web servers
+ hosts: webservers
+ remote_user: root
+
+ tasks:
+ - name: ensure apache is at the latest version
+ yum:
+ name: httpd
+ state: latest
+ - name: write the apache config file
+ template:
+ src: /srv/httpd.j2
+ dest: /etc/httpd.conf
+
+- name: update db servers
+ hosts: databases
+ remote_user: root
+
+ tasks:
+ - name: ensure postgresql is at the latest version
+ yum:
+ name: postgresql
+ state: latest
+ - name: ensure that postgresql is started
+ service:
+ name: postgresql
+ state: started
diff --git a/tests/unit/files/playbooks/example_playbooks/playbook1.yml b/tests/unit/files/playbooks/example_playbooks/playbook1.yml
new file mode 100644
index 0000000000..e258a101e1
--- /dev/null
+++ b/tests/unit/files/playbooks/example_playbooks/playbook1.yml
@@ -0,0 +1,5 @@
+---
+- hosts: all
+ gather_facts: false
+ tasks:
+ - ping:
diff --git a/tests/unit/roster/test_ansible.py b/tests/unit/roster/test_ansible.py
index 7f1144454b..c4ab8b7639 100644
--- a/tests/unit/roster/test_ansible.py
+++ b/tests/unit/roster/test_ansible.py
@@ -63,7 +63,7 @@ class AnsibleRosterTestCase(TestCase, mixins.LoaderModuleMockMixin):
opts = salt.config.master_config(
os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "master")
)
- utils = salt.loader.utils(opts, whitelist=["json", "stringutils"])
+ utils = salt.loader.utils(opts, whitelist=["json", "stringutils", "ansible"])
runner = salt.loader.runner(opts, utils=utils, whitelist=["salt"])
return {ansible: {"__utils__": utils, "__opts__": {}, "__runner__": runner}}
--
2.34.1

View File

@ -1,4 +1,4 @@
From 834defc8e38c4495ed51bb549d86727dd8b812b3 Mon Sep 17 00:00:00 2001
From 797b256548cbcda0f3828c6d182c44a3815dd313 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
@ -24,18 +24,19 @@ Implement network.fqdns module function (bsc#1134860) (#172)
Co-authored-by: Eric Siebigteroth <eric.siebigteroth@suse.de>
---
salt/modules/network.py | 5 ++++-
salt/utils/network.py | 16 ++++++++++++++
tests/unit/utils/test_network.py | 37 ++++++++++++++++++++++++++++++++
3 files changed, 57 insertions(+), 1 deletion(-)
salt/modules/network.py | 5 +++-
salt/utils/network.py | 16 +++++++++++
tests/pytests/unit/modules/test_network.py | 4 +--
tests/unit/utils/test_network.py | 32 ++++++++++++++++++++++
4 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/salt/modules/network.py b/salt/modules/network.py
index 08c20b99f9..53ebfe4bc7 100644
index 1149c96097..8c2d188903 100644
--- a/salt/modules/network.py
+++ b/salt/modules/network.py
@@ -2089,7 +2089,10 @@ def fqdns():
def _lookup_fqdn(ip):
@@ -2100,7 +2100,10 @@ def fqdns():
# https://sourceware.org/bugzilla/show_bug.cgi?id=19329
time.sleep(random.randint(5, 25) / 1000)
try:
- return [socket.getfqdn(socket.gethostbyaddr(ip)[0])]
+ name, aliaslist, addresslist = socket.gethostbyaddr(ip)
@ -46,10 +47,10 @@ index 08c20b99f9..53ebfe4bc7 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 22075066fd..8867041e0e 100644
index d042cd177d..bccda01556 100644
--- a/salt/utils/network.py
+++ b/salt/utils/network.py
@@ -2302,3 +2302,19 @@ def filter_by_networks(values, networks):
@@ -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
@ -69,20 +70,37 @@ index 22075066fd..8867041e0e 100644
+ and len(hostname) < 0xFF
+ 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
--- a/tests/pytests/unit/modules/test_network.py
+++ b/tests/pytests/unit/modules/test_network.py
@@ -28,7 +28,7 @@ def fake_fqdn():
with patch("socket.getfqdn", autospec=True, return_value=fqdn), patch(
"socket.gethostbyaddr",
autospec=True,
- return_value=("fnord", "fnord fnord"),
+ return_value=("fnord", ["fnord fnord"], []),
):
yield fqdn
@@ -88,7 +88,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,
- return_value=("fnord", "fnord fnord"),
+ return_value=("fnord", ["fnord fnord"], []),
):
actual_fqdns = networkmod.fqdns()
assert actual_fqdns == {
diff --git a/tests/unit/utils/test_network.py b/tests/unit/utils/test_network.py
index 6863ccd0c9..637d5e9811 100644
index 422f85d68c..3060aba0aa 100644
--- a/tests/unit/utils/test_network.py
+++ b/tests/unit/utils/test_network.py
@@ -1273,3 +1273,40 @@ class NetworkTestCase(TestCase):
@@ -1269,3 +1269,35 @@ class NetworkTestCase(TestCase):
),
):
self.assertEqual(network.get_fqhostname(), host)
+
+ def test_netlink_tool_remote_on(self):
+ with patch("subprocess.check_output", return_value=NETLINK_SS):
+ remotes = network._netlink_tool_remote_on("4505", "remote")
+ self.assertEqual(remotes, {"127.0.0.1", "::ffff:1.2.3.4"})
+
+ def test_is_fqdn(self):
+ """
+ Test is_fqdn function passes possible FQDN names.
@ -115,6 +133,6 @@ index 6863ccd0c9..637d5e9811 100644
+ ]:
+ assert not network.is_fqdn(fqdn)
--
2.34.1
2.37.3

View File

@ -0,0 +1,63 @@
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 3f8e937d938f19dd40fde527497f7775bbffe353 Mon Sep 17 00:00:00 2001
From 55fc248aabd486f8ae4ff2bc755d653cdc39a4bb 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 3c3fbf4970..0d378355ab 100644
index 4a2281c47f..544143d286 100644
--- a/salt/modules/aptpkg.py
+++ b/salt/modules/aptpkg.py
@@ -3056,6 +3056,15 @@ def info_installed(*names, **kwargs):
@@ -3479,6 +3479,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 3c3fbf4970..0d378355ab 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 51b7ffbe4d..8c64c8c9c1 100644
index 8e404a673c..76b59d8604 100644
--- a/tests/pytests/unit/modules/test_aptpkg.py
+++ b/tests/pytests/unit/modules/test_aptpkg.py
@@ -361,6 +361,24 @@ def test_info_installed_attr(lowpkg_info_var):
@@ -384,6 +384,24 @@ def test_info_installed_attr(lowpkg_info_var):
assert ret["wget"] == expected_pkg
@ -61,6 +61,6 @@ index 51b7ffbe4d..8c64c8c9c1 100644
"""
Test info_installed 'all_versions'.
--
2.34.1
2.37.3

View File

@ -1,4 +1,4 @@
From a6e490d8cede6e66bb5f22f314e1ec4e898dfa3c Mon Sep 17 00:00:00 2001
From c68a988ebcc7bae06231c9a9ebc3d654a7d6ffbc 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,11 +14,11 @@ 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 287d0b8c4c..ef9eb0c07e 100644
index 5e557c51da..ef162d2270 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -147,7 +147,7 @@ elif [ "$SUDO" ] && [ -n "$SUDO_USER" ]
then SUDO="sudo "
@@ -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"
@ -27,6 +27,6 @@ index 287d0b8c4c..ef9eb0c07e 100644
do
if command -v "$py_cmd" >/dev/null 2>&1 && "$py_cmd" -c "import sys; sys.exit(not (sys.version_info >= (2, 6)));"
--
2.29.2
2.37.3

View File

@ -1,4 +1,4 @@
From f31ab712a0838709bee0ba2420c99caa6700fbf4 Mon Sep 17 00:00:00 2001
From f113f94d40ee37919aa974a4fab95e482c5a0631 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 0a1c3b347c..1b4e311cee 100644
index 94e97a0b5b..0cbd611b71 100644
--- a/salt/modules/aptpkg.py
+++ b/salt/modules/aptpkg.py
@@ -1691,6 +1691,9 @@ def list_repos(**kwargs):
@@ -1933,6 +1933,9 @@ def list_repos(**kwargs):
repo["file"] = source.file
repo["comps"] = getattr(source, "comps", [])
repo["disabled"] = source.disabled
@ -23,6 +23,6 @@ index 0a1c3b347c..1b4e311cee 100644
repo["type"] = source.type
repo["uri"] = source.uri
--
2.33.0
2.37.3

View File

@ -1,4 +1,4 @@
From 7b4f5007b7e6a35386d197afe53d02c8d7b41d53 Mon Sep 17 00:00:00 2001
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)
@ -71,10 +71,10 @@ index 0000000000..22a9711383
+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 2c42290598..9e72a5b4b7 100644
index 7cdee12c4d..0cc0deb874 100644
--- a/salt/config/__init__.py
+++ b/salt/config/__init__.py
@@ -960,6 +960,14 @@ VALID_OPTS = immutabletypes.freeze(
@@ -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),
@ -89,7 +89,7 @@ index 2c42290598..9e72a5b4b7 100644
}
)
@@ -1601,6 +1609,10 @@ DEFAULT_MASTER_OPTS = immutabletypes.freeze(
@@ -1608,6 +1616,10 @@ DEFAULT_MASTER_OPTS = immutabletypes.freeze(
"fips_mode": False,
"detect_remote_minions": False,
"remote_minions_port": 22,

View File

@ -1,4 +1,4 @@
From 64c2735b64a074acc1ef05a82f9fcf342426f87e Mon Sep 17 00:00:00 2001
From 33e45a7ced8a3cfc0a8c37cdc5d7a29d6f6833c3 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 39a66fefba..d9c3d6e303 100755
index d633af35ec..586842972d 100755
--- a/setup.py
+++ b/setup.py
@@ -805,14 +805,6 @@ class Install(install):
@@ -718,14 +718,6 @@ class Install(install):
install.finalize_options(self)
def run(self):
@ -28,6 +28,6 @@ index 39a66fefba..d9c3d6e303 100755
# _version.py in the build command
self.distribution.running_salt_install = True
--
2.29.2
2.37.3

View File

@ -1,4 +1,4 @@
From cdd5edaa40233d83e3ed2eb61de3fbf70bc29dfb Mon Sep 17 00:00:00 2001
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)
@ -11,10 +11,10 @@ Signed-off-by: Witek Bedyk <witold.bedyk@suse.com>
1 file changed, 3 insertions(+)
diff --git a/salt/state.py b/salt/state.py
index b759c8e0ee..2c785233c5 100644
index db228228a7..316dcdec63 100644
--- a/salt/state.py
+++ b/salt/state.py
@@ -4061,6 +4061,9 @@ class BaseHighState:
@@ -4170,6 +4170,9 @@ class BaseHighState:
)
else:
try:
@ -25,6 +25,6 @@ index b759c8e0ee..2c785233c5 100644
fn_,
self.state.rend,
--
2.36.0
2.37.3

View File

@ -1,90 +0,0 @@
From a363596e5e02307680859432da9935905b749846 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Wed, 19 Jan 2022 17:33:01 +0100
Subject: [PATCH] Mock ip_addrs() in utils/minions.py unit test (#443)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Previously the test used `salt.utils.network.ip_addrs()' in the same way
that the tested code did. This worked well as long as at least one IP
address was returned by `salt.utils.network.ip_addrs()'.
Since this is a unit test, it should not depend on the environment,
it should just work™, even if there are no real IP addresses assigned to
the system (or container) that runs the test.
Co-authored-by: Pablo Suárez Hernández <psuarezhernandez@suse.com>
---
tests/pytests/unit/utils/test_minions.py | 36 +++++++++++++-----------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/tests/pytests/unit/utils/test_minions.py b/tests/pytests/unit/utils/test_minions.py
index a9eee20ea1..6bc6c80bbd 100644
--- a/tests/pytests/unit/utils/test_minions.py
+++ b/tests/pytests/unit/utils/test_minions.py
@@ -8,18 +8,22 @@ def test_connected_ids():
test ckminion connected_ids when
local_port_tcp returns 127.0.0.1
"""
- opts = {"publish_port": 4505, "detect_remote_minions": False}
+ opts = {
+ "publish_port": 4505,
+ "detect_remote_minions": False,
+ "minion_data_cache": True,
+ }
minion = "minion"
- ip = salt.utils.network.ip_addrs()
- mdata = {"grains": {"ipv4": ip, "ipv6": []}}
- ckminions = salt.utils.minions.CkMinions({"minion_data_cache": True})
+ ips = {"203.0.113.1", "203.0.113.2"}
+ mdata = {"grains": {"ipv4": ips, "ipv6": []}}
+ patch_ip_addrs = patch("salt.utils.network.local_port_tcp", return_value=ips)
patch_net = patch("salt.utils.network.local_port_tcp", return_value={"127.0.0.1"})
patch_list = patch("salt.cache.Cache.list", return_value=[minion])
patch_fetch = patch("salt.cache.Cache.fetch", return_value=mdata)
- with patch.dict(ckminions.opts, opts):
- with patch_net, patch_list, patch_fetch:
- ret = ckminions.connected_ids()
- assert ret == {minion}
+ ckminions = salt.utils.minions.CkMinions(opts)
+ with patch_net, patch_ip_addrs, patch_list, patch_fetch:
+ ret = ckminions.connected_ids()
+ assert ret == {minion}
def test_connected_ids_remote_minions():
@@ -31,21 +35,21 @@ def test_connected_ids_remote_minions():
"publish_port": 4505,
"detect_remote_minions": True,
"remote_minions_port": 22,
+ "minion_data_cache": True,
}
minion = "minion"
minion2 = "minion2"
minion2_ip = "192.168.2.10"
- ip = salt.utils.network.ip_addrs()
- mdata = {"grains": {"ipv4": ip, "ipv6": []}}
+ minion_ips = {"203.0.113.1", "203.0.113.2", "127.0.0.1"}
+ mdata = {"grains": {"ipv4": minion_ips, "ipv6": []}}
mdata2 = {"grains": {"ipv4": [minion2_ip], "ipv6": []}}
- ckminions = salt.utils.minions.CkMinions({"minion_data_cache": True})
- patch_net = patch("salt.utils.network.local_port_tcp", return_value={"127.0.0.1"})
+ patch_net = patch("salt.utils.network.local_port_tcp", return_value=minion_ips)
patch_remote_net = patch(
"salt.utils.network.remote_port_tcp", return_value={minion2_ip}
)
patch_list = patch("salt.cache.Cache.list", return_value=[minion, minion2])
patch_fetch = patch("salt.cache.Cache.fetch", side_effect=[mdata, mdata2])
- with patch.dict(ckminions.opts, opts):
- with patch_net, patch_list, patch_fetch, patch_remote_net:
- ret = ckminions.connected_ids()
- assert ret == {minion2, minion}
+ ckminions = salt.utils.minions.CkMinions(opts)
+ with patch_net, patch_list, patch_fetch, patch_remote_net:
+ ret = ckminions.connected_ids()
+ assert ret == {minion2, minion}
--
2.34.1

View File

@ -1,4 +1,4 @@
From 09afcd0d04788ec4351c1c0b73a0c6eb3b0fd8c9 Mon Sep 17 00:00:00 2001
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
@ -18,10 +18,10 @@ Subject: [PATCH] Normalize package names once with pkg.installed/removed
3 files changed, 192 insertions(+), 6 deletions(-)
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
index 9f8f548e5f..3138ac2e59 100644
index 46f0b1f613..f52e084346 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -1449,7 +1449,12 @@ def install(
@@ -1460,7 +1460,12 @@ def install(
try:
pkg_params, pkg_type = __salt__["pkg_resource.parse_targets"](
@ -35,7 +35,7 @@ index 9f8f548e5f..3138ac2e59 100644
)
except MinionError as exc:
raise CommandExecutionError(exc)
@@ -1603,7 +1608,10 @@ def install(
@@ -1612,7 +1617,10 @@ def install(
except ValueError:
pass
else:
@ -47,7 +47,7 @@ index 9f8f548e5f..3138ac2e59 100644
arch = "." + archpart
pkgname = namepart
@@ -2134,11 +2142,13 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
@@ -2143,11 +2151,13 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
arch = ""
pkgname = target
try:
@ -64,10 +64,10 @@ index 9f8f548e5f..3138ac2e59 100644
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 0d601e1aaf..71298e6c7a 100644
index ef4e062145..cda966a1e8 100644
--- a/salt/states/pkg.py
+++ b/salt/states/pkg.py
@@ -1901,6 +1901,7 @@ def installed(
@@ -1873,6 +1873,7 @@ def installed(
normalize=normalize,
update_holds=update_holds,
ignore_epoch=ignore_epoch,
@ -75,7 +75,7 @@ index 0d601e1aaf..71298e6c7a 100644
**kwargs
)
except CommandExecutionError as exc:
@@ -2973,7 +2974,7 @@ def _uninstall(
@@ -2940,7 +2941,7 @@ def _uninstall(
}
changes = __salt__["pkg.{}".format(action)](
@ -85,7 +85,7 @@ index 0d601e1aaf..71298e6c7a 100644
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 17b91bcb39..10acae9f88 100644
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
@ -122,7 +122,7 @@ index 17b91bcb39..10acae9f88 100644
}
@@ -715,3 +726,167 @@ def test_held_unheld(package_manager):
@@ -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"])
@ -291,6 +291,6 @@ index 17b91bcb39..10acae9f88 100644
+ assert ret["result"]
+ assert ret["changes"] == expected
--
2.36.1
2.37.3

View File

@ -1,92 +0,0 @@
From e0f8087409bdff4c3036e38ed4f22f5f031306e8 Mon Sep 17 00:00:00 2001
From: Ricardo Mateus <rjmateus@gmail.com>
Date: Fri, 9 Apr 2021 10:57:27 +0100
Subject: [PATCH] Notify beacon for Debian/Ubuntu systems (#347)
Signed-off-by: Ricardo Mateus <rmateus@suse.com>
(cherry picked from commit 33d6baebba94cc7a66d5555de984ca98684157a0)
---
scripts/suse/dpkg/99dpkgnotify | 1 +
scripts/suse/dpkg/README.md | 9 +++++++
scripts/suse/dpkg/dpkgnotify | 44 ++++++++++++++++++++++++++++++++++
3 files changed, 54 insertions(+)
create mode 100644 scripts/suse/dpkg/99dpkgnotify
create mode 100644 scripts/suse/dpkg/README.md
create mode 100644 scripts/suse/dpkg/dpkgnotify
diff --git a/scripts/suse/dpkg/99dpkgnotify b/scripts/suse/dpkg/99dpkgnotify
new file mode 100644
index 0000000000..8013387a57
--- /dev/null
+++ b/scripts/suse/dpkg/99dpkgnotify
@@ -0,0 +1 @@
+DPkg::Post-Invoke {"/usr/bin/dpkgnotify";};
diff --git a/scripts/suse/dpkg/README.md b/scripts/suse/dpkg/README.md
new file mode 100644
index 0000000000..b7a75c4786
--- /dev/null
+++ b/scripts/suse/dpkg/README.md
@@ -0,0 +1,9 @@
+## What it is
+
+Debian base package to notify installation of new packages outside the control of salt.
+
+## Installation
+This script depends on python package, so python3 should be installed on the machine
+
+- The 99dpkgnotify file must be installed in /etc/apt/apt.conf.d/99dpkgnotify
+- The dpkgnotify file must be installed in /usr/bin/dpkgnotify
diff --git a/scripts/suse/dpkg/dpkgnotify b/scripts/suse/dpkg/dpkgnotify
new file mode 100644
index 0000000000..d3ad3d2ba9
--- /dev/null
+++ b/scripts/suse/dpkg/dpkgnotify
@@ -0,0 +1,44 @@
+#!/usr/bin/python3
+
+import os
+import hashlib
+
+CK_PATH = "/var/cache/salt/minion/dpkg.cookie"
+DPKG_PATH = "/var/lib/dpkg/status"
+
+def _get_mtime():
+ """
+ Get the modified time of the Package Database.
+ Returns:
+ Unix ticks
+ """
+ return os.path.exists(DPKG_PATH) and int(os.path.getmtime(DPKG_PATH)) or 0
+
+
+def _get_checksum():
+ """
+ Get the checksum of the Package Database.
+ Returns:
+ hexdigest
+ """
+ digest = hashlib.sha256()
+ with open(DPKG_PATH, "rb") as pkg_db_fh:
+ while True:
+ buff = pkg_db_fh.read(0x1000)
+ if not buff:
+ break
+ digest.update(buff)
+ return digest.hexdigest()
+
+
+def dpkg_post_invoke():
+ """
+ Hook after the package installation transaction.
+ """
+ if 'SALT_RUNNING' not in os.environ:
+ with open(CK_PATH, 'w') as ck_fh:
+ ck_fh.write('{chksum} {mtime}\n'.format(chksum=_get_checksum(), mtime=_get_mtime()))
+
+
+if __name__ == "__main__":
+ dpkg_post_invoke()
--
2.30.2

View File

@ -0,0 +1,276 @@
From 8a584a8546667ab5390e9a2003a8ce3cb3add25c 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
* Pass __context__ to ext pillar
* Add test for passing the context to pillar ext module
* Align the test and pillar to prevent failing test
---
salt/master.py | 7 ++-
salt/pillar/__init__.py | 16 +++++-
tests/pytests/unit/test_master.py | 91 ++++++++++++++++++++++++++++++-
3 files changed, 108 insertions(+), 6 deletions(-)
diff --git a/salt/master.py b/salt/master.py
index 7f41ffe77b..0110082626 100644
--- a/salt/master.py
+++ b/salt/master.py
@@ -951,6 +951,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()
+ self.context = {}
# 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):
self.key,
)
self.clear_funcs.connect()
- self.aes_funcs = AESFuncs(self.opts)
+ self.aes_funcs = AESFuncs(self.opts, context=self.context)
salt.utils.crypt.reinit_crypto()
self.__bind()
@@ -1202,7 +1203,7 @@ class AESFuncs(TransportMethods):
"_ext_nodes", # To be removed in 3006 (Sulfur) #60980
)
- def __init__(self, opts):
+ def __init__(self, opts, context=None):
"""
Create a new AESFuncs
@@ -1212,6 +1213,7 @@ class AESFuncs(TransportMethods):
:returns: Instance for handling AES operations
"""
self.opts = opts
+ self.context = context
self.event = salt.utils.event.get_master_event(
self.opts, self.opts["sock_dir"], listen=False
)
@@ -1603,6 +1605,7 @@ class AESFuncs(TransportMethods):
pillarenv=load.get("pillarenv"),
extra_minion_data=load.get("extra_minion_data"),
clean_cache=load.get("clean_cache"),
+ context=self.context,
)
data = pillar.compile_pillar()
self.fs_.update_opts()
diff --git a/salt/pillar/__init__.py b/salt/pillar/__init__.py
index 7be963566a..906bdfe55d 100644
--- a/salt/pillar/__init__.py
+++ b/salt/pillar/__init__.py
@@ -46,6 +46,7 @@ def get_pillar(
pillarenv=None,
extra_minion_data=None,
clean_cache=False,
+ context=None,
):
"""
Return the correct pillar driver based on the file_client option
@@ -81,6 +82,7 @@ def get_pillar(
pillar_override=pillar_override,
pillarenv=pillarenv,
clean_cache=clean_cache,
+ context=context,
)
return ptype(
opts,
@@ -92,6 +94,7 @@ def get_pillar(
pillar_override=pillar_override,
pillarenv=pillarenv,
extra_minion_data=extra_minion_data,
+ context=context,
)
@@ -280,7 +283,7 @@ class AsyncRemotePillar(RemotePillarMixin):
raise salt.ext.tornado.gen.Return(ret_pillar)
def destroy(self):
- if self._closing:
+ if hasattr(self, "_closing") and self._closing:
return
self._closing = True
@@ -309,6 +312,7 @@ class RemotePillar(RemotePillarMixin):
pillar_override=None,
pillarenv=None,
extra_minion_data=None,
+ context=None,
):
self.opts = opts
self.opts["saltenv"] = saltenv
@@ -333,6 +337,7 @@ class RemotePillar(RemotePillarMixin):
merge_lists=True,
)
self._closing = False
+ self.context = context
def compile_pillar(self):
"""
@@ -406,6 +411,7 @@ class PillarCache:
pillarenv=None,
extra_minion_data=None,
clean_cache=False,
+ context=None,
):
# 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:
minion_cache_path=self._minion_cache_path(minion_id),
)
+ self.context = context
+
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,
pillar_override=self.pillar_override,
pillarenv=self.pillarenv,
+ context=self.context,
)
return fresh_pillar.compile_pillar()
@@ -530,6 +539,7 @@ class Pillar:
pillar_override=None,
pillarenv=None,
extra_minion_data=None,
+ context=None,
):
self.minion_id = minion_id
self.ext = ext
@@ -568,7 +578,7 @@ class Pillar:
if opts.get("pillar_source_merging_strategy"):
self.merge_strategy = opts["pillar_source_merging_strategy"]
- self.ext_pillars = salt.loader.pillars(ext_pillar_opts, self.functions)
+ self.ext_pillars = salt.loader.pillars(ext_pillar_opts, self.functions, context=context)
self.ignored_pillars = {}
self.pillar_override = pillar_override or {}
if not isinstance(self.pillar_override, dict):
@@ -1335,7 +1345,7 @@ class Pillar:
"""
This method exist in order to be API compatible with RemotePillar
"""
- if self._closing:
+ if hasattr(self, "_closing") and self._closing:
return
self._closing = True
diff --git a/tests/pytests/unit/test_master.py b/tests/pytests/unit/test_master.py
index a49ecfec3b..ca02c7788d 100644
--- a/tests/pytests/unit/test_master.py
+++ b/tests/pytests/unit/test_master.py
@@ -1,7 +1,7 @@
import time
import salt.master
-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
+
+
+def test_mworker_pass_context():
+ """
+ Test of passing the __context__ to pillar ext module loader
+ """
+ req_channel_mock = MagicMock()
+ local_client_mock = MagicMock()
+
+ opts = {
+ "req_server_niceness": None,
+ "mworker_niceness": None,
+ "sock_dir": "/tmp",
+ "conf_file": "/tmp/fake_conf",
+ "transport": "zeromq",
+ "fileserver_backend": ["roots"],
+ "file_client": "local",
+ "pillar_cache": False,
+ "state_top": "top.sls",
+ "pillar_roots": {},
+ }
+
+ data = {
+ "id": "MINION_ID",
+ "grains": {},
+ "saltenv": None,
+ "pillarenv": None,
+ "pillar_override": {},
+ "extra_minion_data": {},
+ "ver": "2",
+ "cmd": "_pillar",
+ }
+
+ test_context = {"testing": 123}
+
+ def mworker_bind_mock():
+ mworker.aes_funcs.run_func(data["cmd"], data)
+
+ with patch("salt.client.get_local_client", local_client_mock), patch(
+ "salt.master.ClearFuncs", MagicMock()
+ ), patch("salt.minion.MasterMinion", MagicMock()), patch(
+ "salt.utils.verify.valid_id", return_value=True
+ ), patch(
+ "salt.loader.matchers", MagicMock()
+ ), patch(
+ "salt.loader.render", MagicMock()
+ ), patch(
+ "salt.loader.utils", MagicMock()
+ ), patch(
+ "salt.loader.fileserver", MagicMock()
+ ), patch(
+ "salt.loader.minion_mods", MagicMock()
+ ), patch(
+ "salt.loader._module_dirs", MagicMock()
+ ), patch(
+ "salt.loader.LazyLoader", MagicMock()
+ ) as loadler_pillars_mock:
+ mworker = salt.master.MWorker(opts, {}, {}, [req_channel_mock])
+
+ with patch.object(mworker, "_MWorker__bind", mworker_bind_mock), patch.dict(
+ mworker.context, test_context
+ ):
+ mworker.run()
+ assert (
+ loadler_pillars_mock.call_args_list[0][1].get("pack").get("__context__")
+ == test_context
+ )
+
+ loadler_pillars_mock.reset_mock()
+
+ opts.update(
+ {
+ "pillar_cache": True,
+ "pillar_cache_backend": "file",
+ "pillar_cache_ttl": 1000,
+ "cachedir": "/tmp",
+ }
+ )
+
+ mworker = salt.master.MWorker(opts, {}, {}, [req_channel_mock])
+
+ with patch.object(mworker, "_MWorker__bind", mworker_bind_mock), patch.dict(
+ mworker.context, test_context
+ ), patch("salt.utils.cache.CacheFactory.factory", MagicMock()):
+ mworker.run()
+ assert (
+ loadler_pillars_mock.call_args_list[0][1].get("pack").get("__context__")
+ == test_context
+ )
--
2.37.3

View File

@ -1,4 +1,4 @@
From c86432645863a21da589346ad587b610ab51a2a9 Mon Sep 17 00:00:00 2001
From ad3735581379e5d4bbc7baef3eaa4a1b8387ccbf 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
@ -11,14 +11,14 @@ Subject: [PATCH] Prevent affection of SSH.opts with LazyLoader
* Fix test_ssh unit tests
---
salt/client/ssh/__init__.py | 19 +++++++++++--------
tests/unit/client/test_ssh.py | 16 ++++++++--------
2 files changed, 19 insertions(+), 16 deletions(-)
tests/unit/client/test_ssh.py | 18 +++++++++---------
2 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index bc77eb700e..6d24d8d716 100644
index 8ae417f575..fe1213b723 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -225,15 +225,16 @@ class SSH:
@@ -224,15 +224,16 @@ class SSH(MultiprocessingStateMixin):
ROSTER_UPDATE_FLAG = "#__needs_update"
def __init__(self, opts, context=None):
@ -29,8 +29,8 @@ index bc77eb700e..6d24d8d716 100644
+ pull_sock = os.path.join(self.opts["sock_dir"], "master_event_pull.ipc")
if os.path.exists(pull_sock) and zmq:
self.event = salt.utils.event.get_event(
- "master", opts["sock_dir"], opts["transport"], opts=opts, listen=False
+ "master", self.opts["sock_dir"], self.opts["transport"], opts=self.opts, listen=False
- "master", opts["sock_dir"], opts=opts, listen=False
+ "master", self.opts["sock_dir"], opts=self.opts, listen=False
)
else:
self.event = None
@ -38,7 +38,7 @@ index bc77eb700e..6d24d8d716 100644
if self.opts["regen_thin"]:
self.opts["ssh_wipe"] = True
if not salt.utils.path.which("ssh"):
@@ -244,7 +245,7 @@ class SSH:
@@ -243,7 +244,7 @@ class SSH(MultiprocessingStateMixin):
" to run. Exiting."
),
)
@ -47,7 +47,7 @@ index bc77eb700e..6d24d8d716 100644
self.tgt_type = (
self.opts["selected_target_option"]
if self.opts["selected_target_option"]
@@ -341,6 +342,9 @@ class SSH:
@@ -339,6 +340,9 @@ class SSH(MultiprocessingStateMixin):
self.opts["cachedir"], "salt-ssh.session.lock"
)
self.ssh_session_grace_time = int(self.opts.get("ssh_session_grace_time", 1))
@ -55,9 +55,9 @@ index bc77eb700e..6d24d8d716 100644
+ self.sopts["ssh_cli_tgt"] = copy.deepcopy(self.opts["ssh_cli_tgt"])
+ self.opts = self.sopts
@property
def parse_tgt(self):
@@ -594,7 +598,6 @@ class SSH:
# __setstate__ and __getstate__ are only used on spawning platforms.
def __setstate__(self, state):
@@ -607,7 +611,6 @@ class SSH(MultiprocessingStateMixin):
Spin up the needed threads or processes and execute the subsequent
routines
"""
@ -65,7 +65,7 @@ index bc77eb700e..6d24d8d716 100644
que = multiprocessing.Queue()
running = {}
targets_queue = deque(self.targets.keys())
@@ -605,7 +608,7 @@ class SSH:
@@ -618,7 +621,7 @@ class SSH(MultiprocessingStateMixin):
if not self.targets:
log.error("No matching targets found in roster.")
break
@ -74,7 +74,7 @@ index bc77eb700e..6d24d8d716 100644
if targets_queue:
host = targets_queue.popleft()
else:
@@ -669,7 +672,7 @@ class SSH:
@@ -682,7 +685,7 @@ class SSH(MultiprocessingStateMixin):
continue
args = (
que,
@ -83,7 +83,7 @@ index bc77eb700e..6d24d8d716 100644
host,
self.targets[host],
mine,
@@ -763,7 +766,7 @@ class SSH:
@@ -776,7 +779,7 @@ class SSH(MultiprocessingStateMixin):
if len(rets) >= len(self.targets):
break
# Sleep when limit or all threads started
@ -93,7 +93,7 @@ index bc77eb700e..6d24d8d716 100644
) >= len(running):
time.sleep(0.1)
diff --git a/tests/unit/client/test_ssh.py b/tests/unit/client/test_ssh.py
index 23cb3d0700..5003500de1 100644
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):
@ -110,11 +110,20 @@ index 23cb3d0700..5003500de1 100644
):
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):
"""
@@ -562,7 +562,7 @@ class SSHTests(ShellCase):
@@ -587,7 +587,7 @@ class SSHTests(ShellCase):
MagicMock(return_value=salt.utils.yaml.safe_load(self.roster)),
):
client._expand_target()
@ -123,7 +132,7 @@ index 23cb3d0700..5003500de1 100644
def test_expand_target_no_user(self):
"""
@@ -602,7 +602,7 @@ class SSHTests(ShellCase):
@@ -627,7 +627,7 @@ class SSHTests(ShellCase):
client = ssh.SSH(opts)
assert opts["tgt"] == user + host
client._update_targets()
@ -132,7 +141,7 @@ index 23cb3d0700..5003500de1 100644
assert client.targets[host]["user"] == user.split("@")[0]
def test_update_targets_dns(self):
@@ -620,7 +620,7 @@ class SSHTests(ShellCase):
@@ -645,7 +645,7 @@ class SSHTests(ShellCase):
client = ssh.SSH(opts)
assert opts["tgt"] == user + host
client._update_targets()
@ -141,7 +150,7 @@ index 23cb3d0700..5003500de1 100644
assert client.targets[host]["user"] == user.split("@")[0]
def test_update_targets_no_user(self):
@@ -661,7 +661,7 @@ class SSHTests(ShellCase):
@@ -686,7 +686,7 @@ class SSHTests(ShellCase):
):
client._expand_target()
client._update_targets()
@ -150,7 +159,7 @@ index 23cb3d0700..5003500de1 100644
assert client.targets[host]["user"] == user.split("@")[0]
def test_parse_tgt(self):
@@ -681,7 +681,7 @@ class SSHTests(ShellCase):
@@ -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]
@ -159,7 +168,7 @@ index 23cb3d0700..5003500de1 100644
def test_parse_tgt_no_user(self):
"""
@@ -700,7 +700,7 @@ class SSHTests(ShellCase):
@@ -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"]
@ -169,6 +178,6 @@ index 23cb3d0700..5003500de1 100644
def test_extra_filerefs(self):
"""
--
2.35.1
2.37.3

View File

@ -1,4 +1,4 @@
From 27db7d49c4b3348d5dcfe229f0d5823c0e770179 Mon Sep 17 00:00:00 2001
From 6c1878310bf75be467b5ce15e8c89134a6f770cb 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
@ -12,52 +12,11 @@ Subject: [PATCH] Prevent pkg plugins errors on missing cookie path
* Fix yumnotify
---
scripts/suse/dpkg/dpkgnotify | 18 +++++++++++++++---
scripts/suse/yum/plugins/README.md | 2 +-
scripts/suse/yum/plugins/yumnotify.py | 17 +++++++++++++----
scripts/suse/zypper/plugins/commit/zyppnotify | 18 ++++++++++++------
4 files changed, 41 insertions(+), 14 deletions(-)
3 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/scripts/suse/dpkg/dpkgnotify b/scripts/suse/dpkg/dpkgnotify
index d3ad3d2ba9..3d6d038a98 100644
--- a/scripts/suse/dpkg/dpkgnotify
+++ b/scripts/suse/dpkg/dpkgnotify
@@ -2,10 +2,12 @@
import os
import hashlib
+import sys
CK_PATH = "/var/cache/salt/minion/dpkg.cookie"
DPKG_PATH = "/var/lib/dpkg/status"
+
def _get_mtime():
"""
Get the modified time of the Package Database.
@@ -35,9 +37,19 @@ def dpkg_post_invoke():
"""
Hook after the package installation transaction.
"""
- if 'SALT_RUNNING' not in os.environ:
- with open(CK_PATH, 'w') as ck_fh:
- ck_fh.write('{chksum} {mtime}\n'.format(chksum=_get_checksum(), mtime=_get_mtime()))
+ if "SALT_RUNNING" not in os.environ:
+ try:
+ ck_dir = os.path.dirname(CK_PATH)
+ if not os.path.exists(ck_dir):
+ os.makedirs(ck_dir)
+ with open(CK_PATH, "w") as ck_fh:
+ ck_fh.write(
+ "{chksum} {mtime}\n".format(
+ chksum=_get_checksum(), mtime=_get_mtime()
+ )
+ )
+ except OSError as e:
+ print("Unable to save the cookie file: %s" % (e), file=sys.stderr)
if __name__ == "__main__":
diff --git a/scripts/suse/yum/plugins/README.md b/scripts/suse/yum/plugins/README.md
index cb3abd2260..3515845b31 100644
--- a/scripts/suse/yum/plugins/README.md
@ -138,6 +97,6 @@ index bacbc8b97e..e3528e87a9 100755
self.ack()
--
2.34.1
2.37.3

View File

@ -1,4 +1,4 @@
From 24093156ace91a8766eb1f5acbc47eee8e634d8e Mon Sep 17 00:00:00 2001
From 57f2400bfce206e16e7f282cd3b93cd4d7e99dd7 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
@ -11,17 +11,14 @@ Readjust logic to validate script args
Use RLock to prevent issues in single threads
---
salt/_logging/impl.py | 2 +-
salt/client/ssh/__init__.py | 9 ++--
tests/integration/ssh/test_pre_flight.py | 56 ++++++++++++++++++++++--
tests/unit/client/test_ssh.py | 35 +++++++++++++++
4 files changed, 92 insertions(+), 10 deletions(-)
salt/_logging/impl.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/salt/_logging/impl.py b/salt/_logging/impl.py
index 953490b284..4f48672032 100644
index e050f43caf..2d1a276cb8 100644
--- a/salt/_logging/impl.py
+++ b/salt/_logging/impl.py
@@ -92,7 +92,7 @@ MODNAME_PATTERN = re.compile(r"(?P<name>%%\(name\)(?:\-(?P<digits>[\d]+))?s)")
@@ -107,7 +107,7 @@ DFLT_LOG_FMT_LOGFILE = "%(asctime)s,%(msecs)03d [%(name)-17s:%(lineno)-4d][%(lev
# LOG_LOCK is used to prevent deadlocks on using logging
# in combination with multiprocessing with salt-api
@ -29,163 +26,8 @@ index 953490b284..4f48672032 100644
+LOG_LOCK = threading.RLock()
# ----- REMOVE ME ON REFACTOR COMPLETE ------------------------------------------------------------------------------>
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index 0066f4597b..3e032c7197 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -15,6 +15,7 @@ import os
import psutil
import queue
import re
+import shlex
import subprocess
import sys
import tarfile
@@ -1458,11 +1459,9 @@ ARGS = {arguments}\n'''.format(
"""
args = ""
if script_args:
- args = " {}".format(
- " ".join([str(el) for el in script_args])
- if isinstance(script_args, (list, tuple))
- else script_args
- )
+ if not isinstance(script_args, (list, tuple)):
+ script_args = shlex.split(str(script_args))
+ args = " {}".format(" ".join([shlex.quote(str(el)) for el in script_args]))
if extension == "ps1":
ret = self.shell.exec_cmd('"powershell {}"'.format(script))
else:
diff --git a/tests/integration/ssh/test_pre_flight.py b/tests/integration/ssh/test_pre_flight.py
index 6233ec0fe7..9c39219e9d 100644
--- a/tests/integration/ssh/test_pre_flight.py
+++ b/tests/integration/ssh/test_pre_flight.py
@@ -25,10 +25,14 @@ class SSHPreFlightTest(SSHCase):
RUNTIME_VARS.TMP, "test-pre-flight-script-worked.txt"
)
- def _create_roster(self):
- self.custom_roster(self.roster, self.data)
+ def _create_roster(self, pre_flight_script_args=None):
+ data = dict(self.data)
+ if pre_flight_script_args:
+ data["ssh_pre_flight_args"] = pre_flight_script_args
- with salt.utils.files.fopen(self.data["ssh_pre_flight"], "w") as fp_:
+ self.custom_roster(self.roster, data)
+
+ with salt.utils.files.fopen(data["ssh_pre_flight"], "w") as fp_:
fp_.write("touch {}".format(self.test_script))
@pytest.mark.slow_test
@@ -58,6 +62,45 @@ class SSHPreFlightTest(SSHCase):
)
assert os.path.exists(self.test_script)
+ @pytest.mark.slow_test
+ def test_ssh_run_pre_flight_args(self):
+ """
+ test ssh when --pre-flight is passed to salt-ssh
+ to ensure the script runs successfully passing some args
+ """
+ self._create_roster(pre_flight_script_args="foobar test")
+ # make sure we previously ran a command so the thin dir exists
+ self.run_function("test.ping", wipe=False)
+ assert not os.path.exists(self.test_script)
+
+ assert self.run_function(
+ "test.ping", ssh_opts="--pre-flight", roster_file=self.roster, wipe=False
+ )
+ assert os.path.exists(self.test_script)
+
+ @pytest.mark.slow_test
+ def test_ssh_run_pre_flight_args_prevent_injection(self):
+ """
+ test ssh when --pre-flight is passed to salt-ssh
+ and evil arguments are used in order to produce shell injection
+ """
+ injected_file = os.path.join(RUNTIME_VARS.TMP, "injection")
+ self._create_roster(
+ pre_flight_script_args="foobar; echo injected > {}".format(injected_file)
+ )
+ # make sure we previously ran a command so the thin dir exists
+ self.run_function("test.ping", wipe=False)
+ assert not os.path.exists(self.test_script)
+ assert not os.path.isfile(injected_file)
+
+ assert self.run_function(
+ "test.ping", ssh_opts="--pre-flight", roster_file=self.roster, wipe=False
+ )
+
+ assert not os.path.isfile(
+ injected_file
+ ), "File injection suceeded. This shouldn't happend"
+
@pytest.mark.slow_test
def test_ssh_run_pre_flight_failure(self):
"""
@@ -77,7 +120,12 @@ class SSHPreFlightTest(SSHCase):
"""
make sure to clean up any old ssh directories
"""
- files = [self.roster, self.data["ssh_pre_flight"], self.test_script]
+ files = [
+ self.roster,
+ self.data["ssh_pre_flight"],
+ self.test_script,
+ os.path.join(RUNTIME_VARS.TMP, "injection"),
+ ]
for fp_ in files:
if os.path.exists(fp_):
os.remove(fp_)
diff --git a/tests/unit/client/test_ssh.py b/tests/unit/client/test_ssh.py
index 6f3d87d493..23cb3d0700 100644
--- a/tests/unit/client/test_ssh.py
+++ b/tests/unit/client/test_ssh.py
@@ -234,6 +234,41 @@ class SSHSingleTests(TestCase):
mock_flight.assert_called()
assert ret == cmd_ret
+ def test_run_with_pre_flight_with_args(self):
+ """
+ test Single.run() when ssh_pre_flight is set
+ and script successfully runs
+ """
+ target = self.target.copy()
+ target["ssh_pre_flight"] = os.path.join(RUNTIME_VARS.TMP, "script.sh")
+ target["ssh_pre_flight_args"] = "foobar"
+ single = ssh.Single(
+ self.opts,
+ self.opts["argv"],
+ "localhost",
+ mods={},
+ fsclient=None,
+ thin=salt.utils.thin.thin_path(self.opts["cachedir"]),
+ mine=False,
+ **target
+ )
+
+ cmd_ret = ("Success", "foobar", 0)
+ mock_flight = MagicMock(return_value=cmd_ret)
+ mock_cmd = MagicMock(return_value=cmd_ret)
+ patch_flight = patch("salt.client.ssh.Single.run_ssh_pre_flight", mock_flight)
+ patch_cmd = patch("salt.client.ssh.Single.cmd_block", mock_cmd)
+ patch_exec_cmd = patch(
+ "salt.client.ssh.shell.Shell.exec_cmd", return_value=("", "", 1)
+ )
+ patch_os = patch("os.path.exists", side_effect=[True])
+
+ with patch_os, patch_flight, patch_cmd, patch_exec_cmd:
+ ret = single.run()
+ mock_cmd.assert_called()
+ mock_flight.assert_called()
+ assert ret == cmd_ret
+
def test_run_with_pre_flight_stderr(self):
"""
test Single.run() when ssh_pre_flight is set
class SaltLogRecord(logging.LogRecord):
--
2.35.1
2.37.3

View File

@ -1,4 +1,4 @@
From c3a058842344dacd01b0a0c55483c22b35f449e8 Mon Sep 17 00:00:00 2001
From c27ac9afb6bd13fc26fc440e0a097bbb82cbb640 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 b5621174a4..c3342ab6d1 100644
index dd836b7ad0..32e22ce9a8 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -1111,7 +1111,9 @@ def _get_repo_info(alias, repos_cfg=None, root=None):
@@ -1121,7 +1121,9 @@ def _get_repo_info(alias, repos_cfg=None, root=None):
Get one repo meta-data.
"""
try:
@ -24,6 +24,6 @@ index b5621174a4..c3342ab6d1 100644
for key, val in meta.items():
if val in ["0", "1"]:
--
2.29.2
2.37.3

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
From 9885fa0fc9ec818515551b2a415e6f1b8e3680b9 Mon Sep 17 00:00:00 2001
From 2de635bd9c2f9571092d5904ac8fa971c0140235 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 6af922337f..ac618bd385 100644
index e52535d428..dd836b7ad0 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -1401,8 +1401,10 @@ def refresh_db(force=None, root=None):
@@ -1410,8 +1410,10 @@ def refresh_db(force=None, root=None):
return ret
@ -28,7 +28,7 @@ index 6af922337f..ac618bd385 100644
return sorted({pkg.split(":", 1)[0] for pkg in pkgs if len(pkg.split(":", 1)) == 2})
@@ -1418,6 +1420,7 @@ def install(
@@ -1427,6 +1429,7 @@ def install(
ignore_repo_failure=False,
no_recommends=False,
root=None,
@ -36,7 +36,7 @@ index 6af922337f..ac618bd385 100644
**kwargs
):
"""
@@ -1533,6 +1536,9 @@ def install(
@@ -1542,6 +1545,9 @@ def install(
.. versionadded:: 2018.3.0
@ -46,7 +46,7 @@ index 6af922337f..ac618bd385 100644
Returns a dict containing the new package names and versions::
@@ -1608,7 +1614,8 @@ def install(
@@ -1617,7 +1623,8 @@ def install(
diff_attr = kwargs.get("diff_attr")
@ -56,7 +56,7 @@ index 6af922337f..ac618bd385 100644
old = (
list_pkgs(attr=diff_attr, root=root, includes=includes)
if not downloadonly
@@ -1838,7 +1845,7 @@ def upgrade(
@@ -1847,7 +1854,7 @@ def upgrade(
return ret
@ -65,7 +65,7 @@ index 6af922337f..ac618bd385 100644
"""
Remove and purge do identical things but with different Zypper commands,
this function performs the common logic.
@@ -1848,7 +1855,7 @@ def _uninstall(name=None, pkgs=None, root=None):
@@ -1857,7 +1864,7 @@ def _uninstall(name=None, pkgs=None, root=None):
except MinionError as exc:
raise CommandExecutionError(exc)
@ -74,7 +74,7 @@ index 6af922337f..ac618bd385 100644
old = list_pkgs(root=root, includes=includes)
targets = []
for target in pkg_params:
@@ -1911,7 +1918,7 @@ def normalize_name(name):
@@ -1920,7 +1927,7 @@ def normalize_name(name):
def remove(
@ -83,7 +83,7 @@ index 6af922337f..ac618bd385 100644
): # pylint: disable=unused-argument
"""
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
@@ -1943,8 +1950,11 @@ def remove(
@@ -1952,8 +1959,11 @@ def remove(
root
Operate on a different root directory.
@ -96,7 +96,7 @@ index 6af922337f..ac618bd385 100644
Returns a dict containing the changes.
@@ -1956,10 +1966,12 @@ def remove(
@@ -1965,10 +1975,12 @@ def remove(
salt '*' pkg.remove <package1>,<package2>,<package3>
salt '*' pkg.remove pkgs='["foo", "bar"]'
"""
@ -111,7 +111,7 @@ index 6af922337f..ac618bd385 100644
"""
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
On minions running systemd>=205, `systemd-run(1)`_ is now used to
@@ -1991,6 +2003,10 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused-
@@ -2000,6 +2012,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 6af922337f..ac618bd385 100644
.. versionadded:: 0.16.0
@@ -2004,7 +2020,7 @@ def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused-
@@ -2013,7 +2029,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"]'
"""
@ -130,8 +130,8 @@ index 6af922337f..ac618bd385 100644
+ return _uninstall(inclusion_detection, name=name, pkgs=pkgs, root=root)
def list_locks(root=None):
def list_holds(pattern=None, full=True, root=None, **kwargs):
--
2.33.0
2.37.3

View File

@ -1,4 +1,4 @@
From cedde1082b3a11b941327ba8e213f44637fb8a6b Mon Sep 17 00:00:00 2001
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)
@ -27,7 +27,7 @@ index 0000000000..59f1914593
@@ -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 b622105e15..7a249486fb 100644
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
@ -292,6 +292,6 @@ index 3f1560a385..37d555844c 100644
+ self.assertEqual(lockf_mock.call_count, 2)
+ zypper.__zypper__._reset()
--
2.37.2
2.37.3

View File

@ -1,4 +1,4 @@
From 2883215dfb434d4056812ed96d968f7043501d70 Mon Sep 17 00:00:00 2001
From 3ce70f43376dbf62edf2ca2aa8c9f28aa733b3d8 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,7 +8,7 @@ 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 ba600e106b..3e990cc05d 100644
index e80a01f92f..8203d2f989 100644
--- a/salt/utils/pkg/rpm.py
+++ b/salt/utils/pkg/rpm.py
@@ -59,9 +59,10 @@ def get_osarch():
@ -26,6 +26,6 @@ index ba600e106b..3e990cc05d 100644
def check_32(arch, osarch=None):
--
2.33.0
2.37.3

View File

@ -1,4 +1,4 @@
From a82b6316d8a780a7a8cbfbabeb52fa50b3fb1032 Mon Sep 17 00:00:00 2001
From dc849a15ea214170d4de9f54615caa8b3136dc10 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
@ -21,19 +21,19 @@ This reverts commit 66c58dedf8c364eaeb35c5adce8bcc8fe5c1219a.
7 files changed, 11 insertions(+), 48 deletions(-)
diff --git a/salt/beacons/__init__.py b/salt/beacons/__init__.py
index 414142c262..13e2ae78db 100644
index b346c2a648..90918cba5b 100644
--- a/salt/beacons/__init__.py
+++ b/salt/beacons/__init__.py
@@ -71,7 +71,6 @@ class Beacon:
beacon_name = current_beacon_config["beacon_module"]
else:
beacon_name = mod
@@ -94,7 +94,6 @@ class Beacon:
log.error("Configuration for beacon must be a list.")
continue
- b_config[mod].append({"_beacon_name": mod})
fun_str = "{}.beacon".format(beacon_name)
validate_str = "{}.validate".format(beacon_name)
if fun_str in self.beacons:
runonce = self._determine_beacon_config(
diff --git a/salt/beacons/diskusage.py b/salt/beacons/diskusage.py
index 1216abf79b..897bc90a6a 100644
index 5be33ff975..0b8d7c53e1 100644
--- a/salt/beacons/diskusage.py
+++ b/salt/beacons/diskusage.py
@@ -8,7 +8,6 @@ Beacon to monitor disk usage.
@ -44,7 +44,7 @@ index 1216abf79b..897bc90a6a 100644
import salt.utils.platform
try:
@@ -81,8 +80,6 @@ def beacon(config):
@@ -83,8 +82,6 @@ def beacon(config):
it will override the previously defined threshold.
"""
@ -54,10 +54,10 @@ index 1216abf79b..897bc90a6a 100644
ret = []
for mounts in config:
diff --git a/salt/beacons/inotify.py b/salt/beacons/inotify.py
index b6e7334eee..c44bd49fb0 100644
index 283b84fdc7..0dc60662a6 100644
--- a/salt/beacons/inotify.py
+++ b/salt/beacons/inotify.py
@@ -65,19 +65,17 @@ def _get_notifier(config):
@@ -67,19 +67,17 @@ def _get_notifier(config):
"""
Check the context for the notifier and construct it if not present
"""
@ -81,7 +81,7 @@ index b6e7334eee..c44bd49fb0 100644
def validate(config):
@@ -237,9 +235,6 @@ def beacon(config):
@@ -239,9 +237,6 @@ def beacon(config):
being at the Notifier level in pyinotify.
"""
@ -91,7 +91,7 @@ index b6e7334eee..c44bd49fb0 100644
config = salt.utils.beacons.list_to_dict(config)
ret = []
@@ -262,7 +257,7 @@ def beacon(config):
@@ -264,7 +259,7 @@ def beacon(config):
break
path = os.path.dirname(path)
@ -100,7 +100,7 @@ index b6e7334eee..c44bd49fb0 100644
if excludes and isinstance(excludes, list):
for exclude in excludes:
@@ -349,9 +344,6 @@ def beacon(config):
@@ -351,9 +346,6 @@ def beacon(config):
def close(config):
@ -114,7 +114,7 @@ index b6e7334eee..c44bd49fb0 100644
+ __context__["inotify.notifier"].stop()
+ del __context__["inotify.notifier"]
diff --git a/salt/beacons/napalm_beacon.py b/salt/beacons/napalm_beacon.py
index ec8cf63fca..164b29cdf8 100644
index 122d56edb7..692fbe07aa 100644
--- a/salt/beacons/napalm_beacon.py
+++ b/salt/beacons/napalm_beacon.py
@@ -168,9 +168,10 @@ with a NTP server at a stratum level greater than 5.
@ -129,7 +129,7 @@ index ec8cf63fca..164b29cdf8 100644
import salt.utils.napalm
log = logging.getLogger(__name__)
@@ -301,9 +302,6 @@ def beacon(config):
@@ -306,9 +307,6 @@ def beacon(config):
"""
Watch napalm function and fire events.
"""
@ -186,10 +186,10 @@ 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 27940c6f65..a347f3f27f 100644
index 2ca0b30ea2..841a3b8140 100644
--- a/tests/pytests/unit/test_beacons.py
+++ b/tests/pytests/unit/test_beacons.py
@@ -70,19 +70,3 @@ def test_beacon_module():
@@ -108,19 +108,3 @@ def test_beacon_module():
]
assert ret == _expected
@ -210,6 +210,6 @@ index 27940c6f65..a347f3f27f 100644
- beacon.process(mock_opts["beacons"], mock_opts["grains"])
- patched[name].assert_has_calls(calls)
--
2.34.1
2.37.3

View File

@ -1,4 +1,4 @@
From cdecbbdf5db3f1cb6b603916fecd80738f5fae9a Mon Sep 17 00:00:00 2001
From 0dc36f5d2e8ba94e2a527323b698fd49a98f5246 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)
@ -8,7 +8,7 @@ Subject: [PATCH] Run salt-api as user salt (bsc#1064520)
1 file changed, 1 insertion(+)
diff --git a/pkg/salt-api.service b/pkg/salt-api.service
index 7ca582dfb4..bf513e4dbd 100644
index d0b6d74120..9cdc9c582b 100644
--- a/pkg/salt-api.service
+++ b/pkg/salt-api.service
@@ -6,6 +6,7 @@ After=network.target
@ -20,6 +20,6 @@ index 7ca582dfb4..bf513e4dbd 100644
ExecStart=/usr/bin/salt-api
TimeoutStopSec=3
--
2.29.2
2.37.3

View File

@ -1,4 +1,4 @@
From 3d75826c24a6a1533623982cc4d92325c739d908 Mon Sep 17 00:00:00 2001
From 34d047fa0e2733359501e15ecc282159ddbd29f9 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
@ -10,7 +10,7 @@ Subject: [PATCH] Run salt master as dedicated salt user
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/conf/master b/conf/master
index 07bf2e9591..6415a536e7 100644
index 17b3768267..95aed0066f 100644
--- a/conf/master
+++ b/conf/master
@@ -25,7 +25,8 @@
@ -42,6 +42,6 @@ index a0306ff370..97d158db18 100644
missingok
rotate 7
--
2.34.1
2.37.3

View File

@ -1,3 +1,175 @@
-------------------------------------------------------------------
Thu Jan 12 15:49:38 UTC 2023 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
- Allow entrypoint compatibility for "importlib-metadata>=5.0.0" (bsc#1207071)
- Added:
* allow-entrypoint-compatibility-for-importlib-metadat.patch
-------------------------------------------------------------------
Mon Jan 9 12:44:28 UTC 2023 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
- Add missing patch after rebase to fix collections Mapping issues
- Added:
* fixes-for-python-3.10-502.patch
-------------------------------------------------------------------
Wed Jan 4 13:29:57 UTC 2023 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
- Prevent deadlocks in salt-ssh executions
- Added:
* use-rlock-to-avoid-deadlocks-in-salt-ssh.patch
-------------------------------------------------------------------
Mon Jan 2 15:51:45 UTC 2023 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
- Create new salt-tests subpackage containing Salt tests
-------------------------------------------------------------------
Thu Dec 29 13:35:08 UTC 2022 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
- Update to Salt release version 3005.1
* See release notes: https://docs.saltstack.com/en/latest/topics/releases/3005.1.html
- Modified:
* activate-all-beacons-sources-config-pillar-grains.patch
* add-amazon-ec2-detection-for-virtual-grains-bsc-1195.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
* add-support-for-name-pkgs-and-diff_attr-parameters-t.patch
* align-amazon-ec2-nitro-grains-with-upstream-pr-bsc-1.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
* clarify-pkg.installed-pkg_verify-documentation.patch
* debian-info_installed-compatibility-50453.patch
* detect-module.run-syntax.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.states.file.managed-for-follow_symlinks-tru.patch
* fix-salt.utils.stringutils.to_str-calls-to-make-it-w.patch
* fix-state.apply-in-test-mode-with-file-state-module-.patch
* fix-test_ipc-unit-tests.patch
* fix-the-regression-for-yumnotify-plugin-456.patch
* fix-traceback.print_exc-calls-for-test_pip_state-432.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-aliases-in-the-fqdns-grains.patch
* include-stdout-in-error-message-for-zypperpkg-559.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-pass-renderer-configurable-other-fixes-532.patch
* make-setup.py-script-to-not-require-setuptools-9.1.patch
* make-sure-saltcacheloader-use-correct-fileclient-519.patch
* normalize-package-names-once-with-pkg.installed-remo.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
* retry-if-rpm-lock-is-temporarily-unavailable-547.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
* 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
* 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-salt-bundle-in-dockermod.patch
* x509-fixes-111.patch
* zypperpkg-ignore-retcode-104-for-search-bsc-1176697-.patch
- Removed:
* 3003.3-do-not-consider-skipped-targets-as-failed-for.patch
* 3003.3-postgresql-json-support-in-pillar-423.patch
* add-missing-ansible-module-functions-to-whitelist-in.patch
* add-rpm_vercmp-python-library-for-version-comparison.patch
* adds-explicit-type-cast-for-port.patch
* backport-syndic-auth-fixes.patch
* batch.py-avoid-exception-when-minion-does-not-respon.patch
* check-if-dpkgnotify-is-executable-bsc-1186674-376.patch
* do-not-crash-when-unexpected-cmd-output-at-listing-p.patch
* enhance-logging-when-inotify-beacon-is-missing-pyino.patch
* fix-62092-catch-zmq.error.zmqerror-to-set-hwm-for-zm.patch
* fix-crash-when-calling-manage.not_alive-runners.patch
* fixes-56144-to-enable-hotadd-profile-support.patch
* fixes-for-python-3.10-502.patch
* fix-exception-in-yumpkg.remove-for-not-installed-pac.patch
* fix-for-cve-2022-22967-bsc-1200566.patch
* fix-inspector-module-export-function-bsc-1097531-481.patch
* fix-ip6_interface-grain-to-not-leak-secondary-ipv4-a.patch
* fix-issues-with-salt-ssh-s-extra-filerefs.patch
* fix-jinja2-contextfuntion-base-on-version-bsc-119874.patch
* fix-multiple-security-issues-bsc-1197417.patch
* fix-salt-call-event.send-call-with-grains-and-pillar.patch
* fix-the-regression-in-schedule-module-releasded-in-3.patch
* fix-wrong-test_mod_del_repo_multiline_values-test-af.patch
* force-zyppnotify-to-prefer-packages.db-than-packages.patch
* implementation-of-held-unheld-functions-for-state-pk.patch
* implementation-of-suse_ip-execution-module-bsc-10999.patch
* improvements-on-ansiblegate-module-354.patch
* mock-ip_addrs-in-utils-minions.py-unit-test-443.patch
* notify-beacon-for-debian-ubuntu-systems-347.patch
* refactor-and-improvements-for-transactional-updates-.patch
* support-transactional-systems-microos.patch
* wipe-notify_socket-from-env-in-cmdmod-bsc-1193357-30.patch
-------------------------------------------------------------------
Fri Oct 28 14:43:03 UTC 2022 - Victor Zhestkov <victor.zhestkov@suse.com>
- Pass the context to pillar ext modules
- Align Amazon EC2 (Nitro) grains with upstream (bsc#1203685)
- Detect module run syntax version
- Implement automated patches alignment for the Salt Bundle
- Added:
* detect-module.run-syntax.patch
* pass-the-context-to-pillar-ext-modules.patch
* align-amazon-ec2-nitro-grains-with-upstream-pr-bsc-1.patch
-------------------------------------------------------------------
Fri Oct 21 13:30:08 UTC 2022 - Alexander Graul <alexander.graul@suse.com>
- Ignore extend declarations from excluded SLS files (bsc#1203886)
- Clarify pkg.installed pkg_verify documentation
- Enhance capture of error messages for Zypper calls in zypperpkg module
- Added:
* ignore-extend-declarations-from-excluded-sls-files.patch
* include-stdout-in-error-message-for-zypperpkg-559.patch
* clarify-pkg.installed-pkg_verify-documentation.patch
-------------------------------------------------------------------
Thu Oct 6 10:10:16 UTC 2022 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>

Some files were not shown because too many files have changed in this diff Show More