Sync from SUSE:ALP:Source:Standard:1.0 venv-salt-minion revision 852e9552de3017e4bdb2b48d4b0759fd

This commit is contained in:
Adrian Schröter 2024-11-15 12:54:50 +01:00
parent ef9db76e53
commit a72bcaa312
23 changed files with 2809 additions and 18 deletions

View File

@ -1 +1 @@
597049dd3d38cffb3d6e555ded591bc36ed09a58
cc4e56e0465b20664e2f24bfe7034e5fee37232f

View File

@ -0,0 +1,73 @@
From 1be3f92ef3bf14e47340e2e075291204b3e75e98 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Wed, 25 Sep 2024 14:07:42 +0300
Subject: [PATCH] Allow NamedLoaderContexts to be returned from loader
It is useful in some cases to return NamedLoaderContexts from loaded
functions. Instead of choking or requireing implimenters to call the
context's value() method before being de-scoped, detect when a
NamedLoaderContext has been returned and return the value from the
current context.
Co-authored-by: Daniel A. Wozniak <daniel.wozniak@broadcom.com>
---
salt/loader/lazy.py | 5 ++++-
tests/pytests/integration/modules/test_config.py | 8 ++++++++
tests/pytests/unit/loader/test_loader.py | 13 +++++++++++++
3 files changed, 25 insertions(+), 1 deletion(-)
create mode 100644 tests/pytests/integration/modules/test_config.py
diff --git a/salt/loader/lazy.py b/salt/loader/lazy.py
index 5de995d446..b7fd97f0e1 100644
--- a/salt/loader/lazy.py
+++ b/salt/loader/lazy.py
@@ -1246,7 +1246,10 @@ class LazyLoader(salt.utils.lazy.LazyDict):
self.parent_loader = current_loader
token = salt.loader.context.loader_ctxvar.set(self)
try:
- return _func_or_method(*args, **kwargs)
+ ret = _func_or_method(*args, **kwargs)
+ if isinstance(ret, salt.loader.context.NamedLoaderContext):
+ ret = ret.value()
+ return ret
finally:
self.parent_loader = None
salt.loader.context.loader_ctxvar.reset(token)
diff --git a/tests/pytests/integration/modules/test_config.py b/tests/pytests/integration/modules/test_config.py
new file mode 100644
index 0000000000..afdf470605
--- /dev/null
+++ b/tests/pytests/integration/modules/test_config.py
@@ -0,0 +1,8 @@
+import pytest
+
+
+@pytest.mark.slow_test
+def test_config_items(salt_cli, salt_minion):
+ ret = salt_cli.run("config.items", minion_tgt=salt_minion.id)
+ assert ret.returncode == 0
+ assert isinstance(ret.data, dict)
diff --git a/tests/pytests/unit/loader/test_loader.py b/tests/pytests/unit/loader/test_loader.py
index 86348749db..aba605f42a 100644
--- a/tests/pytests/unit/loader/test_loader.py
+++ b/tests/pytests/unit/loader/test_loader.py
@@ -62,3 +62,16 @@ def test_raw_mod_functions():
ret = salt.loader.raw_mod(opts, "grains", "get")
for k, v in ret.items():
assert isinstance(v, salt.loader.lazy.LoadedFunc)
+
+
+def test_return_named_context_from_loaded_func(tmp_path):
+ opts = {
+ "optimization_order": [0],
+ }
+ contents = """
+ def foobar():
+ return __test__
+ """
+ with pytest.helpers.temp_file("mymod.py", contents, directory=tmp_path):
+ loader = salt.loader.LazyLoader([tmp_path], opts, pack={"__test__": "meh"})
+ assert loader["mymod.foobar"]() == "meh"
--
2.46.1

View File

@ -0,0 +1,153 @@
From b2faa019f0f5aa03b03e6c54c9aa60b7f6aa4f91 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Fri, 30 Aug 2024 14:35:33 +0200
Subject: [PATCH] Avoid crash on wrong output of systemctl version
(bsc#1229539)
* Better handling output of systemctl --version
* Add more cases to test grains.core._systemd
---
salt/grains/core.py | 27 +++++++-
tests/pytests/unit/grains/test_core.py | 89 ++++++++++++++++++++++++++
2 files changed, 113 insertions(+), 3 deletions(-)
diff --git a/salt/grains/core.py b/salt/grains/core.py
index 4454c303fe..98bbd3868e 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -2432,10 +2432,31 @@ def _systemd():
"""
Return the systemd grain
"""
- systemd_info = __salt__["cmd.run"]("systemctl --version").splitlines()
+ systemd_version = "UNDEFINED"
+ systemd_features = ""
+ try:
+ systemd_output = __salt__["cmd.run_all"]("systemctl --version")
+ except Exception: # pylint: disable=broad-except
+ log.error("Exception while executing `systemctl --version`", exc_info=True)
+ return {
+ "version": systemd_version,
+ "features": systemd_features,
+ }
+ if systemd_output.get("retcode") == 0:
+ systemd_info = systemd_output.get("stdout", "").splitlines()
+ try:
+ if systemd_info[0].startswith("systemd "):
+ systemd_version = systemd_info[0].split()[1]
+ systemd_features = systemd_info[1]
+ except IndexError:
+ pass
+ if systemd_version == "UNDEFINED" or systemd_features == "":
+ log.error(
+ "Unexpected output returned by `systemctl --version`: %s", systemd_output
+ )
return {
- "version": systemd_info[0].split()[1],
- "features": systemd_info[1],
+ "version": systemd_version,
+ "features": systemd_features,
}
diff --git a/tests/pytests/unit/grains/test_core.py b/tests/pytests/unit/grains/test_core.py
index 36545287b9..b64b8c4bf8 100644
--- a/tests/pytests/unit/grains/test_core.py
+++ b/tests/pytests/unit/grains/test_core.py
@@ -3593,3 +3593,92 @@ def test_virtual_set_virtual_ec2():
assert virtual_grains["virtual"] == "Nitro"
assert virtual_grains["virtual_subtype"] == "Amazon EC2"
+
+
+@pytest.mark.parametrize(
+ "systemd_data,expected",
+ (
+ (
+ {
+ "pid": 1234,
+ "retcode": 0,
+ "stdout": "systemd 254 (254.3-1)\n+PAM +AUDIT -SELINUX -APPARMOR -IMA +SMACK "
+ "+SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS "
+ "+FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 "
+ "-PWQUALITY +P11KIT -QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD "
+ "+BPF_FRAMEWORK +XKBCOMMON +UTMP -SYSVINIT default-hierarchy=unified",
+ "stderr": "",
+ },
+ {
+ "version": "254",
+ "features": "+PAM +AUDIT -SELINUX -APPARMOR -IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL "
+ "+ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP "
+ "+LIBFDISK +PCRE2 -PWQUALITY +P11KIT -QRENCODE +TPM2 +BZIP2 +LZ4 +XZ "
+ "+ZLIB +ZSTD +BPF_FRAMEWORK +XKBCOMMON +UTMP -SYSVINIT default-hierarchy=unified",
+ },
+ ),
+ (
+ {
+ "pid": 2345,
+ "retcode": 1,
+ "stdout": "",
+ "stderr": "some garbage in the output",
+ },
+ {
+ "version": "UNDEFINED",
+ "features": "",
+ },
+ ),
+ (
+ {
+ "pid": 3456,
+ "retcode": 0,
+ "stdout": "unexpected stdout\none more line",
+ "stderr": "",
+ },
+ {
+ "version": "UNDEFINED",
+ "features": "",
+ },
+ ),
+ (
+ {
+ "pid": 4567,
+ "retcode": 0,
+ "stdout": "",
+ "stderr": "",
+ },
+ {
+ "version": "UNDEFINED",
+ "features": "",
+ },
+ ),
+ (
+ Exception("Some exception on calling `systemctl --version`"),
+ {
+ "version": "UNDEFINED",
+ "features": "",
+ },
+ ),
+ ),
+)
+def test__systemd(systemd_data, expected):
+ """
+ test _systemd
+ """
+
+ def mock_run_all_systemd(_):
+ if isinstance(systemd_data, Exception):
+ raise systemd_data
+ return systemd_data
+
+ with patch.dict(
+ core.__salt__,
+ {
+ "cmd.run_all": mock_run_all_systemd,
+ },
+ ):
+ ret = core._systemd()
+ assert "version" in ret
+ assert "features" in ret
+ assert ret == expected
--
2.46.0

View File

@ -0,0 +1,27 @@
From bbdb56932845dceb47332a4c967c13a9a78b88bc Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Wed, 25 Sep 2024 14:08:20 +0300
Subject: [PATCH] Avoid explicit reading of /etc/salt/minion
(bsc#1220357)
Co-authored-by: Daniel A. Wozniak <dwozniak@vmware.com>
---
salt/utils/azurearm.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/salt/utils/azurearm.py b/salt/utils/azurearm.py
index 276cbb66b3..9ae128273c 100644
--- a/salt/utils/azurearm.py
+++ b/salt/utils/azurearm.py
@@ -47,8 +47,6 @@ try:
except ImportError:
HAS_AZURE = False
-__opts__ = salt.config.minion_config("/etc/salt/minion")
-__salt__ = salt.loader.minion_mods(__opts__)
log = logging.getLogger(__name__)
--
2.46.1

View File

@ -0,0 +1,166 @@
From d5f3df07783d8aaf3a897ca2f209e662973b930c Mon Sep 17 00:00:00 2001
From: Marek Czernek <marek.czernek@suse.com>
Date: Wed, 4 Sep 2024 13:11:33 +0200
Subject: [PATCH] Fix deprecated code (#677)
Due to SUSE's extended support policy, we won't remove
code from Salt until next major release.
---
salt/_logging/handlers.py | 6 +++---
salt/log/__init__.py | 2 +-
salt/log/handlers/__init__.py | 2 +-
salt/log/mixins.py | 2 +-
salt/log/setup.py | 4 ++--
salt/modules/aptpkg.py | 2 +-
salt/modules/cassandra_mod.py | 2 +-
salt/returners/cassandra_return.py | 2 +-
salt/returners/django_return.py | 2 +-
9 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/salt/_logging/handlers.py b/salt/_logging/handlers.py
index f4b0b6fec3d..5a1a1613137 100644
--- a/salt/_logging/handlers.py
+++ b/salt/_logging/handlers.py
@@ -36,7 +36,7 @@ class TemporaryLoggingHandler(logging.NullHandler):
def __init__(self, level=logging.NOTSET, max_queue_size=10000):
warn_until_date(
- "20240101",
+ "20260101",
"Please stop using '{name}.TemporaryLoggingHandler'. "
"'{name}.TemporaryLoggingHandler' will go away after "
"{{date}}.".format(name=__name__),
@@ -225,7 +225,7 @@ if sys.version_info < (3, 7):
def __init__(self, queue): # pylint: disable=useless-super-delegation
super().__init__(queue)
warn_until_date(
- "20240101",
+ "20260101",
"Please stop using '{name}.QueueHandler' and instead "
"use 'logging.handlers.QueueHandler'. "
"'{name}.QueueHandler' will go away after "
@@ -283,7 +283,7 @@ else:
def __init__(self, queue): # pylint: disable=useless-super-delegation
super().__init__(queue)
warn_until_date(
- "20240101",
+ "20260101",
"Please stop using '{name}.QueueHandler' and instead "
"use 'logging.handlers.QueueHandler'. "
"'{name}.QueueHandler' will go away after "
diff --git a/salt/log/__init__.py b/salt/log/__init__.py
index 3458474f2ca..69bfa8ed15b 100644
--- a/salt/log/__init__.py
+++ b/salt/log/__init__.py
@@ -24,7 +24,7 @@ from salt.log.setup import (
from salt.utils.versions import warn_until_date
warn_until_date(
- "20240101",
+ "20260101",
"Please stop using '{name}' and instead use 'salt._logging'. "
"'{name}' will go away after {{date}}.".format(name=__name__),
stacklevel=3,
diff --git a/salt/log/handlers/__init__.py b/salt/log/handlers/__init__.py
index 8bc740e20f1..55cf10cdb78 100644
--- a/salt/log/handlers/__init__.py
+++ b/salt/log/handlers/__init__.py
@@ -12,7 +12,7 @@ from salt._logging.handlers import (
from salt.utils.versions import warn_until_date
warn_until_date(
- "20240101",
+ "20260101",
"Please stop using '{name}' and instead use 'salt._logging.handlers'. "
"'{name}' will go away after {{date}}.".format(name=__name__),
)
diff --git a/salt/log/mixins.py b/salt/log/mixins.py
index 6619b564198..65f5ed7f78a 100644
--- a/salt/log/mixins.py
+++ b/salt/log/mixins.py
@@ -11,7 +11,7 @@ from salt.utils.versions import warn_until_date
# pylint: enable=unused-import
warn_until_date(
- "20240101",
+ "20260101",
"Please stop using '{name}' and instead use 'salt._logging.mixins'. "
"'{name}' will go away after {{date}}.".format(name=__name__),
)
diff --git a/salt/log/setup.py b/salt/log/setup.py
index 74bd7bbd3e1..f4c80b0f280 100644
--- a/salt/log/setup.py
+++ b/salt/log/setup.py
@@ -21,7 +21,7 @@ from salt._logging.impl import set_log_record_factory as setLogRecordFactory
from salt.utils.versions import warn_until_date
warn_until_date(
- "20240101",
+ "20260101",
"Please stop using '{name}' and instead use 'salt._logging'. "
"'{name}' will go away after {{date}}. Do note however that "
"'salt._logging' is now considered a non public implementation "
@@ -34,7 +34,7 @@ def _deprecated_warning(func):
@wraps(func)
def wrapper(*args, **kwargs):
warn_until_date(
- "20240101",
+ "20260101",
"Please stop using 'salt.log.setup.{name}()' as it no longer does anything and "
"will go away after {{date}}.".format(name=func.__qualname__),
stacklevel=4,
diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py
index ad5450c4151..cd40aea54f1 100644
--- a/salt/modules/aptpkg.py
+++ b/salt/modules/aptpkg.py
@@ -3128,7 +3128,7 @@ def expand_repo_def(**kwargs):
NOT USABLE IN THE CLI
"""
warn_until_date(
- "20250101",
+ "20260101",
"The pkg.expand_repo_def function is deprecated and set for removal "
"after {date}. This is only unsed internally by the apt pkg state "
"module. If that's not the case, please file an new issue requesting "
diff --git a/salt/modules/cassandra_mod.py b/salt/modules/cassandra_mod.py
index 029fd08fb9b..db9c8821920 100644
--- a/salt/modules/cassandra_mod.py
+++ b/salt/modules/cassandra_mod.py
@@ -45,7 +45,7 @@ def __virtual__():
)
warn_until_date(
- "20240101",
+ "20260101",
"The cassandra returner is broken and deprecated, and will be removed"
" after {date}. Use the cassandra_cql returner instead",
)
diff --git a/salt/returners/cassandra_return.py b/salt/returners/cassandra_return.py
index ac01a4e46cb..5fcc00ee8ce 100644
--- a/salt/returners/cassandra_return.py
+++ b/salt/returners/cassandra_return.py
@@ -53,7 +53,7 @@ def __virtual__():
if not HAS_PYCASSA:
return False, "Could not import cassandra returner; pycassa is not installed."
warn_until_date(
- "20240101",
+ "20260101",
"The cassandra returner is broken and deprecated, and will be removed"
" after {date}. Use the cassandra_cql returner instead",
)
diff --git a/salt/returners/django_return.py b/salt/returners/django_return.py
index 36386875552..474653f3831 100644
--- a/salt/returners/django_return.py
+++ b/salt/returners/django_return.py
@@ -57,7 +57,7 @@ __virtualname__ = "django"
def __virtual__():
warn_until_date(
- "20240101",
+ "20260101",
"The django returner is broken and deprecated, and will be removed"
" after {date}.",
)
--
2.46.0

View File

@ -0,0 +1,25 @@
From a6d27a6f50bbbea539ec64bf96a5b9755e32bf69 Mon Sep 17 00:00:00 2001
From: Marek Czernek <marek.czernek@suse.com>
Date: Wed, 4 Sep 2024 13:11:05 +0200
Subject: [PATCH] Fix test_debian to work in our infrastructure (#676)
---
tests/pytests/functional/states/pkgrepo/test_debian.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/pytests/functional/states/pkgrepo/test_debian.py b/tests/pytests/functional/states/pkgrepo/test_debian.py
index 87716706d5e..7bda100b634 100644
--- a/tests/pytests/functional/states/pkgrepo/test_debian.py
+++ b/tests/pytests/functional/states/pkgrepo/test_debian.py
@@ -205,7 +205,7 @@ def ubuntu_state_tree(system_aptsources, state_tree, grains):
- dist: {{ codename }}
- file: /etc/apt/sources.list.d/firefox-beta.list
- keyid: CE49EC21
- - keyserver: keyserver.ubuntu.com
+ - keyserver: hkp://keyserver.ubuntu.com:80
{%- endif %}
{%- if backports %}{%- do ubuntu_repos.append('kubuntu-ppa') %}
--
2.46.0

View File

@ -0,0 +1,44 @@
From 5567f2bd51d66b7797c986cf64f79f71ca57eb63 Mon Sep 17 00:00:00 2001
From: Marek Czernek <marek.czernek@suse.com>
Date: Wed, 4 Sep 2024 13:10:44 +0200
Subject: [PATCH] Fix test_system flaky setup_teardown fn
---
tests/pytests/functional/modules/test_system.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/tests/pytests/functional/modules/test_system.py b/tests/pytests/functional/modules/test_system.py
index 2cd03a3a3e4..270aafbe2cd 100644
--- a/tests/pytests/functional/modules/test_system.py
+++ b/tests/pytests/functional/modules/test_system.py
@@ -4,10 +4,12 @@ import os
import signal
import subprocess
import textwrap
+import time
import pytest
import salt.utils.files
+from salt.exceptions import CommandExecutionError
INSIDE_CONTAINER = os.getenv("HOSTNAME", "") == "salt-test-container"
@@ -80,7 +82,13 @@ def setup_teardown_vars(file, service, system):
file.remove("/etc/machine-info")
if _systemd_timesyncd_available_:
- res = service.start("systemd-timesyncd")
+ try:
+ res = service.start("systemd-timesyncd")
+ except CommandExecutionError:
+ # We possibly did too many restarts in too short time
+ # Wait 10s (default systemd timeout) and try again
+ time.sleep(10)
+ res = service.start("systemd-timesyncd")
assert res
--
2.46.0

View File

@ -0,0 +1,83 @@
From d933c8f0795fdada84a01a2cc754586fa720993d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Tue, 10 Sep 2024 13:46:09 +0100
Subject: [PATCH] Fix the SELinux context for Salt Minion service
(bsc#1219041) (#670)
Currently there are no SELinux policies for Salt.
By default, the Salt Minion service runs as 'unconfined_service_t' when
SELinux is enabled. This works fine in most cases but generates a problem
then trying to transition to an 'unconfined_t', i.a. when running
"cmd.run .... runas=nobody". Then we see this denied in audit logs:
type=AVC msg=audit(1722870119.142:718): avc: denied { transition } for pid=3421 comm="su" path="/usr/bin/bash" dev="vda3" ino=28565 scontext=system_u:system_r:unconfined_service_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0 tclass=process permissive=0
(This happens for cmd.run at the time of trying to invoke a shell as a
different user to gather the environment variables from this particular
user)
Fixing the SELinuxContext for the Salt Minion systemd service to a
general 'unconfined_t' workarounds this situation.
SELinuxContext attribute was added on systemd version 209.
---
pkg/common/salt-minion.service | 1 +
pkg/old/deb/salt-minion.service | 1 +
pkg/old/suse/salt-minion.service | 1 +
pkg/old/suse/salt-minion.service.rhel7 | 1 +
4 files changed, 4 insertions(+)
diff --git a/pkg/common/salt-minion.service b/pkg/common/salt-minion.service
index 69aff18c583..696d0263c39 100644
--- a/pkg/common/salt-minion.service
+++ b/pkg/common/salt-minion.service
@@ -9,6 +9,7 @@ Type=notify
NotifyAccess=all
LimitNOFILE=8192
ExecStart=/usr/bin/salt-minion
+SELinuxContext=system_u:system_r:unconfined_t:s0
[Install]
WantedBy=multi-user.target
diff --git a/pkg/old/deb/salt-minion.service b/pkg/old/deb/salt-minion.service
index 7e6cf146549..b0ad82c1334 100644
--- a/pkg/old/deb/salt-minion.service
+++ b/pkg/old/deb/salt-minion.service
@@ -8,6 +8,7 @@ KillMode=process
NotifyAccess=all
LimitNOFILE=8192
ExecStart=/usr/bin/salt-minion
+SELinuxContext=system_u:system_r:unconfined_t:s0
[Install]
WantedBy=multi-user.target
diff --git a/pkg/old/suse/salt-minion.service b/pkg/old/suse/salt-minion.service
index 12f28314cb1..b99ef063522 100644
--- a/pkg/old/suse/salt-minion.service
+++ b/pkg/old/suse/salt-minion.service
@@ -10,6 +10,7 @@ ExecStart=/usr/bin/salt-minion
KillMode=process
Restart=on-failure
RestartSec=15
+SELinuxContext=system_u:system_r:unconfined_t:s0
[Install]
WantedBy=multi-user.target
diff --git a/pkg/old/suse/salt-minion.service.rhel7 b/pkg/old/suse/salt-minion.service.rhel7
index 69172677140..92cc66d32f4 100644
--- a/pkg/old/suse/salt-minion.service.rhel7
+++ b/pkg/old/suse/salt-minion.service.rhel7
@@ -9,6 +9,7 @@ ExecStart=/usr/bin/salt-minion
KillMode=process
Restart=on-failure
RestartSec=15
+SELinuxContext=system_u:system_r:unconfined_t:s0
[Install]
WantedBy=multi-user.target
--
2.46.0

View File

@ -0,0 +1,261 @@
From 7daf461528c90776b8f865cd58d20e23bd5b6f3f Mon Sep 17 00:00:00 2001
From: Marek Czernek <marek.czernek@suse.com>
Date: Wed, 2 Oct 2024 09:09:34 +0200
Subject: [PATCH] Fix x509 test fails on old openssl systems (#682)
---
.../functional/modules/test_x509_v2.py | 41 +++++++++++++----
.../pytests/functional/states/test_x509_v2.py | 44 +++++++++++++++----
.../scenarios/performance/test_performance.py | 8 +++-
3 files changed, 75 insertions(+), 18 deletions(-)
diff --git a/tests/pytests/functional/modules/test_x509_v2.py b/tests/pytests/functional/modules/test_x509_v2.py
index 2e8152d04a..7de8f3b01f 100644
--- a/tests/pytests/functional/modules/test_x509_v2.py
+++ b/tests/pytests/functional/modules/test_x509_v2.py
@@ -681,8 +681,13 @@ def test_create_certificate_self_signed(x509, algo, request):
privkey = request.getfixturevalue(f"{algo}_privkey")
try:
res = x509.create_certificate(signing_private_key=privkey, CN="success")
- except UnsupportedAlgorithm:
+ except (UnsupportedAlgorithm, NotImplementedError):
pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ except salt.exceptions.CommandExecutionError as e:
+ if "Could not load PEM-encoded" in e.error:
+ pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ else:
+ raise e
assert res.startswith("-----BEGIN CERTIFICATE-----")
cert = _get_cert(res)
assert cert.subject.rfc4514_string() == "CN=success"
@@ -754,8 +759,13 @@ def test_create_certificate_from_privkey(x509, ca_key, ca_cert, algo, request):
private_key=privkey,
CN="success",
)
- except UnsupportedAlgorithm:
+ except (UnsupportedAlgorithm, NotImplementedError):
pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ except salt.exceptions.CommandExecutionError as e:
+ if "Could not load PEM-encoded" in e.error:
+ pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ else:
+ raise e
assert res.startswith("-----BEGIN CERTIFICATE-----")
cert = _get_cert(res)
assert cert.subject.rfc4514_string() == "CN=success"
@@ -802,8 +812,13 @@ def test_create_certificate_from_pubkey(x509, ca_key, ca_cert, algo, request):
public_key=pubkey,
CN="success",
)
- except UnsupportedAlgorithm:
+ except (UnsupportedAlgorithm, NotImplementedError):
pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ except salt.exceptions.CommandExecutionError as e:
+ if "Could not load PEM-encoded" in e.error:
+ pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ else:
+ raise e
assert res.startswith("-----BEGIN CERTIFICATE-----")
cert = _get_cert(res)
assert cert.subject.rfc4514_string() == "CN=success"
@@ -1341,8 +1356,13 @@ def test_create_csr(x509, algo, request):
privkey = request.getfixturevalue(f"{algo}_privkey")
try:
res = x509.create_csr(private_key=privkey)
- except UnsupportedAlgorithm:
+ except (UnsupportedAlgorithm, NotImplementedError):
pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ except salt.exceptions.CommandExecutionError as e:
+ if "Could not load PEM-encoded" in e.error:
+ pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ else:
+ raise e
assert res.startswith("-----BEGIN CERTIFICATE REQUEST-----")
@@ -1402,7 +1422,7 @@ def test_create_csr_raw(x509, rsa_privkey):
def test_create_private_key(x509, algo):
try:
res = x509.create_private_key(algo=algo)
- except UnsupportedAlgorithm:
+ except (UnsupportedAlgorithm, NotImplementedError):
pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
assert res.startswith("-----BEGIN PRIVATE KEY-----")
@@ -1413,7 +1433,7 @@ def test_create_private_key_with_passphrase(x509, algo):
passphrase = "hunter2"
try:
res = x509.create_private_key(algo=algo, passphrase=passphrase)
- except UnsupportedAlgorithm:
+ except (UnsupportedAlgorithm, NotImplementedError):
pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
assert res.startswith("-----BEGIN ENCRYPTED PRIVATE KEY-----")
# ensure it can be loaded
@@ -1465,8 +1485,13 @@ def test_get_private_key_size(x509, algo, expected, request):
privkey = request.getfixturevalue(f"{algo}_privkey")
try:
res = x509.get_private_key_size(privkey)
- except UnsupportedAlgorithm:
+ except (UnsupportedAlgorithm, NotImplementedError):
pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ except salt.exceptions.CommandExecutionError as e:
+ if "Could not load PEM-encoded" in e.error:
+ pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
+ else:
+ raise e
assert res == expected
@@ -1612,7 +1637,7 @@ def test_verify_signature(x509, algo, request):
wrong_privkey = request.getfixturevalue(f"{algo}_privkey")
try:
privkey = x509.create_private_key(algo=algo)
- except UnsupportedAlgorithm:
+ except (UnsupportedAlgorithm, NotImplementedError):
pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
cert = x509.create_certificate(signing_private_key=privkey)
assert x509.verify_signature(cert, privkey)
diff --git a/tests/pytests/functional/states/test_x509_v2.py b/tests/pytests/functional/states/test_x509_v2.py
index 47a1c555f8..139f7b1906 100644
--- a/tests/pytests/functional/states/test_x509_v2.py
+++ b/tests/pytests/functional/states/test_x509_v2.py
@@ -574,9 +574,9 @@ def existing_cert(x509, cert_args, ca_key, rsa_privkey, request):
ca_key,
encoding=cert_args.get("encoding", "pem"),
passphrase=cert_args.get("pkcs12_passphrase"),
- subject=subject
- if "signing_policy" not in cert_args
- else "CN=from_signing_policy",
+ subject=(
+ subject if "signing_policy" not in cert_args else "CN=from_signing_policy"
+ ),
)
yield cert_args["name"]
@@ -694,8 +694,12 @@ def existing_csr_exts(x509, csr_args, csr_args_exts, ca_key, rsa_privkey, reques
def existing_pk(x509, pk_args, request):
pk_args.update(request.param)
ret = x509.private_key_managed(**pk_args)
- if ret.result == False and "UnsupportedAlgorithm" in ret.comment:
- pytest.skip(f"Algorithm '{pk_args['algo']}' is not supported on this OpenSSL version")
+ if ret.result == False and (
+ "UnsupportedAlgorithm" in ret.comment or "NotImplementedError" in ret.comment
+ ):
+ pytest.skip(
+ f"Algorithm '{pk_args['algo']}' is not supported on this OpenSSL version"
+ )
_assert_pk_basic(
ret,
pk_args.get("algo", "rsa"),
@@ -1054,6 +1058,8 @@ def test_certificate_managed_days_valid_does_not_override_days_remaining(
def test_certificate_managed_privkey_change(x509, cert_args, ec_privkey, ca_key):
cert_args["private_key"] = ec_privkey
ret = x509.certificate_managed(**cert_args)
+ if ret.result == False and "NotImplementedError" in ret.comment:
+ pytest.skip("Current OpenSSL does not support 'ec' algorithm")
_assert_cert_basic(ret, cert_args["name"], ec_privkey, ca_key)
assert ret.changes["private_key"]
@@ -1237,6 +1243,8 @@ def test_certificate_managed_wrong_ca_key(
cert_args["private_key"] = ec_privkey
cert_args["signing_private_key"] = rsa_privkey
ret = x509.certificate_managed(**cert_args)
+ if ret.result == False and "NotImplementedError" in ret.comment:
+ pytest.skip("Current OpenSSL does not support 'ec' algorithm")
assert ret.result is False
assert not ret.changes
assert "Signing private key does not match the certificate" in ret.comment
@@ -1917,6 +1925,8 @@ def test_csr_managed_existing_invalid_version(x509, csr_args, rsa_privkey):
def test_csr_managed_privkey_change(x509, csr_args, ec_privkey):
csr_args["private_key"] = ec_privkey
ret = x509.csr_managed(**csr_args)
+ if ret.result == False and "NotImplementedError" in ret.comment:
+ pytest.skip("Current OpenSSL does not support 'ec' algorithm")
_assert_csr_basic(ret, ec_privkey)
assert ret.changes["private_key"]
@@ -2141,11 +2151,14 @@ def test_private_key_managed(x509, pk_args, algo, encoding, passphrase):
pytest.skip(
"PKCS12 serialization of Edwards-curve keys requires cryptography v37"
)
+
pk_args["algo"] = algo
pk_args["encoding"] = encoding
pk_args["passphrase"] = passphrase
ret = x509.private_key_managed(**pk_args)
- if ret.result == False and "UnsupportedAlgorithm" in ret.comment:
+ if ret.result == False and (
+ "UnsupportedAlgorithm" in ret.comment or "NotImplementedError" in ret.comment
+ ):
pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
_assert_pk_basic(ret, algo, encoding, passphrase)
@@ -2155,6 +2168,8 @@ def test_private_key_managed_keysize(x509, pk_args, algo, keysize):
pk_args["algo"] = algo
pk_args["keysize"] = keysize
ret = x509.private_key_managed(**pk_args)
+ if ret.result == False and "NotImplementedError" in ret.comment:
+ pytest.skip("Current OpenSSL does not support 'ec' algorithm")
pk = _assert_pk_basic(ret, algo)
assert pk.key_size == keysize
@@ -2174,8 +2189,12 @@ def test_private_key_managed_keysize(x509, pk_args, algo, keysize):
)
def test_private_key_managed_existing(x509, pk_args):
ret = x509.private_key_managed(**pk_args)
- if ret.result == False and "UnsupportedAlgorithm" in ret.comment:
- pytest.skip(f"Algorithm '{pk_args['algo']}' is not supported on this OpenSSL version")
+ if ret.result == False and (
+ "UnsupportedAlgorithm" in ret.comment or "NotImplementedError" in ret.comment
+ ):
+ pytest.skip(
+ f"Algorithm '{pk_args['algo']}' is not supported on this OpenSSL version"
+ )
_assert_not_changed(ret)
@@ -2382,6 +2401,8 @@ def test_private_key_managed_follow_symlinks_changes(
pk_args["encoding"] = encoding
pk_args["algo"] = "ec"
ret = x509.private_key_managed(**pk_args)
+ if ret.result == False and "NotImplementedError" in ret.comment:
+ pytest.skip("Current OpenSSL does not support 'ec' algorithm")
assert ret.changes
assert Path(ret.name).is_symlink() == follow
@@ -2722,7 +2743,12 @@ def _get_cert(cert, encoding="pem", passphrase=None):
def _belongs_to(cert_or_pubkey, privkey):
if isinstance(cert_or_pubkey, cx509.Certificate):
cert_or_pubkey = cert_or_pubkey.public_key()
- return x509util.is_pair(cert_or_pubkey, x509util.load_privkey(privkey))
+ try:
+ return x509util.is_pair(cert_or_pubkey, x509util.load_privkey(privkey))
+ except NotImplementedError:
+ pytest.skip(
+ "This OpenSSL version does not support current cryptographic algorithm"
+ )
def _signed_by(cert, privkey):
diff --git a/tests/pytests/scenarios/performance/test_performance.py b/tests/pytests/scenarios/performance/test_performance.py
index 85b92ed986..6319e26ce1 100644
--- a/tests/pytests/scenarios/performance/test_performance.py
+++ b/tests/pytests/scenarios/performance/test_performance.py
@@ -10,7 +10,13 @@ from saltfactories.utils import random_string
from salt.version import SaltVersionsInfo, __version__
-pytestmark = [pytest.mark.skip_if_binaries_missing("docker")]
+pytestmark = [
+ pytest.mark.skip_if_binaries_missing("docker"),
+ pytest.mark.skipif(
+ os.environ.get("GITHUB_ACTIONS", "") == "true",
+ reason="Cannot spawn containers in GH actions run",
+ ),
+]
class ContainerMaster(SaltDaemon, master.SaltMaster):
--
2.46.1

View File

@ -0,0 +1,98 @@
From 4e226426d0897f2d9dc64891ced78487b181d40e Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Fri, 30 Aug 2024 14:33:51 +0200
Subject: [PATCH] Improve error handling with different OpenSSL
versions
* Make error checking of x509 more flexible
for most recent cryptography and openSSL versions
* Add test for different exception value on loading private key
* Add fix for test_privkey_new_with_prereq on old OpenSSL
---
salt/utils/x509.py | 3 +-
.../pytests/functional/states/test_x509_v2.py | 29 +++++++++++++++++++
.../integration/states/test_x509_v2.py | 7 +++++
3 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/salt/utils/x509.py b/salt/utils/x509.py
index 5b2ae15882..f9fdca64d9 100644
--- a/salt/utils/x509.py
+++ b/salt/utils/x509.py
@@ -695,7 +695,8 @@ def load_privkey(pk, passphrase=None, get_encoding=False):
return pk, "pem", None
return pk
except ValueError as err:
- if "Bad decrypt" in str(err):
+ str_err = str(err)
+ if "Bad decrypt" in str_err or "Could not deserialize key data" in str_err:
raise SaltInvocationError(
"Bad decrypt - is the password correct?"
) from err
diff --git a/tests/pytests/functional/states/test_x509_v2.py b/tests/pytests/functional/states/test_x509_v2.py
index 929be014cd..47a1c555f8 100644
--- a/tests/pytests/functional/states/test_x509_v2.py
+++ b/tests/pytests/functional/states/test_x509_v2.py
@@ -3,6 +3,8 @@ from pathlib import Path
import pytest
+from tests.support.mock import patch
+
try:
import cryptography
import cryptography.x509 as cx509
@@ -2826,3 +2828,30 @@ def _get_privkey(pk, encoding="pem", passphrase=None):
pk = base64.b64decode(pk)
return pkcs12.load_pkcs12(pk, passphrase).key
raise ValueError("Need correct encoding")
+
+
+@pytest.mark.usefixtures("existing_pk")
+@pytest.mark.parametrize("existing_pk", [{"passphrase": "password"}], indirect=True)
+def test_exceptions_on_calling_load_pem_private_key(x509, pk_args):
+ pk_args["passphrase"] = "hunter1"
+ pk_args["overwrite"] = True
+
+ with patch(
+ "cryptography.hazmat.primitives.serialization.load_pem_private_key",
+ side_effect=ValueError("Bad decrypt. Incorrect password?"),
+ ):
+ ret = x509.private_key_managed(**pk_args)
+ _assert_pk_basic(ret, "rsa", passphrase="hunter1")
+
+ with patch(
+ "cryptography.hazmat.primitives.serialization.load_pem_private_key",
+ side_effect=ValueError(
+ "Could not deserialize key data. The data may be in an incorrect format, "
+ "the provided password may be incorrect, "
+ "it may be encrypted with an unsupported algorithm, "
+ "or it may be an unsupported key type "
+ "(e.g. EC curves with explicit parameters)."
+ ),
+ ):
+ ret = x509.private_key_managed(**pk_args)
+ _assert_pk_basic(ret, "rsa", passphrase="hunter1")
diff --git a/tests/pytests/integration/states/test_x509_v2.py b/tests/pytests/integration/states/test_x509_v2.py
index 4f94341295..ad8d904c92 100644
--- a/tests/pytests/integration/states/test_x509_v2.py
+++ b/tests/pytests/integration/states/test_x509_v2.py
@@ -195,6 +195,13 @@ Certificate:
"""
with x509_salt_master.state_tree.base.temp_file("manage_cert.sls", state):
ret = x509_salt_call_cli.run("state.apply", "manage_cert")
+ if (
+ ret.returncode == 1
+ and "NotImplementedError: ECDSA keys with unnamed curves" in ret.stdout
+ ):
+ pytest.skip(
+ "The version of OpenSSL doesn't support ECDSA keys with unnamed curves"
+ )
assert ret.returncode == 0
assert ret.data[next(iter(ret.data))]["changes"]
assert (tmp_path / "priv.key").exists()
--
2.46.0

View File

@ -56,6 +56,8 @@ saltbundlepy-pycurl.deb$
saltbundlepy-dateutil.deb$
saltbundlepy-passlib.deb$
# Required for salt testsuite
saltbundlepy-pytest.deb$
saltbundlepy-attrs.deb$
@ -85,3 +87,5 @@ saltbundlepy-werkzeug.deb$
saltbundlepy-devel.deb$
# Include salt-test (test executor)
saltbundlepy-salt-test.deb$
saltbundlepy-pathspec.deb$
saltbundlepy-yamllint.deb$

View File

@ -64,6 +64,8 @@ saltbundlepy-pycurl.rpm$
saltbundlepy-dateutil.rpm$
saltbundlepy-passlib.rpm$
# Required for salt testsuite
saltbundlepy-pytest.rpm$
saltbundlepy-attrs.rpm$
@ -93,3 +95,5 @@ saltbundlepy-werkzeug.rpm$
saltbundlepy-devel.rpm$
# Include salt-test (test executor)
saltbundlepy-salt-test.rpm$
saltbundlepy-pathspec.rpm$
saltbundlepy-yamllint.rpm$

View File

@ -0,0 +1,105 @@
From 94973ee85d766d7e98d02d89f4c81e59b36cb716 Mon Sep 17 00:00:00 2001
From: Marek Czernek <marek.czernek@suse.com>
Date: Thu, 29 Aug 2024 10:01:12 +0200
Subject: [PATCH] Join masters if it is a list (#671)
Co-authored-by: Twangboy <shane.d.lee@gmail.com>
---
changelog/64170.fixed.md | 2 +
salt/utils/cloud.py | 10 +++++
tests/pytests/unit/utils/test_cloud.py | 52 ++++++++++++++++++++++++++
3 files changed, 64 insertions(+)
create mode 100644 changelog/64170.fixed.md
diff --git a/changelog/64170.fixed.md b/changelog/64170.fixed.md
new file mode 100644
index 0000000000..1d20355bf1
--- /dev/null
+++ b/changelog/64170.fixed.md
@@ -0,0 +1,2 @@
+Fixed issue in salt-cloud so that multiple masters specified in the cloud
+are written to the minion config properly
diff --git a/salt/utils/cloud.py b/salt/utils/cloud.py
index b7208dc4a6..a084313059 100644
--- a/salt/utils/cloud.py
+++ b/salt/utils/cloud.py
@@ -1202,6 +1202,16 @@ def wait_for_passwd(
time.sleep(trysleep)
+def _format_master_param(master):
+ """
+ If the master is a list, we need to convert it to a comma delimited string
+ Otherwise, we just return master
+ """
+ if isinstance(master, list):
+ return ",".join(master)
+ return master
+
+
def deploy_windows(
host,
port=445,
diff --git a/tests/pytests/unit/utils/test_cloud.py b/tests/pytests/unit/utils/test_cloud.py
index 550b63c974..db9d258d39 100644
--- a/tests/pytests/unit/utils/test_cloud.py
+++ b/tests/pytests/unit/utils/test_cloud.py
@@ -605,3 +605,55 @@ def test_deploy_script_ssh_timeout():
ssh_kwargs = root_cmd.call_args.kwargs
assert "ssh_timeout" in ssh_kwargs
assert ssh_kwargs["ssh_timeout"] == 34
+
+
+@pytest.mark.parametrize(
+ "master,expected",
+ [
+ (None, None),
+ ("single_master", "single_master"),
+ (["master1", "master2", "master3"], "master1,master2,master3"),
+ ],
+)
+def test__format_master_param(master, expected):
+ result = cloud._format_master_param(master)
+ assert result == expected
+
+
+@pytest.mark.skip_unless_on_windows(reason="Only applicable for Windows.")
+@pytest.mark.parametrize(
+ "master,expected",
+ [
+ (None, None),
+ ("single_master", "single_master"),
+ (["master1", "master2", "master3"], "master1,master2,master3"),
+ ],
+)
+def test_deploy_windows_master(master, expected):
+ """
+ Test deploy_windows with master parameter
+ """
+ mock_true = MagicMock(return_value=True)
+ mock_tuple = MagicMock(return_value=(0, 0, 0))
+ with patch("salt.utils.smb.get_conn", MagicMock()), patch(
+ "salt.utils.smb.mkdirs", MagicMock()
+ ), patch("salt.utils.smb.put_file", MagicMock()), patch(
+ "salt.utils.smb.delete_file", MagicMock()
+ ), patch(
+ "salt.utils.smb.delete_directory", MagicMock()
+ ), patch(
+ "time.sleep", MagicMock()
+ ), patch.object(
+ cloud, "wait_for_port", mock_true
+ ), patch.object(
+ cloud, "fire_event", MagicMock()
+ ), patch.object(
+ cloud, "wait_for_psexecsvc", mock_true
+ ), patch.object(
+ cloud, "run_psexec_command", mock_tuple
+ ) as mock:
+ cloud.deploy_windows(host="test", win_installer="install.exe", master=master)
+ expected_cmd = "c:\\salttemp\\install.exe"
+ expected_args = "/S /master={} /minion-name=None".format(expected)
+ assert mock.call_args_list[0].args[0] == expected_cmd
+ assert mock.call_args_list[0].args[1] == expected_args
--
2.44.0

View File

@ -0,0 +1,883 @@
From 25c3df7713bd2a19a0980358fa72c1c48a08a1f4 Mon Sep 17 00:00:00 2001
From: Marek Czernek <marek.czernek@suse.com>
Date: Wed, 7 Aug 2024 10:28:07 +0200
Subject: [PATCH] Make tests compatible with venv bundle
Co-authored-by: cmcmarrow <charles.mcmarrow.4@gmail.com>
---
tests/pytests/functional/modules/test_sdb.py | 1 +
tests/pytests/functional/modules/test_yaml.py | 2 +-
.../rthooks/test_salt_utils_vt_terminal.py | 22 +++++--
.../pyinstaller/rthooks/test_subprocess.py | 22 +++++--
.../utils/yamllint/test_yamllint.py | 2 +-
tests/pytests/unit/modules/test_pip.py | 63 +++++++++++++------
.../unit/modules/test_transactional_update.py | 13 ++--
tests/pytests/unit/states/test_pkgrepo.py | 3 +-
tests/pytests/unit/test_fileserver.py | 8 +--
tests/pytests/unit/utils/test_gitfs.py | 18 ++++++
tests/pytests/unit/utils/test_msgpack.py | 2 +-
tests/pytests/unit/utils/test_pycrypto.py | 25 ++++----
tests/unit/test_config.py | 20 +++++-
tests/unit/utils/test_sdb.py | 2 +-
tests/unit/utils/test_templates.py | 34 ++++++++++
15 files changed, 177 insertions(+), 60 deletions(-)
diff --git a/tests/pytests/functional/modules/test_sdb.py b/tests/pytests/functional/modules/test_sdb.py
index 5519bf8ab57..837e7515d30 100644
--- a/tests/pytests/functional/modules/test_sdb.py
+++ b/tests/pytests/functional/modules/test_sdb.py
@@ -16,6 +16,7 @@ def minion_config_overrides():
}
+@pytest.mark.skip("Great module migration")
@pytest.mark.parametrize(
"expected_value",
(
diff --git a/tests/pytests/functional/modules/test_yaml.py b/tests/pytests/functional/modules/test_yaml.py
index 2a8fbc113ff..9aad0dfdc8c 100644
--- a/tests/pytests/functional/modules/test_yaml.py
+++ b/tests/pytests/functional/modules/test_yaml.py
@@ -13,7 +13,7 @@ try:
import salt.modules.yaml
import salt.utils.yamllint
- YAMLLINT_AVAILABLE = True
+ YAMLLINT_AVAILABLE = salt.utils.yamllint.has_yamllint()
except ImportError:
YAMLLINT_AVAILABLE = False
diff --git a/tests/pytests/functional/utils/pyinstaller/rthooks/test_salt_utils_vt_terminal.py b/tests/pytests/functional/utils/pyinstaller/rthooks/test_salt_utils_vt_terminal.py
index c45b5730a8e..ea687c0776d 100644
--- a/tests/pytests/functional/utils/pyinstaller/rthooks/test_salt_utils_vt_terminal.py
+++ b/tests/pytests/functional/utils/pyinstaller/rthooks/test_salt_utils_vt_terminal.py
@@ -8,6 +8,9 @@ import salt.utils.pyinstaller.rthooks._overrides as overrides
from tests.support import mock
from tests.support.helpers import PatchedEnviron
+LD_LIBRARY_PATH = ""
+if os.environ.get('VIRTUAL_ENV'):
+ LD_LIBRARY_PATH = f"{os.environ.get('VIRTUAL_ENV')}/lib"
@pytest.fixture(params=("LD_LIBRARY_PATH", "LIBPATH"))
def envvar(request):
@@ -17,9 +20,14 @@ def envvar(request):
@pytest.fixture
def meipass(envvar):
with mock.patch("salt.utils.pyinstaller.rthooks._overrides.sys") as patched_sys:
- patched_sys._MEIPASS = "{}_VALUE".format(envvar)
- assert overrides.sys._MEIPASS == "{}_VALUE".format(envvar)
- yield "{}_VALUE".format(envvar)
+ ld_path_mock_val = f"{envvar}_VALUE"
+ if envvar == "LD_LIBRARY_PATH" and LD_LIBRARY_PATH:
+ # venv-minion python wrapper hardcodes LD_LIB_PATH that
+ # we cannot overwrite from the testsuite
+ ld_path_mock_val = LD_LIBRARY_PATH
+ patched_sys._MEIPASS = ld_path_mock_val
+ assert overrides.sys._MEIPASS == ld_path_mock_val
+ yield ld_path_mock_val
assert not hasattr(sys, "_MEIPASS")
assert not hasattr(overrides.sys, "_MEIPASS")
@@ -111,7 +119,8 @@ def test_vt_terminal_environ_cleanup(envvar, meipass):
returned_env = json.loads(buffer_o)
assert returned_env != original_env
assert envvar in returned_env
- assert returned_env[envvar] == ""
+ envvar_value = LD_LIBRARY_PATH if envvar == "LD_LIBRARY_PATH" else ""
+ assert returned_env[envvar] == envvar_value
def test_vt_terminal_environ_cleanup_passed_directly_not_removed(envvar, meipass):
@@ -139,4 +148,7 @@ def test_vt_terminal_environ_cleanup_passed_directly_not_removed(envvar, meipass
returned_env = json.loads(buffer_o)
assert returned_env != original_env
assert envvar in returned_env
- assert returned_env[envvar] == envvar
+ envvar_val = envvar
+ if LD_LIBRARY_PATH and envvar == "LD_LIBRARY_PATH":
+ envvar_val = LD_LIBRARY_PATH
+ assert returned_env[envvar] == envvar_val
diff --git a/tests/pytests/functional/utils/pyinstaller/rthooks/test_subprocess.py b/tests/pytests/functional/utils/pyinstaller/rthooks/test_subprocess.py
index 836e392d016..e4b5420d5e3 100644
--- a/tests/pytests/functional/utils/pyinstaller/rthooks/test_subprocess.py
+++ b/tests/pytests/functional/utils/pyinstaller/rthooks/test_subprocess.py
@@ -9,6 +9,9 @@ import salt.utils.pyinstaller.rthooks._overrides as overrides
from tests.support import mock
from tests.support.helpers import PatchedEnviron
+LD_LIBRARY_PATH = ""
+if os.environ.get('VIRTUAL_ENV'):
+ LD_LIBRARY_PATH = f"{os.environ.get('VIRTUAL_ENV')}/lib"
@pytest.fixture(params=("LD_LIBRARY_PATH", "LIBPATH"))
def envvar(request):
@@ -18,9 +21,14 @@ def envvar(request):
@pytest.fixture
def meipass(envvar):
with mock.patch("salt.utils.pyinstaller.rthooks._overrides.sys") as patched_sys:
- patched_sys._MEIPASS = "{}_VALUE".format(envvar)
- assert overrides.sys._MEIPASS == "{}_VALUE".format(envvar)
- yield "{}_VALUE".format(envvar)
+ ld_path_mock_val = f"{envvar}_VALUE"
+ if envvar == "LD_LIBRARY_PATH" and LD_LIBRARY_PATH:
+ # venv-minion python wrapper hardcodes LD_LIB_PATH that
+ # we cannot overwrite from the testsuite
+ ld_path_mock_val = LD_LIBRARY_PATH
+ patched_sys._MEIPASS = ld_path_mock_val
+ assert overrides.sys._MEIPASS == ld_path_mock_val
+ yield ld_path_mock_val
assert not hasattr(sys, "_MEIPASS")
assert not hasattr(overrides.sys, "_MEIPASS")
@@ -88,7 +96,8 @@ def test_subprocess_popen_environ_cleanup(envvar, meipass):
returned_env = json.loads(stdout)
assert returned_env != original_env
assert envvar in returned_env
- assert returned_env[envvar] == ""
+ envvar_value = LD_LIBRARY_PATH if envvar == "LD_LIBRARY_PATH" else ""
+ assert returned_env[envvar] == envvar_value
def test_subprocess_popen_environ_cleanup_passed_directly_not_removed(envvar, meipass):
@@ -108,4 +117,7 @@ def test_subprocess_popen_environ_cleanup_passed_directly_not_removed(envvar, me
returned_env = json.loads(stdout)
assert returned_env != original_env
assert envvar in returned_env
- assert returned_env[envvar] == envvar
+ envvar_val = envvar
+ if LD_LIBRARY_PATH and envvar == "LD_LIBRARY_PATH":
+ envvar_val = LD_LIBRARY_PATH
+ assert returned_env[envvar] == envvar_val
diff --git a/tests/pytests/functional/utils/yamllint/test_yamllint.py b/tests/pytests/functional/utils/yamllint/test_yamllint.py
index 403c6fc610e..3c730523c4d 100644
--- a/tests/pytests/functional/utils/yamllint/test_yamllint.py
+++ b/tests/pytests/functional/utils/yamllint/test_yamllint.py
@@ -7,7 +7,7 @@ import salt.utils.versions as versions
try:
import salt.utils.yamllint as yamllint
- YAMLLINT_AVAILABLE = True
+ YAMLLINT_AVAILABLE = yamllint.has_yamllint()
except ImportError:
YAMLLINT_AVAILABLE = False
diff --git a/tests/pytests/unit/modules/test_pip.py b/tests/pytests/unit/modules/test_pip.py
index 4b2da77786b..fbe0dc5f1cf 100644
--- a/tests/pytests/unit/modules/test_pip.py
+++ b/tests/pytests/unit/modules/test_pip.py
@@ -15,6 +15,10 @@ MISSING_SETUP_PY_FILE = not os.path.exists(
os.path.join(RUNTIME_VARS.CODE_DIR, "setup.py")
)
+TARGET = []
+if os.environ.get('VENV_PIP_TARGET'):
+ TARGET = ["--target", os.environ.get('VENV_PIP_TARGET')]
+
class FakeFopen:
def __init__(self, filename):
@@ -102,6 +106,7 @@ def test_install_frozen_app(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
pkg,
]
mock.assert_called_with(
@@ -123,6 +128,7 @@ def test_install_source_app(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
pkg,
]
mock.assert_called_with(
@@ -143,6 +149,7 @@ def test_fix4361(python_binary):
"install",
"--requirement",
"requirements.txt",
+ *TARGET,
]
mock.assert_called_with(
expected_cmd,
@@ -169,7 +176,7 @@ def test_install_multiple_editable(python_binary):
"git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting",
]
- expected = [*python_binary, "install"]
+ expected = [*python_binary, "install", *TARGET]
for item in editables:
expected.extend(["--editable", item])
@@ -205,7 +212,7 @@ def test_install_multiple_pkgs_and_editables(python_binary):
"git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting",
]
- expected = [*python_binary, "install"]
+ expected = [*python_binary, "install", *TARGET]
expected.extend(pkgs)
for item in editables:
expected.extend(["--editable", item])
@@ -241,6 +248,7 @@ def test_install_multiple_pkgs_and_editables(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
pkgs[0],
"--editable",
editables[0],
@@ -268,7 +276,7 @@ def test_issue5940_install_multiple_pip_mirrors(python_binary):
expected = [*python_binary, "install", "--use-mirrors"]
for item in mirrors:
expected.extend(["--mirrors", item])
- expected.append("pep8")
+ expected = [*expected, *TARGET, "pep8"]
# Passing mirrors as a list
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
@@ -300,6 +308,7 @@ def test_issue5940_install_multiple_pip_mirrors(python_binary):
"--use-mirrors",
"--mirrors",
mirrors[0],
+ *TARGET,
"pep8",
]
@@ -327,7 +336,7 @@ def test_install_with_multiple_find_links(python_binary):
expected = [*python_binary, "install"]
for item in find_links:
expected.extend(["--find-links", item])
- expected.append(pkg)
+ expected = [*expected, *TARGET, pkg]
# Passing mirrors as a list
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
@@ -370,6 +379,7 @@ def test_install_with_multiple_find_links(python_binary):
"install",
"--find-links",
find_links[0],
+ *TARGET,
pkg,
]
@@ -435,6 +445,7 @@ def test_install_cached_requirements_used(python_binary):
"install",
"--requirement",
"my_cached_reqs",
+ *TARGET,
]
mock.assert_called_with(
expected,
@@ -491,6 +502,7 @@ def test_install_log_argument_in_resulting_command(python_binary):
"install",
"--log",
log_path,
+ *TARGET,
pkg,
]
mock.assert_called_with(
@@ -521,7 +533,7 @@ def test_install_timeout_argument_in_resulting_command(python_binary):
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, timeout=10)
mock.assert_called_with(
- expected + [10, pkg],
+ expected + [10, *TARGET, pkg],
saltenv="base",
runas=None,
use_vt=False,
@@ -533,7 +545,7 @@ def test_install_timeout_argument_in_resulting_command(python_binary):
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, timeout="10")
mock.assert_called_with(
- expected + ["10", pkg],
+ expected + ["10", *TARGET, pkg],
saltenv="base",
runas=None,
use_vt=False,
@@ -557,6 +569,7 @@ def test_install_index_url_argument_in_resulting_command(python_binary):
"install",
"--index-url",
index_url,
+ *TARGET,
pkg,
]
mock.assert_called_with(
@@ -579,6 +592,7 @@ def test_install_extra_index_url_argument_in_resulting_command(python_binary):
"install",
"--extra-index-url",
extra_index_url,
+ *TARGET,
pkg,
]
mock.assert_called_with(
@@ -595,7 +609,7 @@ def test_install_no_index_argument_in_resulting_command(python_binary):
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, no_index=True)
- expected = [*python_binary, "install", "--no-index", pkg]
+ expected = [*python_binary, "install", "--no-index", *TARGET, pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -611,7 +625,7 @@ def test_install_build_argument_in_resulting_command(python_binary):
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, build=build)
- expected = [*python_binary, "install", "--build", build, pkg]
+ expected = [*python_binary, "install", "--build", build, *TARGET, pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -646,6 +660,7 @@ def test_install_download_argument_in_resulting_command(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
"--download",
download,
pkg,
@@ -664,7 +679,7 @@ def test_install_no_download_argument_in_resulting_command(python_binary):
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, no_download=True)
- expected = [*python_binary, "install", "--no-download", pkg]
+ expected = [*python_binary, "install", *TARGET, "--no-download", pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -691,6 +706,7 @@ def test_install_download_cache_dir_arguments_in_resulting_command(python_binary
expected = [
*python_binary,
"install",
+ *TARGET,
cmd_arg,
download_cache,
pkg,
@@ -720,7 +736,7 @@ def test_install_source_argument_in_resulting_command(python_binary):
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, source=source)
- expected = [*python_binary, "install", "--source", source, pkg]
+ expected = [*python_binary, "install", *TARGET, "--source", source, pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -739,6 +755,7 @@ def test_install_exists_action_argument_in_resulting_command(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
"--exists-action",
action,
pkg,
@@ -761,7 +778,7 @@ def test_install_install_options_argument_in_resulting_command(python_binary):
install_options = ["--exec-prefix=/foo/bar", "--install-scripts=/foo/bar/bin"]
pkg = "pep8"
- expected = [*python_binary, "install"]
+ expected = [*python_binary, "install", *TARGET]
for item in install_options:
expected.extend(["--install-option", item])
expected.append(pkg)
@@ -797,6 +814,7 @@ def test_install_install_options_argument_in_resulting_command(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
"--install-option",
install_options[0],
pkg,
@@ -814,7 +832,7 @@ def test_install_global_options_argument_in_resulting_command(python_binary):
global_options = ["--quiet", "--no-user-cfg"]
pkg = "pep8"
- expected = [*python_binary, "install"]
+ expected = [*python_binary, "install", *TARGET]
for item in global_options:
expected.extend(["--global-option", item])
expected.append(pkg)
@@ -850,6 +868,7 @@ def test_install_global_options_argument_in_resulting_command(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
"--global-option",
global_options[0],
pkg,
@@ -868,7 +887,7 @@ def test_install_upgrade_argument_in_resulting_command(python_binary):
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, upgrade=True)
- expected = [*python_binary, "install", "--upgrade", pkg]
+ expected = [*python_binary, "install", *TARGET, "--upgrade", pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -886,6 +905,7 @@ def test_install_force_reinstall_argument_in_resulting_command(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
"--force-reinstall",
pkg,
]
@@ -906,6 +926,7 @@ def test_install_ignore_installed_argument_in_resulting_command(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
"--ignore-installed",
pkg,
]
@@ -923,7 +944,7 @@ def test_install_no_deps_argument_in_resulting_command(python_binary):
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, no_deps=True)
- expected = [*python_binary, "install", "--no-deps", pkg]
+ expected = [*python_binary, "install", *TARGET, "--no-deps", pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -938,7 +959,7 @@ def test_install_no_install_argument_in_resulting_command(python_binary):
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, no_install=True)
- expected = [*python_binary, "install", "--no-install", pkg]
+ expected = [*python_binary, "install", *TARGET, "--no-install", pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -954,7 +975,7 @@ def test_install_proxy_argument_in_resulting_command(python_binary):
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
pip.install(pkg, proxy=proxy)
- expected = [*python_binary, "install", "--proxy", proxy, pkg]
+ expected = [*python_binary, "install", "--proxy", proxy, *TARGET, pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -981,7 +1002,7 @@ def test_install_proxy_false_argument_in_resulting_command(python_binary):
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
with patch.dict(pip.__opts__, config_mock):
pip.install(pkg, proxy=proxy)
- expected = [*python_binary, "install", pkg]
+ expected = [*python_binary, "install", *TARGET, pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -1012,6 +1033,7 @@ def test_install_global_proxy_in_resulting_command(python_binary):
"install",
"--proxy",
proxy,
+ *TARGET,
pkg,
]
mock.assert_called_with(
@@ -1032,6 +1054,7 @@ def test_install_multiple_requirements_arguments_in_resulting_command(python_bin
expected = [*python_binary, "install"]
for item in cached_reqs:
expected.extend(["--requirement", item])
+ expected.extend(TARGET)
# Passing option as a list
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
@@ -1068,6 +1091,7 @@ def test_install_multiple_requirements_arguments_in_resulting_command(python_bin
"install",
"--requirement",
cached_reqs[0],
+ *TARGET,
]
mock.assert_called_with(
expected,
@@ -1088,6 +1112,7 @@ def test_install_extra_args_arguments_in_resulting_command(python_binary):
expected = [
*python_binary,
"install",
+ *TARGET,
pkg,
"--latest-pip-kwarg",
"param",
@@ -1604,7 +1629,7 @@ def test_install_pre_argument_in_resulting_command(python_binary):
with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
with patch("salt.modules.pip.version", MagicMock(return_value="1.3")):
pip.install(pkg, pre_releases=True)
- expected = [*python_binary, "install", pkg]
+ expected = [*python_binary, "install", *TARGET, pkg]
mock.assert_called_with(
expected,
saltenv="base",
@@ -1620,7 +1645,7 @@ def test_install_pre_argument_in_resulting_command(python_binary):
):
with patch("salt.modules.pip._get_pip_bin", MagicMock(return_value=["pip"])):
pip.install(pkg, pre_releases=True)
- expected = ["pip", "install", "--pre", pkg]
+ expected = ["pip", "install", *TARGET, "--pre", pkg]
mock_run_all.assert_called_with(
expected,
saltenv="base",
diff --git a/tests/pytests/unit/modules/test_transactional_update.py b/tests/pytests/unit/modules/test_transactional_update.py
index dbd72fd74bf..e0ef2abd0f3 100644
--- a/tests/pytests/unit/modules/test_transactional_update.py
+++ b/tests/pytests/unit/modules/test_transactional_update.py
@@ -1,3 +1,4 @@
+import os
import pytest
import salt.loader.context
@@ -10,6 +11,10 @@ pytestmark = [
pytest.mark.skip_on_windows(reason="Not supported on Windows"),
]
+SALT_CALL_BINARY = "salt-call"
+if os.environ.get('VIRTUAL_ENV'):
+ SALT_CALL_BINARY = f"{os.environ.get('VIRTUAL_ENV')}/bin/salt-call"
+
@pytest.fixture
def configure_loader_modules():
@@ -379,7 +384,7 @@ def test_call_fails_function():
"--continue",
"--quiet",
"run",
- "salt-call",
+ SALT_CALL_BINARY,
"--out",
"json",
"-l",
@@ -411,7 +416,7 @@ def test_call_success_no_reboot():
"--continue",
"--quiet",
"run",
- "salt-call",
+ SALT_CALL_BINARY,
"--out",
"json",
"-l",
@@ -454,7 +459,7 @@ def test_call_success_reboot():
"--continue",
"--quiet",
"run",
- "salt-call",
+ SALT_CALL_BINARY,
"--out",
"json",
"-l",
@@ -488,7 +493,7 @@ def test_call_success_parameters():
"--continue",
"--quiet",
"run",
- "salt-call",
+ SALT_CALL_BINARY,
"--out",
"json",
"-l",
diff --git a/tests/pytests/unit/states/test_pkgrepo.py b/tests/pytests/unit/states/test_pkgrepo.py
index 5f540bd2454..14d17ad3f9f 100644
--- a/tests/pytests/unit/states/test_pkgrepo.py
+++ b/tests/pytests/unit/states/test_pkgrepo.py
@@ -1,7 +1,6 @@
"""
:codeauthor: Tyler Johnson <tjohnson@saltstack.com>
"""
-
import pytest
import salt.states.pkgrepo as pkgrepo
@@ -390,7 +389,7 @@ def test_migrated_wrong_method():
with patch.dict(pkgrepo.__grains__, grains), patch.dict(
pkgrepo.__salt__, salt_mock
):
- assert pkgrepo.migrated("/mnt", method_="magic") == {
+ assert pkgrepo.migrated("/mnt", method="magic") == {
"name": "/mnt",
"result": False,
"changes": {},
diff --git a/tests/pytests/unit/test_fileserver.py b/tests/pytests/unit/test_fileserver.py
index 8dd3ea0a27d..49be3967dc4 100644
--- a/tests/pytests/unit/test_fileserver.py
+++ b/tests/pytests/unit/test_fileserver.py
@@ -75,9 +75,7 @@ def test_file_server_url_escape(tmp_path):
opts = {
"fileserver_backend": ["roots"],
"extension_modules": "",
- "optimization_order": [
- 0,
- ],
+ "optimization_order": [0, 1],
"file_roots": {
"base": [fileroot],
},
@@ -102,9 +100,7 @@ def test_file_server_serve_url_escape(tmp_path):
opts = {
"fileserver_backend": ["roots"],
"extension_modules": "",
- "optimization_order": [
- 0,
- ],
+ "optimization_order": [0, 1],
"file_roots": {
"base": [fileroot],
},
diff --git a/tests/pytests/unit/utils/test_gitfs.py b/tests/pytests/unit/utils/test_gitfs.py
index 2bf627049f9..bd7d74cb2b2 100644
--- a/tests/pytests/unit/utils/test_gitfs.py
+++ b/tests/pytests/unit/utils/test_gitfs.py
@@ -3,6 +3,7 @@ import time
import pytest
+import salt.config
import salt.fileserver.gitfs
import salt.utils.gitfs
from salt.exceptions import FileserverConfigError
@@ -24,6 +25,23 @@ if HAS_PYGIT2:
import pygit2
+@pytest.fixture
+def minion_opts(tmp_path):
+ """
+ Default minion configuration with relative temporary paths to not require root permissions.
+ """
+ root_dir = tmp_path / "minion"
+ opts = salt.config.DEFAULT_MINION_OPTS.copy()
+ opts["__role"] = "minion"
+ opts["root_dir"] = str(root_dir)
+ for name in ("cachedir", "pki_dir", "sock_dir", "conf_dir"):
+ dirpath = root_dir / name
+ dirpath.mkdir(parents=True)
+ opts[name] = str(dirpath)
+ opts["log_file"] = "logs/minion.log"
+ return opts
+
+
@pytest.mark.parametrize(
"role_name,role_class",
(
diff --git a/tests/pytests/unit/utils/test_msgpack.py b/tests/pytests/unit/utils/test_msgpack.py
index a09b6e5b8b1..3d0b9d7fc8c 100644
--- a/tests/pytests/unit/utils/test_msgpack.py
+++ b/tests/pytests/unit/utils/test_msgpack.py
@@ -3,7 +3,7 @@ import pytest
import salt.utils.msgpack
from tests.support.mock import MagicMock, patch
-
+@pytest.mark.skipif(salt.utils.msgpack.version < (1, 0, 0), reason="Test requires msgpack version >= 1.0.0")
def test_load_encoding(tmp_path):
"""
test when using msgpack version >= 1.0.0 we
diff --git a/tests/pytests/unit/utils/test_pycrypto.py b/tests/pytests/unit/utils/test_pycrypto.py
index 693ad10e240..9e0b58d1b35 100644
--- a/tests/pytests/unit/utils/test_pycrypto.py
+++ b/tests/pytests/unit/utils/test_pycrypto.py
@@ -57,21 +57,20 @@ def test_gen_hash_crypt(algorithm, expected):
"""
Test gen_hash with crypt library
"""
- with patch("salt.utils.pycrypto.methods", {}):
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=expected["salt"], password=passwd, algorithm=algorithm
- )
- assert ret == expected["hashed"]
+ ret = salt.utils.pycrypto.gen_hash(
+ crypt_salt=expected["salt"], password=passwd, algorithm=algorithm
+ )
+ assert ret == expected["hashed"]
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=expected["badsalt"], password=passwd, algorithm=algorithm
- )
- assert ret != expected["hashed"]
+ ret = salt.utils.pycrypto.gen_hash(
+ crypt_salt=expected["badsalt"], password=passwd, algorithm=algorithm
+ )
+ assert ret != expected["hashed"]
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=None, password=passwd, algorithm=algorithm
- )
- assert ret != expected["hashed"]
+ ret = salt.utils.pycrypto.gen_hash(
+ crypt_salt=None, password=passwd, algorithm=algorithm
+ )
+ assert ret != expected["hashed"]
@pytest.mark.skipif(not salt.utils.pycrypto.HAS_CRYPT, reason="crypt not available")
diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py
index 5cc58c273d0..6995b01c892 100644
--- a/tests/unit/test_config.py
+++ b/tests/unit/test_config.py
@@ -83,9 +83,12 @@ class SampleConfTest(DefaultConfigsBase, TestCase):
"""
master_config = SAMPLE_CONF_DIR + "master"
ret = salt.config._read_conf_file(master_config)
+ # openSUSE modified the default config in
+ # https://github.com/opensuse/salt/commit/6ffbf7fcc178f32c670b177b25ed64658c59f1bf
+ expected_config = {"user": "salt", "syndic_user": "salt"}
self.assertEqual(
ret,
- {},
+ expected_config,
"Sample config file '{}' must be commented out.".format(master_config),
)
@@ -347,7 +350,10 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
with patched_environ(SALT_MINION_CONFIG=env_fpath):
# Should load from env variable, not the default configuration file
- config = salt.config.minion_config("{}/minion".format(CONFIG_DIR))
+ # Override defaults from venv-minion conf
+ defaults = salt.config.DEFAULT_MINION_OPTS.copy()
+ defaults["default_include"] = ""
+ config = salt.config.minion_config("{}/minion".format(CONFIG_DIR), defaults=defaults)
self.assertEqual(config["log_file"], env_fpath)
root_dir = os.path.join(tempdir, "foo", "bar")
@@ -1946,6 +1952,11 @@ class APIConfigTestCase(DefaultConfigsBase, TestCase):
if salt.utils.platform.is_windows():
expected = "{}\\var\\log\\salt\\api".format(RUNTIME_VARS.TMP_ROOT_DIR)
+ if os.environ.get("VIRTUAL_ENV"):
+ # venv bundle configures --salt-logs-dir=%{_localstatedir}/log
+ # in the RPM spec file
+ expected = expected.replace("/salt/api", "/api")
+
ret = salt.config.api_config("/some/fake/path")
self.assertEqual(ret["log_file"], expected)
@@ -2017,6 +2028,11 @@ class APIConfigTestCase(DefaultConfigsBase, TestCase):
mock_pid = "c:\\mock\\root\\var\\run\\salt-api.pid"
mock_master_config["root_dir"] = "c:\\mock\\root"
+ if os.environ.get("VIRTUAL_ENV"):
+ # venv bundle configures --salt-logs-dir=%{_localstatedir}/log
+ # in the RPM spec file
+ mock_log = mock_log.replace("/salt", "")
+
with patch(
"salt.config.client_config", MagicMock(return_value=mock_master_config)
):
diff --git a/tests/unit/utils/test_sdb.py b/tests/unit/utils/test_sdb.py
index 87886cbc521..69cbda07beb 100644
--- a/tests/unit/utils/test_sdb.py
+++ b/tests/unit/utils/test_sdb.py
@@ -49,7 +49,7 @@ class SdbTestCase(TestCase, LoaderModuleMockMixin):
# test with SQLite database write and read
def test_sqlite_get_found(self):
- expected = {b"name": b"testone", b"number": 46}
+ expected = {"name": "testone", "number": 46}
sdb.sdb_set("sdb://test_sdb_data/test1", expected, self.sdb_opts)
resp = sdb.sdb_get("sdb://test_sdb_data/test1", self.sdb_opts)
self.assertEqual(resp, expected)
diff --git a/tests/unit/utils/test_templates.py b/tests/unit/utils/test_templates.py
index 264b4ae801d..604395f5e08 100644
--- a/tests/unit/utils/test_templates.py
+++ b/tests/unit/utils/test_templates.py
@@ -1,6 +1,7 @@
"""
Unit tests for salt.utils.templates.py
"""
+
import logging
import os
import sys
@@ -22,6 +23,20 @@ try:
except ImportError:
HAS_CHEETAH = False
+try:
+ import genshi as _
+
+ HAS_GENSHI = True
+except ImportError:
+ HAS_GENSHI = False
+
+try:
+ import mako as _
+
+ HAS_MAKO = True
+except ImportError:
+ HAS_MAKO = False
+
log = logging.getLogger(__name__)
@@ -83,16 +98,19 @@ class RenderTestCase(TestCase):
assert res == expected
### Tests for mako template
+ @pytest.mark.skipif(not HAS_MAKO, reason="Mako module not available for testing")
def test_render_mako_sanity(self):
tmpl = """OK"""
res = salt.utils.templates.render_mako_tmpl(tmpl, dict(self.context))
self.assertEqual(res, "OK")
+ @pytest.mark.skipif(not HAS_MAKO, reason="Mako module not available for testing")
def test_render_mako_evaluate(self):
tmpl = """${ "OK" }"""
res = salt.utils.templates.render_mako_tmpl(tmpl, dict(self.context))
self.assertEqual(res, "OK")
+ @pytest.mark.skipif(not HAS_MAKO, reason="Mako module not available for testing")
def test_render_mako_evaluate_multi(self):
tmpl = """
% if 1:
@@ -103,6 +121,7 @@ class RenderTestCase(TestCase):
stripped = res.strip()
self.assertEqual(stripped, "OK")
+ @pytest.mark.skipif(not HAS_MAKO, reason="Mako module not available for testing")
def test_render_mako_variable(self):
tmpl = """${ var }"""
@@ -152,21 +171,33 @@ class RenderTestCase(TestCase):
self.assertEqual(res, "OK")
### Tests for genshi template (xml-based)
+ @pytest.mark.skipif(
+ not HAS_GENSHI, reason="Genshi module not available for testing"
+ )
def test_render_genshi_sanity(self):
tmpl = """<RU>OK</RU>"""
res = salt.utils.templates.render_genshi_tmpl(tmpl, dict(self.context))
self.assertEqual(res, "<RU>OK</RU>")
+ @pytest.mark.skipif(
+ not HAS_GENSHI, reason="Genshi module not available for testing"
+ )
def test_render_genshi_evaluate(self):
tmpl = """<RU>${ "OK" }</RU>"""
res = salt.utils.templates.render_genshi_tmpl(tmpl, dict(self.context))
self.assertEqual(res, "<RU>OK</RU>")
+ @pytest.mark.skipif(
+ not HAS_GENSHI, reason="Genshi module not available for testing"
+ )
def test_render_genshi_evaluate_condition(self):
tmpl = """<RU xmlns:py="http://genshi.edgewall.org/" py:if="1">OK</RU>"""
res = salt.utils.templates.render_genshi_tmpl(tmpl, dict(self.context))
self.assertEqual(res, "<RU>OK</RU>")
+ @pytest.mark.skipif(
+ not HAS_GENSHI, reason="Genshi module not available for testing"
+ )
def test_render_genshi_variable(self):
tmpl = """<RU>$var</RU>"""
@@ -175,6 +206,9 @@ class RenderTestCase(TestCase):
res = salt.utils.templates.render_genshi_tmpl(tmpl, ctx)
self.assertEqual(res, "<RU>OK</RU>")
+ @pytest.mark.skipif(
+ not HAS_GENSHI, reason="Genshi module not available for testing"
+ )
def test_render_genshi_variable_replace(self):
tmpl = """<RU xmlns:py="http://genshi.edgewall.org/" py:content="var">not ok</RU>"""
--
2.46.0

13
post_start_cleanup.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/sh
if builtin type -P transactional-update &> /dev/null && [ "$TRANSACTIONAL_UPDATE" != "true" ]; then
# Do not clean previous environment on T-U systems when not in transaction
exit 0
fi
if [ -d "VENV_LOCATION_PLACEHOLDER/lib/prev_env" ]; then
rm -r "VENV_LOCATION_PLACEHOLDER/lib/prev_env" || :
fi
if [ -L "VENV_LOCATION_PLACEHOLDER/lib/PLACEHOLDER" ]; then
unlink "VENV_LOCATION_PLACEHOLDER/lib/PLACEHOLDER" || :
fi

View File

@ -0,0 +1,25 @@
From 936c298c177a50783b080c445745bedf77050cb0 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Wed, 25 Sep 2024 14:04:40 +0300
Subject: [PATCH] Prevent using SyncWrapper with no reason
---
salt/channel/server.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/salt/channel/server.py b/salt/channel/server.py
index b6d51fef08..f1b6f701a9 100644
--- a/salt/channel/server.py
+++ b/salt/channel/server.py
@@ -86,7 +86,7 @@ class ReqServerChannel:
# other things needed for _auth
# Create the event manager
self.event = salt.utils.event.get_master_event(
- self.opts, self.opts["sock_dir"], listen=False
+ self.opts, self.opts["sock_dir"], listen=False, io_loop=io_loop
)
self.auto_key = salt.daemons.masterapi.AutoKey(self.opts)
# only create a con_cache-client if the con_cache is active
--
2.46.1

View File

@ -0,0 +1,224 @@
From ff789d88541954e4fc1678dff728bc6a3ea7472e Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Fri, 30 Aug 2024 14:30:27 +0200
Subject: [PATCH] Remove redundant run_func from
salt.master.MWorker._handle_aes
* New request context
* Fix docs
* Remove redundant run_func from salt.master.MWorker._handle_aes
* Get rid of run_func in salt.Minion._target
---------
Co-authored-by: Daniel A. Wozniak <dwozniak@vmware.com>
---
doc/topics/releases/3007.0.rst | 0
salt/_logging/impl.py | 15 ++++++---
salt/master.py | 12 ++-----
salt/minion.py | 10 ++----
salt/utils/ctx.py | 60 +++++++++++-----------------------
5 files changed, 34 insertions(+), 63 deletions(-)
create mode 100644 doc/topics/releases/3007.0.rst
diff --git a/doc/topics/releases/3007.0.rst b/doc/topics/releases/3007.0.rst
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/salt/_logging/impl.py b/salt/_logging/impl.py
index 1d71cb8be8..4d1ebd2495 100644
--- a/salt/_logging/impl.py
+++ b/salt/_logging/impl.py
@@ -26,6 +26,8 @@ GARBAGE = logging.GARBAGE = 1
QUIET = logging.QUIET = 1000
import salt.defaults.exitcodes # isort:skip pylint: disable=unused-import
+import salt.utils.ctx
+
from salt._logging.handlers import DeferredStreamHandler # isort:skip
from salt._logging.handlers import RotatingFileHandler # isort:skip
from salt._logging.handlers import StreamHandler # isort:skip
@@ -33,7 +35,6 @@ from salt._logging.handlers import SysLogHandler # isort:skip
from salt._logging.handlers import WatchedFileHandler # isort:skip
from salt._logging.mixins import LoggingMixinMeta # isort:skip
from salt.exceptions import LoggingRuntimeError # isort:skip
-from salt.utils.ctx import RequestContext # isort:skip
from salt.utils.immutabletypes import freeze, ImmutableDict # isort:skip
from salt.utils.textformat import TextFormat # isort:skip
@@ -242,10 +243,14 @@ class SaltLoggingClass(LOGGING_LOGGER_CLASS, metaclass=LoggingMixinMeta):
if extra is None:
extra = {}
- # pylint: disable=no-member
- current_jid = RequestContext.current.get("data", {}).get("jid", None)
- log_fmt_jid = RequestContext.current.get("opts", {}).get("log_fmt_jid", None)
- # pylint: enable=no-member
+ current_jid = (
+ salt.utils.ctx.get_request_context().get("data", {}).get("jid", None)
+ )
+ log_fmt_jid = (
+ salt.utils.ctx.get_request_context()
+ .get("opts", {})
+ .get("log_fmt_jid", None)
+ )
if current_jid is not None:
extra["jid"] = current_jid
diff --git a/salt/master.py b/salt/master.py
index d7182d10b5..49cfb68860 100644
--- a/salt/master.py
+++ b/salt/master.py
@@ -38,6 +38,7 @@ import salt.state
import salt.utils.args
import salt.utils.atomicfile
import salt.utils.crypt
+import salt.utils.ctx
import salt.utils.event
import salt.utils.files
import salt.utils.gitfs
@@ -58,10 +59,8 @@ import salt.wheel
from salt.cli.batch_async import BatchAsync, batch_async_required
from salt.config import DEFAULT_INTERVAL
from salt.defaults import DEFAULT_TARGET_DELIM
-from salt.ext.tornado.stack_context import StackContext
from salt.transport import TRANSPORTS
from salt.utils.channel import iter_transport_opts
-from salt.utils.ctx import RequestContext
from salt.utils.debug import (
enable_sigusr1_handler,
enable_sigusr2_handler,
@@ -1108,13 +1107,8 @@ class MWorker(salt.utils.process.SignalHandlingProcess):
start = time.time()
self.stats[cmd]["runs"] += 1
- def run_func(data):
- return self.aes_funcs.run_func(data["cmd"], data)
-
- with StackContext(
- functools.partial(RequestContext, {"data": data, "opts": self.opts})
- ):
- ret = run_func(data)
+ with salt.utils.ctx.request_context({"data": data, "opts": self.opts}):
+ ret = self.aes_funcs.run_func(data["cmd"], data)
if self.opts["master_stats"]:
self._post_stats(start, cmd)
diff --git a/salt/minion.py b/salt/minion.py
index 2ccd0cd5a9..e21a017cfd 100644
--- a/salt/minion.py
+++ b/salt/minion.py
@@ -39,6 +39,7 @@ import salt.transport
import salt.utils.args
import salt.utils.context
import salt.utils.crypt
+import salt.utils.ctx
import salt.utils.data
import salt.utils.dictdiffer
import salt.utils.dictupdate
@@ -70,7 +71,6 @@ from salt.exceptions import (
SaltSystemExit,
)
from salt.template import SLS_ENCODING
-from salt.utils.ctx import RequestContext
from salt.utils.debug import enable_sigusr1_handler
from salt.utils.event import tagify
from salt.utils.network import parse_host_port
@@ -1805,18 +1805,12 @@ class Minion(MinionBase):
uid = salt.utils.user.get_uid(user=opts.get("user", None))
minion_instance.proc_dir = get_proc_dir(opts["cachedir"], uid=uid)
- def run_func(minion_instance, opts, data):
+ with salt.utils.ctx.request_context({"data": data, "opts": opts}):
if isinstance(data["fun"], tuple) or isinstance(data["fun"], list):
return Minion._thread_multi_return(minion_instance, opts, data)
else:
return Minion._thread_return(minion_instance, opts, data)
- with salt.ext.tornado.stack_context.StackContext(
- functools.partial(RequestContext, {"data": data, "opts": opts})
- ):
- with salt.ext.tornado.stack_context.StackContext(minion_instance.ctx):
- run_func(minion_instance, opts, data)
-
def _execute_job_function(
self, function_name, function_args, executors, opts, data
):
diff --git a/salt/utils/ctx.py b/salt/utils/ctx.py
index a9c0931bd8..2f4b5b4c9b 100644
--- a/salt/utils/ctx.py
+++ b/salt/utils/ctx.py
@@ -1,49 +1,27 @@
-import threading
+import contextlib
+try:
+ # Try the stdlib C extension first
+ import _contextvars as contextvars
+except ImportError:
+ # Py<3.7
+ import contextvars
-class ClassProperty(property):
- """
- Use a classmethod as a property
- http://stackoverflow.com/a/1383402/1258307
- """
+DEFAULT_CTX_VAR = "request_ctxvar"
+request_ctxvar = contextvars.ContextVar(DEFAULT_CTX_VAR)
- def __get__(self, cls, owner):
- return self.fget.__get__(None, owner)() # pylint: disable=no-member
-
-class RequestContext:
+@contextlib.contextmanager
+def request_context(data):
"""
- A context manager that saves some per-thread state globally.
- Intended for use with Tornado's StackContext.
- https://gist.github.com/simon-weber/7755289
- Simply import this class into any module and access the current request handler by this
- class's class method property 'current'. If it returns None, there's no active request.
- .. code:: python
- from raas.utils.ctx import RequestContext
- current_request_handler = RequestContext.current
+ A context manager that sets and un-sets the loader context
"""
+ tok = request_ctxvar.set(data)
+ try:
+ yield
+ finally:
+ request_ctxvar.reset(tok)
- _state = threading.local()
- _state.current_request = {}
-
- def __init__(self, current_request):
- self._current_request = current_request
-
- @ClassProperty
- @classmethod
- def current(cls):
- if not hasattr(cls._state, "current_request"):
- return {}
- return cls._state.current_request
-
- def __enter__(self):
- self._prev_request = self.__class__.current
- self.__class__._state.current_request = self._current_request
-
- def __exit__(self, *exc):
- self.__class__._state.current_request = self._prev_request
- del self._prev_request
- return False
- def __call__(self):
- return self
+def get_request_context():
+ return request_ctxvar.get({})
--
2.46.0

View File

@ -0,0 +1,122 @@
From 3f3c8d80427c9d90bea5fbca785b210260d33a0f Mon Sep 17 00:00:00 2001
From: Marek Czernek <marek.czernek@suse.com>
Date: Wed, 21 Aug 2024 16:15:02 +0200
Subject: [PATCH] Replace use of pygit2 deprecated and removed (1.15.0)
oid with id (#673)
Co-authored-by: David Murphy <damurphy@vmware.com>
---
salt/utils/gitfs.py | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py
index 061647edaca..f3902c1f19a 100644
--- a/salt/utils/gitfs.py
+++ b/salt/utils/gitfs.py
@@ -1683,7 +1683,7 @@ class Pygit2(GitProvider):
# remote ref.
self.repo.checkout(checkout_ref)
if branch:
- self.repo.reset(oid, pygit2.GIT_RESET_HARD)
+ self.repo.reset(pygit2_id, pygit2.GIT_RESET_HARD)
return True
except GitLockError as exc:
if exc.errno == errno.EEXIST:
@@ -1714,11 +1714,11 @@ class Pygit2(GitProvider):
tag_ref = "refs/tags/" + tgt_ref
if remote_ref in refs:
# Get commit id for the remote ref
- oid = self.peel(self.repo.lookup_reference(remote_ref)).id
+ pygit2_id = self.peel(self.repo.lookup_reference(remote_ref)).id
if local_ref not in refs:
# No local branch for this remote, so create one and point
# it at the commit id of the remote ref
- self.repo.create_reference(local_ref, oid)
+ self.repo.create_reference(local_ref, pygit2_id)
try:
target_sha = self.peel(self.repo.lookup_reference(remote_ref)).hex
@@ -1749,7 +1749,8 @@ class Pygit2(GitProvider):
# cachedir).
head_ref = local_head.target
# If head_ref is not a string, it will point to a
- # pygit2.Oid object and we are in detached HEAD mode.
+ # pygit2.id object (oid is deprecated and removed) and
+ # we are in detached HEAD mode.
# Therefore, there is no need to add a local reference. If
# head_ref == local_ref, then the local reference for HEAD
# in refs/heads/ already exists and again, no need to add.
@@ -1918,10 +1919,10 @@ class Pygit2(GitProvider):
the empty directories within it in the "blobs" list
"""
for entry in iter(tree):
- if entry.oid not in self.repo:
+ if entry.id not in self.repo:
# Entry is a submodule, skip it
continue
- blob = self.repo[entry.oid]
+ blob = self.repo[entry.id]
if not isinstance(blob, pygit2.Tree):
continue
blobs.append(
@@ -1940,8 +1941,8 @@ class Pygit2(GitProvider):
return ret
if self.root(tgt_env):
try:
- oid = tree[self.root(tgt_env)].oid
- tree = self.repo[oid]
+ pygit2_id = tree[self.root(tgt_env)].id
+ tree = self.repo[pygit2_id]
except KeyError:
return ret
if not isinstance(tree, pygit2.Tree):
@@ -2056,17 +2057,17 @@ class Pygit2(GitProvider):
the file paths and symlink info in the "blobs" dict
"""
for entry in iter(tree):
- if entry.oid not in self.repo:
+ if entry.id not in self.repo:
# Entry is a submodule, skip it
continue
- obj = self.repo[entry.oid]
+ obj = self.repo[entry.id]
if isinstance(obj, pygit2.Blob):
repo_path = salt.utils.path.join(
prefix, entry.name, use_posixpath=True
)
blobs.setdefault("files", []).append(repo_path)
if stat.S_ISLNK(tree[entry.name].filemode):
- link_tgt = self.repo[tree[entry.name].oid].data
+ link_tgt = self.repo[tree[entry.name].id].data
blobs.setdefault("symlinks", {})[repo_path] = link_tgt
elif isinstance(obj, pygit2.Tree):
_traverse(
@@ -2085,8 +2086,8 @@ class Pygit2(GitProvider):
try:
# This might need to be changed to account for a root that
# spans more than one directory
- oid = tree[self.root(tgt_env)].oid
- tree = self.repo[oid]
+ pygit2_id = tree[self.root(tgt_env)].id
+ tree = self.repo[pygit2_id]
except KeyError:
return files, symlinks
if not isinstance(tree, pygit2.Tree):
@@ -2130,12 +2131,12 @@ class Pygit2(GitProvider):
# path's object ID will be the target of the symlink. Follow
# the symlink and set path to the location indicated
# in the blob data.
- link_tgt = self.repo[entry.oid].data
+ link_tgt = self.repo[entry.id].data
path = salt.utils.path.join(
os.path.dirname(path), link_tgt, use_posixpath=True
)
else:
- blob = self.repo[entry.oid]
+ blob = self.repo[entry.id]
if isinstance(blob, pygit2.Tree):
# Path is a directory, not a file.
blob = None
--
2.46.0

View File

@ -0,0 +1,106 @@
From c00801d2f9807e49769d0e0d848ec12be555dbc1 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Wed, 25 Sep 2024 14:07:05 +0300
Subject: [PATCH] Revert the change making reactor less blocking
(bsc#1230322)
This reverts commit 0d35f09288700f5c961567442c3fcc25838b8de4.
---
salt/utils/reactor.py | 45 ++++++++++++++++---------------------------
1 file changed, 17 insertions(+), 28 deletions(-)
diff --git a/salt/utils/reactor.py b/salt/utils/reactor.py
index 78adad34da..19420a51cf 100644
--- a/salt/utils/reactor.py
+++ b/salt/utils/reactor.py
@@ -1,12 +1,10 @@
"""
Functions which implement running reactor jobs
"""
-
import fnmatch
import glob
import logging
import os
-from threading import Lock
import salt.client
import salt.defaults.exitcodes
@@ -196,6 +194,13 @@ class Reactor(salt.utils.process.SignalHandlingProcess, salt.state.Compiler):
self.resolve_aliases(chunks)
return chunks
+ def call_reactions(self, chunks):
+ """
+ Execute the reaction state
+ """
+ for chunk in chunks:
+ self.wrap.run(chunk)
+
def run(self):
"""
Enter into the server loop
@@ -213,7 +218,7 @@ class Reactor(salt.utils.process.SignalHandlingProcess, salt.state.Compiler):
) as event:
self.wrap = ReactWrap(self.opts)
- for data in event.iter_events(full=True, auto_reconnect=True):
+ for data in event.iter_events(full=True):
# skip all events fired by ourselves
if data["data"].get("user") == self.wrap.event_user:
continue
@@ -263,9 +268,15 @@ class Reactor(salt.utils.process.SignalHandlingProcess, salt.state.Compiler):
if not self.is_leader:
continue
else:
- self.wrap.call_reactions(
- data, self.list_reactors, self.reactions
- )
+ reactors = self.list_reactors(data["tag"])
+ if not reactors:
+ continue
+ chunks = self.reactions(data["tag"], data["data"], reactors)
+ if chunks:
+ try:
+ self.call_reactions(chunks)
+ except SystemExit:
+ log.warning("Exit ignored by reactor")
class ReactWrap:
@@ -286,7 +297,6 @@ class ReactWrap:
def __init__(self, opts):
self.opts = opts
- self._run_lock = Lock()
if ReactWrap.client_cache is None:
ReactWrap.client_cache = salt.utils.cache.CacheDict(
opts["reactor_refresh_interval"]
@@ -470,24 +480,3 @@ class ReactWrap:
Wrap LocalCaller to execute remote exec functions locally on the Minion
"""
self.client_cache["caller"].cmd(fun, *kwargs["arg"], **kwargs["kwarg"])
-
- def _call_reactions(self, data, list_reactors, get_reactions):
- reactors = list_reactors(data["tag"])
- if not reactors:
- return
- chunks = get_reactions(data["tag"], data["data"], reactors)
- if not chunks:
- return
- with self._run_lock:
- try:
- for chunk in chunks:
- self.run(chunk)
- except Exception as exc: # pylint: disable=broad-except
- log.error(
- "Exception while calling the reactions: %s", exc, exc_info=True
- )
-
- def call_reactions(self, data, list_reactors, get_reactions):
- return self.pool.fire_async(
- self._call_reactions, args=(data, list_reactors, get_reactions)
- )
--
2.46.1

View File

@ -0,0 +1,97 @@
From 63ff8ce775eec43b2f768b72fba4154c7832b1f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Yeray=20Guti=C3=A9rrez=20Cedr=C3=A9s?=
<yeray.gutierrez@suse.com>
Date: Wed, 7 Aug 2024 08:54:24 +0100
Subject: [PATCH] Skip more tests related to old OpenSSL algorithms
* Skip more tests related to old OpenSSL algorithms
* Check the comment from state apply ret instead of exception
---------
Co-authored-by: vzhestkov <vzhestkov@suse.com>
---
tests/pytests/functional/modules/test_x509_v2.py | 10 ++++++++--
tests/pytests/functional/states/test_x509_v2.py | 9 +++++++++
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/tests/pytests/functional/modules/test_x509_v2.py b/tests/pytests/functional/modules/test_x509_v2.py
index c060ad2971c..2e8152d04a3 100644
--- a/tests/pytests/functional/modules/test_x509_v2.py
+++ b/tests/pytests/functional/modules/test_x509_v2.py
@@ -1400,7 +1400,10 @@ def test_create_csr_raw(x509, rsa_privkey):
@pytest.mark.slow_test
@pytest.mark.parametrize("algo", ["rsa", "ec", "ed25519", "ed448"])
def test_create_private_key(x509, algo):
- res = x509.create_private_key(algo=algo)
+ try:
+ res = x509.create_private_key(algo=algo)
+ except UnsupportedAlgorithm:
+ pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
assert res.startswith("-----BEGIN PRIVATE KEY-----")
@@ -1408,7 +1411,10 @@ def test_create_private_key(x509, algo):
@pytest.mark.parametrize("algo", ["rsa", "ec", "ed25519", "ed448"])
def test_create_private_key_with_passphrase(x509, algo):
passphrase = "hunter2"
- res = x509.create_private_key(algo=algo, passphrase=passphrase)
+ try:
+ res = x509.create_private_key(algo=algo, passphrase=passphrase)
+ except UnsupportedAlgorithm:
+ pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
assert res.startswith("-----BEGIN ENCRYPTED PRIVATE KEY-----")
# ensure it can be loaded
x509.get_private_key_size(res, passphrase=passphrase)
diff --git a/tests/pytests/functional/states/test_x509_v2.py b/tests/pytests/functional/states/test_x509_v2.py
index e74bdd73f37..929be014cdb 100644
--- a/tests/pytests/functional/states/test_x509_v2.py
+++ b/tests/pytests/functional/states/test_x509_v2.py
@@ -6,6 +6,7 @@ import pytest
try:
import cryptography
import cryptography.x509 as cx509
+ from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec, ed448, ed25519, rsa
from cryptography.hazmat.primitives.serialization import (
@@ -691,6 +692,8 @@ def existing_csr_exts(x509, csr_args, csr_args_exts, ca_key, rsa_privkey, reques
def existing_pk(x509, pk_args, request):
pk_args.update(request.param)
ret = x509.private_key_managed(**pk_args)
+ if ret.result == False and "UnsupportedAlgorithm" in ret.comment:
+ pytest.skip(f"Algorithm '{pk_args['algo']}' is not supported on this OpenSSL version")
_assert_pk_basic(
ret,
pk_args.get("algo", "rsa"),
@@ -2140,6 +2143,8 @@ def test_private_key_managed(x509, pk_args, algo, encoding, passphrase):
pk_args["encoding"] = encoding
pk_args["passphrase"] = passphrase
ret = x509.private_key_managed(**pk_args)
+ if ret.result == False and "UnsupportedAlgorithm" in ret.comment:
+ pytest.skip(f"Algorithm '{algo}' is not supported on this OpenSSL version")
_assert_pk_basic(ret, algo, encoding, passphrase)
@@ -2167,6 +2172,8 @@ def test_private_key_managed_keysize(x509, pk_args, algo, keysize):
)
def test_private_key_managed_existing(x509, pk_args):
ret = x509.private_key_managed(**pk_args)
+ if ret.result == False and "UnsupportedAlgorithm" in ret.comment:
+ pytest.skip(f"Algorithm '{pk_args['algo']}' is not supported on this OpenSSL version")
_assert_not_changed(ret)
@@ -2194,6 +2201,8 @@ def test_private_key_managed_existing_new_with_passphrase_change(x509, pk_args):
def test_private_key_managed_algo_change(x509, pk_args):
pk_args["algo"] = "ed25519"
ret = x509.private_key_managed(**pk_args)
+ if ret.result == False and "UnsupportedAlgorithm" in ret.comment:
+ pytest.skip("Algorithm 'ed25519' is not supported on this OpenSSL version")
_assert_pk_basic(ret, "ed25519")
--
2.46.0

View File

@ -0,0 +1,110 @@
From 2fb453d04b8abe765a964174ae77d57398f2877a Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Wed, 25 Sep 2024 14:06:19 +0300
Subject: [PATCH] Use --cachedir for extension_modules in salt-call
(bsc#1226141)
* Use --cachedir parameter for extension_modules with salt-call
* Add test to check extension_modules value alignment
---
salt/cli/call.py | 11 +++++++-
salt/config/__init__.py | 6 +++++
tests/pytests/unit/cli/test_salt_call.py | 32 ++++++++++++++++++++++++
3 files changed, 48 insertions(+), 1 deletion(-)
create mode 100644 tests/pytests/unit/cli/test_salt_call.py
diff --git a/salt/cli/call.py b/salt/cli/call.py
index 932dc61681..be3ded77e6 100644
--- a/salt/cli/call.py
+++ b/salt/cli/call.py
@@ -3,7 +3,7 @@ import os
import salt.cli.caller
import salt.defaults.exitcodes
import salt.utils.parsers
-from salt.config import _expand_glob_path
+from salt.config import _expand_glob_path, prepend_root_dir
class SaltCall(salt.utils.parsers.SaltCallOptionParser):
@@ -37,6 +37,15 @@ class SaltCall(salt.utils.parsers.SaltCallOptionParser):
if self.options.master:
self.config["master"] = self.options.master
+ if self.options.cachedir and self.config.get(
+ "extension_modules"
+ ) == os.path.join(self.config.get("__cachedir"), "extmods"):
+ # Override `extension_modules`, but only in case if it was autogenerated
+ cache_dir = os.path.abspath(self.options.cachedir)
+ self.config["cachedir"] = cache_dir
+ self.config["extension_modules"] = os.path.join(cache_dir, "extmods")
+ prepend_root_dir(self.config, ["cachedir", "extension_modules"])
+
caller = salt.cli.caller.Caller.factory(self.config)
if self.options.doc:
diff --git a/salt/config/__init__.py b/salt/config/__init__.py
index 68f2b0f674..b3cd5d85ae 100644
--- a/salt/config/__init__.py
+++ b/salt/config/__init__.py
@@ -1,6 +1,7 @@
"""
All salt configuration loading and defaults should be in this module
"""
+
import codecs
import glob
import logging
@@ -3841,6 +3842,11 @@ def apply_minion_config(
_update_ssl_config(opts)
_update_discovery_config(opts)
+ # Store original `cachedir` value, before overriding,
+ # to make overriding more accurate.
+ if "__cachedir" not in opts:
+ opts["__cachedir"] = opts["cachedir"]
+
return opts
diff --git a/tests/pytests/unit/cli/test_salt_call.py b/tests/pytests/unit/cli/test_salt_call.py
new file mode 100644
index 0000000000..078f2af70d
--- /dev/null
+++ b/tests/pytests/unit/cli/test_salt_call.py
@@ -0,0 +1,32 @@
+import os
+
+from salt.cli.call import SaltCall
+from tests.support.mock import MagicMock, patch
+
+
+def test_passing_cachedir_to_extension_modules(temp_salt_minion):
+ """
+ Test passing `cachedir` CLI parameter to `extension_modules` opts
+ """
+ test_cache_dir = os.path.join(temp_salt_minion.config["root_dir"], "new_cache_tmp")
+ with patch(
+ "sys.argv",
+ [
+ "salt-call",
+ "--local",
+ "--config-dir",
+ temp_salt_minion.config["root_dir"],
+ "--cachedir",
+ test_cache_dir,
+ "test.true",
+ ],
+ ), patch("salt.utils.verify.verify_files", MagicMock()), patch(
+ "salt._logging.impl.setup_logfile_handler", MagicMock()
+ ):
+ salt_call = SaltCall()
+ with patch("salt.cli.caller.Caller.factory", MagicMock()) as caller_mock:
+ salt_call.run()
+ assert salt_call.config["cachedir"] == test_cache_dir
+ assert salt_call.config["extension_modules"] == os.path.join(
+ test_cache_dir, "extmods"
+ )
--
2.46.1

View File

@ -1,3 +1,138 @@
-------------------------------------------------------------------
Wed Oct 23 14:46:45 UTC 2024 - Pablo Suárez Hernández <psuarezhernandez@suse.com>
- Fix zyppnotify plugin after latest zypp/libzypp upgrades
(bsc#1231697, bsc#1231045)
-------------------------------------------------------------------
Wed Oct 2 07:49:50 UTC 2024 - Marek Czernek <marek.czernek@suse.com>
- Fix failing x509 tests with OpenSSL < 1.1
- Added:
* fix-x509-test-fails-on-old-openssl-systems-682.patch
-------------------------------------------------------------------
Wed Sep 25 12:00:37 UTC 2024 - Victor Zhestkov <vzhestkov@suse.com>
- Avoid explicit reading of /etc/salt/minion (bsc#1220357)
- Allow NamedLoaderContexts to be returned from loader
- Revert the change making reactor less blocking (bsc#1230322)
- Use --cachedir for extension_modules in salt-call (bsc#1226141)
- Prevent using SyncWrapper with no reason
- Added:
* avoid-explicit-reading-of-etc-salt-minion-bsc-122035.patch
* allow-namedloadercontexts-to-be-returned-from-loader.patch
* revert-the-change-making-reactor-less-blocking-bsc-1.patch
* use-cachedir-for-extension_modules-in-salt-call-bsc-.patch
* prevent-using-syncwrapper-with-no-reason.patch
-------------------------------------------------------------------
Thu Sep 12 16:08:41 UTC 2024 - Marek Czernek <marek.czernek@suse.com>
- Enable post_start_cleanup.sh to work in a transaction
- Added:
* post_start_cleanup.sh
-------------------------------------------------------------------
Tue Sep 10 12:52:23 UTC 2024 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
- Fix the SELinux context for Salt Minion service (bsc#1219041)
- Added:
* fix-the-selinux-context-for-salt-minion-service-bsc-.patch
-------------------------------------------------------------------
Wed Sep 4 11:42:59 UTC 2024 - Marek Czernek <marek.czernek@suse.com>
- Increase warn_until_date date for code we still support
- The test_debian test now uses port 80 for ubuntu keyserver
- Fix too frequent systemd service restart in test_system test
- Added:
* fix-test_debian-to-work-in-our-infrastructure-676.patch
* fix-test_system-flaky-setup_teardown-fn.patch
* fix-deprecated-code-677.patch
-------------------------------------------------------------------
Wed Sep 4 10:07:00 UTC 2024 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
- Security updates on Python 3.11 interpreter:
* Fix quadratic complexity in parsing -quoted cookie values with
backslashes (bsc#1229873, bsc#1230059, CVE-2024-7592).
* Prevent malformed payload to cause infinite loops in zipfile.Path
(bsc#1229704, bsc#1230058, CVE-2024-8088).
* Prevent email header injection due to unquoted newlines
(bsc#1228780, CVE-2024-6923).
* Rearranging definition of private global IP addresses
(bsc#1226448, CVE-2024-4032).
* gh-114572: ssl.SSLContext.cert_store_stats() and
ssl.SSLContext.get_ca_certs() now correctly lock access to the
certificate store, when the ssl.SSLContext is shared across
multiple threads (bsc#1226447, CVE-2024-0397).
- Security updates on Python dependencies:
* zipp: Add patch CVE-2024-5569.patch from upstream gh#jaraco/zipp@fd604bd34f03
(bsc#1227547, CVE-2024-5569, bsc#1229996).
* setuptools: Sanitize any VCS URL we download
(CVE-2024-6345, bsc#1228105, bsc#1229995).
* idna: Add CVE-2024-3651.patch, backported from upstream commit
gh#kjd/idna#172/commits/5beb28b9dd77912c0dd656d8b0fdba3eb80222e7
(bsc#1222842, bsc#1229994, CVE-2024-3651).
* urllib3: Added the ``Proxy-Authorization`` header to the list of headers
to strip from requests when redirecting to a different host
(bsc#1226469, bsc#1229654, CVE-2024-37891).
-------------------------------------------------------------------
Fri Aug 30 14:52:38 UTC 2024 - Victor Zhestkov <vzhestkov@suse.com>
- Avoid crash on wrong output of systemctl version (bsc#1229539)
- Improve error handling with different OpenSSL versions
- Remove redundant run_func from salt.master.MWorker._handle_aes
- Added:
* avoid-crash-on-wrong-output-of-systemctl-version-bsc.patch
* improve-error-handling-with-different-openssl-versio.patch
* remove-redundant-run_func-from-salt.master.mworker._.patch
-------------------------------------------------------------------
Thu Aug 29 11:49:41 UTC 2024 - Yeray Gutiérrez Cedrés <yeray.gutierrez@suse.com>
- Fix cloud minion configuration for multiple masters (bsc#1229109)
- Added:
* join-masters-if-it-is-a-list-671.patch
-------------------------------------------------------------------
Wed Aug 21 14:37:22 UTC 2024 - Marek Czernek <marek.czernek@suse.com>
- Use Pygit2 id instead of deprecated oid in gitfs
- Added:
* replace-use-of-pygit2-deprecated-and-removed-1.15.0-.patch
-------------------------------------------------------------------
Wed Aug 7 14:05:13 UTC 2024 - Victor Zhestkov <vzhestkov@suse.com>
- Add passlib python module to the bundle
- Add yamllint and pathspec python modules to the testsuite
- Modified:
* include-rpm
* include-deb
-------------------------------------------------------------------
Wed Aug 7 09:47:57 UTC 2024 - Marek Czernek <marek.czernek@suse.com>
- Fix few failing tests to work with both Salt and Salt bundle
- Skip testing unsupported OpenSSL crypto algorithms
- Added:
* make-tests-compatible-with-venv-bundle.patch
* skip-more-tests-related-to-old-openssl-algorithms.patch
-------------------------------------------------------------------
Wed Jul 24 10:13:27 UTC 2024 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>

View File

@ -57,6 +57,7 @@ Source12: remove-file
Source13: venv.py.src
Source14: venv-startup
Source15: venv-salt-minion.initd
Source20: post_start_cleanup.sh
Source100: venv-salt-minion-rpmlintrc
Source101: filter-requires.sh
Source200: venv-salt-minion-selinux.tar.gz
@ -415,6 +416,44 @@ Patch124: some-more-small-tests-fixes-enhancements-661.patch
Patch125: test_vultrpy-adjust-test-expectation-to-prevent-fail.patch
# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/66698
Patch126: firewalld-normalize-new-rich-rules-before-comparing-.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/669
Patch127: skip-more-tests-related-to-old-openssl-algorithms.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/662
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66730
Patch128: make-tests-compatible-with-venv-bundle.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66743
Patch129: replace-use-of-pygit2-deprecated-and-removed-1.15.0-.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/671
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/64173
Patch130: join-masters-if-it-is-a-list-671.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66509
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/commit/0c3ebc0795f9c2adec90118281343cae3070e0f6
Patch131: remove-redundant-run_func-from-salt.master.mworker._.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66818
Patch132: improve-error-handling-with-different-openssl-versio.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66856
Patch133: avoid-crash-on-wrong-output-of-systemctl-version-bsc.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66861
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/675
Patch134: fix-test_system-flaky-setup_teardown-fn.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/676
Patch135: fix-test_debian-to-work-in-our-infrastructure-676.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/677
Patch136: fix-deprecated-code-677.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66780
Patch137: fix-the-selinux-context-for-salt-minion-service-bsc-.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66510
Patch138: prevent-using-syncwrapper-with-no-reason.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66742
Patch139: use-cachedir-for-extension_modules-in-salt-call-bsc-.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/680
Patch140: revert-the-change-making-reactor-less-blocking-bsc-1.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/66649
Patch141: allow-namedloadercontexts-to-be-returned-from-loader.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/commit/d54407ba6dc664e5e5f3f613e27ae24f828c9648
Patch142: avoid-explicit-reading-of-etc-salt-minion-bsc-122035.patch
# PATCH-FIX_UPSTREAM: https://github.com/openSUSE/salt/pull/682
Patch143: fix-x509-test-fails-on-old-openssl-systems-682.patch
### IMPORTANT: The line below is used as a snippet marker. Do not touch it.
### SALT PATCHES LIST END
@ -453,6 +492,8 @@ BuildRequires: saltbundlepy-pycurl
BuildRequires: saltbundlepy-tornado
BuildRequires: saltbundlepy-jmespath
BuildRequires: saltbundlepy-passlib
# Include python devel to the bundle
BuildRequires: saltbundlepy-devel
@ -543,6 +584,7 @@ BuildRequires: saltbundlepy-mock
BuildRequires: saltbundlepy-pytest-salt-factories
BuildRequires: saltbundlepy-cherrypy
BuildRequires: saltbundlepy-salt-test
BuildRequires: saltbundlepy-yamllint
# update-alternatives is part of dpkg
%if "%_vendor" != "debbuild"
Requires(post): /usr/sbin/update-alternatives
@ -669,23 +711,8 @@ install -Dpm 0644 pkg/common/venv-salt-minion-postinstall.timer %{buildroot}%{_u
sed -i 's/^After=.*/After=network.target/; s/^Description=.*/Description=The venvjailed Salt Minion/; s#^ExecStart=.*#ExecStart=%{salt_venv}%{venv}/bin/salt-minion#' \
%{buildroot}%{_unitdir}/venv-salt-minion.service
# Create prev_env cleanup script
cat <<EOF > post_start_cleanup.sh
#!/usr/bin/env bash
if builtin type -P transactional-update &> /dev/null && [ "$TRANSACTIONAL_UPDATE" != "true" ]; then
# Do not clean previous environment on T-U systems when not in transaction
exit 0
fi
if [ -d "%{salt_venv}%{venv}/lib/prev_env" ]; then
rm -r "%{salt_venv}%{venv}/lib/prev_env" || :
fi
if [ -L "%{salt_venv}%{venv}/lib/PLACEHOLDER" ]; then
unlink "%{salt_venv}%{venv}/lib/PLACEHOLDER" || :
fi
EOF
install -Dm 0755 post_start_cleanup.sh "%{buildroot}%{salt_venv}%{venv}/bin/post_start_cleanup.sh"
sed -i -r 's|VENV_LOCATION_PLACEHOLDER|%{salt_venv}%{venv}|g' %{S:20}
install -Dm 0755 %{S:20} "%{buildroot}%{salt_venv}%{venv}/bin/post_start_cleanup.sh"
install -Dd -m 0755 %{buildroot}%{_sbindir}
ln -s service %{buildroot}%{_sbindir}/rcvenv-salt-minion
@ -979,6 +1006,7 @@ update-alternatives --remove salt-test /usr/lib/venv-salt-minion/bin/salt-test
%exclude %{salt_venv}%{venv}/bin/salt-factories*
%exclude %{salt_venv}%{venv}/bin/salt-test*
%exclude %{salt_venv}%{venv}/bin/cherryd*
%exclude %{salt_venv}%{venv}/bin/yamllint*
%exclude %{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/salt-testsuite
%exclude %{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/pytest*
%exclude %{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/_pytest*
@ -1005,6 +1033,8 @@ update-alternatives --remove salt-test /usr/lib/venv-salt-minion/bin/salt-test
%exclude %{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/werkzeug*
%exclude %{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/Werkzeug*
%exclude %{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/salt_test*
%exclude %{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/pathspec*
%exclude %{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/yamllint*
%endif
%{_bindir}/venv-salt-*
%{_sbindir}/rcvenv-salt-minion
@ -1065,6 +1095,7 @@ update-alternatives --remove salt-test /usr/lib/venv-salt-minion/bin/salt-test
%{salt_venv}%{venv}/bin/py.test*
%{salt_venv}%{venv}/bin/salt-factories*
%{salt_venv}%{venv}/bin/salt-test*
%{salt_venv}%{venv}/bin/yamllint*
%{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/salt-testsuite
%{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/pytest*
%{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/_pytest*
@ -1091,6 +1122,8 @@ update-alternatives --remove salt-test /usr/lib/venv-salt-minion/bin/salt-test
%{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/werkzeug*
%{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/Werkzeug*
%{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/salt_test*
%{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/pathspec*
%{salt_venv}%{venv}/lib/%{python_ver_short}/site-packages/yamllint*
%endif
%changelog