276 lines
12 KiB
Diff
276 lines
12 KiB
Diff
From deaee93b2f83f1524ec136afc1a5198b33d293d2 Mon Sep 17 00:00:00 2001
|
|
From: Alberto Planas <aplanas@suse.com>
|
|
Date: Mon, 5 Oct 2020 16:24:16 +0200
|
|
Subject: [PATCH] zypperpkg: ignore retcode 104 for search()
|
|
(bsc#1176697) (#270)
|
|
|
|
---
|
|
salt/modules/zypperpkg.py | 28 ++++++---
|
|
tests/unit/modules/test_zypperpkg.py | 87 ++++++++++++++++++++++------
|
|
2 files changed, 89 insertions(+), 26 deletions(-)
|
|
|
|
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
|
|
index d8220a1fdd..4bb10f445a 100644
|
|
--- a/salt/modules/zypperpkg.py
|
|
+++ b/salt/modules/zypperpkg.py
|
|
@@ -103,6 +103,8 @@ class _Zypper:
|
|
}
|
|
|
|
LOCK_EXIT_CODE = 7
|
|
+ NOT_FOUND_EXIT_CODE = 104
|
|
+
|
|
XML_DIRECTIVES = ["-x", "--xmlout"]
|
|
# ZYPPER_LOCK is not affected by --root
|
|
ZYPPER_LOCK = "/var/run/zypp.pid"
|
|
@@ -134,6 +136,7 @@ class _Zypper:
|
|
self.__no_raise = False
|
|
self.__refresh = False
|
|
self.__ignore_repo_failure = False
|
|
+ self.__ignore_not_found = False
|
|
self.__systemd_scope = False
|
|
self.__root = None
|
|
|
|
@@ -153,6 +156,9 @@ class _Zypper:
|
|
# Ignore exit code for 106 (repo is not available)
|
|
if "no_repo_failure" in kwargs:
|
|
self.__ignore_repo_failure = kwargs["no_repo_failure"]
|
|
+ # Ignore exit code for 104 (package not found)
|
|
+ if "ignore_not_found" in kwargs:
|
|
+ self.__ignore_not_found = kwargs["ignore_not_found"]
|
|
if "systemd_scope" in kwargs:
|
|
self.__systemd_scope = kwargs["systemd_scope"]
|
|
if "root" in kwargs:
|
|
@@ -333,6 +339,10 @@ class _Zypper:
|
|
if self.__root:
|
|
self.__cmd.extend(["--root", self.__root])
|
|
|
|
+ # Do not consider 104 as a retcode error
|
|
+ if self.__ignore_not_found:
|
|
+ kwargs["success_retcodes"] = [_Zypper.NOT_FOUND_EXIT_CODE]
|
|
+
|
|
self.__cmd.extend(args)
|
|
kwargs["output_loglevel"] = "trace"
|
|
kwargs["python_shell"] = False
|
|
@@ -479,9 +489,11 @@ class Wildcard:
|
|
Get available versions of the package.
|
|
:return:
|
|
"""
|
|
- solvables = self.zypper.nolock.xml.call(
|
|
- "se", "-xv", self.name
|
|
- ).getElementsByTagName("solvable")
|
|
+ solvables = (
|
|
+ self.zypper(ignore_not_found=True)
|
|
+ .nolock.xml.call("se", "-v", self.name)
|
|
+ .getElementsByTagName("solvable")
|
|
+ )
|
|
if not solvables:
|
|
raise CommandExecutionError(
|
|
"No packages found matching '{}'".format(self.name)
|
|
@@ -1086,7 +1098,7 @@ def list_repo_pkgs(*args, **kwargs):
|
|
|
|
root = kwargs.get("root") or None
|
|
for node in (
|
|
- __zypper__(root=root)
|
|
+ __zypper__(root=root, ignore_not_found=True)
|
|
.xml.call("se", "-s", *targets)
|
|
.getElementsByTagName("solvable")
|
|
):
|
|
@@ -2556,7 +2568,9 @@ def owner(*paths, **kwargs):
|
|
def _get_visible_patterns(root=None):
|
|
"""Get all available patterns in the repo that are visible."""
|
|
patterns = {}
|
|
- search_patterns = __zypper__(root=root).nolock.xml.call("se", "-t", "pattern")
|
|
+ search_patterns = __zypper__(root=root, ignore_not_found=True).nolock.xml.call(
|
|
+ "se", "-t", "pattern"
|
|
+ )
|
|
for element in search_patterns.getElementsByTagName("solvable"):
|
|
installed = element.getAttribute("status") == "installed"
|
|
patterns[element.getAttribute("name")] = {
|
|
@@ -2753,7 +2767,7 @@ def search(criteria, refresh=False, **kwargs):
|
|
|
|
cmd.append(criteria)
|
|
solvables = (
|
|
- __zypper__(root=root)
|
|
+ __zypper__(root=root, ignore_not_found=True)
|
|
.nolock.noraise.xml.call(*cmd)
|
|
.getElementsByTagName("solvable")
|
|
)
|
|
@@ -3005,7 +3019,7 @@ def _get_patches(installed_only=False, root=None):
|
|
"""
|
|
patches = {}
|
|
for element in (
|
|
- __zypper__(root=root)
|
|
+ __zypper__(root=root, ignore_not_found=True)
|
|
.nolock.xml.call("se", "-t", "patch")
|
|
.getElementsByTagName("solvable")
|
|
):
|
|
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
|
|
index 22137a2544..5e4c967520 100644
|
|
--- a/tests/unit/modules/test_zypperpkg.py
|
|
+++ b/tests/unit/modules/test_zypperpkg.py
|
|
@@ -28,7 +28,10 @@ class ZyppCallMock:
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
# If the call is for a configuration modifier, we return self
|
|
- if any(i in kwargs for i in ("no_repo_failure", "systemd_scope", "root")):
|
|
+ if any(
|
|
+ i in kwargs
|
|
+ for i in ("no_repo_failure", "ignore_not_found", "systemd_scope", "root")
|
|
+ ):
|
|
return self
|
|
return MagicMock(return_value=self.__return_value)()
|
|
|
|
@@ -1662,8 +1665,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="(System Packages)"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
- _zpr = MagicMock()
|
|
- _zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
+ __zpr = MagicMock()
|
|
+ __zpr.nolock.xml.call.return_value = minidom.parseString(xmldoc)
|
|
+ _zpr = MagicMock(return_value=__zpr)
|
|
wcard = zypper.Wildcard(_zpr)
|
|
wcard.name, wcard.version = "libzypp", "*"
|
|
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
|
|
@@ -1685,8 +1689,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
|
|
- _zpr = MagicMock()
|
|
- _zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
+ __zpr = MagicMock()
|
|
+ __zpr.nolock.xml.call.return_value = minidom.parseString(xmldoc)
|
|
+ _zpr = MagicMock(return_value=__zpr)
|
|
wcard = zypper.Wildcard(_zpr)
|
|
wcard.name, wcard.version = "libzypp", "16.2.*-2*"
|
|
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
|
|
@@ -1707,8 +1712,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
|
|
- _zpr = MagicMock()
|
|
- _zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
+ __zpr = MagicMock()
|
|
+ __zpr.nolock.xml.call.return_value = minidom.parseString(xmldoc)
|
|
+ _zpr = MagicMock(return_value=__zpr)
|
|
wcard = zypper.Wildcard(_zpr)
|
|
wcard.name, wcard.version = "libzypp", "16.2.5*"
|
|
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
|
|
@@ -1728,8 +1734,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
|
|
- _zpr = MagicMock()
|
|
- _zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
+ __zpr = MagicMock()
|
|
+ __zpr.nolock.xml.call.return_value = minidom.parseString(xmldoc)
|
|
+ _zpr = MagicMock(return_value=__zpr)
|
|
wcard = zypper.Wildcard(_zpr)
|
|
wcard.name, wcard.version = "libzypp", "*.1"
|
|
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
|
|
@@ -1750,8 +1757,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
- _zpr = MagicMock()
|
|
- _zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
+ __zpr = MagicMock()
|
|
+ __zpr.nolock.xml.call.return_value = minidom.parseString(xmldoc)
|
|
+ _zpr = MagicMock(return_value=__zpr)
|
|
assert zypper.Wildcard(_zpr)("libzypp", "16.2.4*") == "16.2.4-19.5"
|
|
assert zypper.Wildcard(_zpr)("libzypp", "16.2*") == "16.2.5-25.1"
|
|
assert zypper.Wildcard(_zpr)("libzypp", "*6-*") == "17.2.6-27.9.1"
|
|
@@ -1770,8 +1778,10 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
- _zpr = MagicMock()
|
|
- _zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
+ __zpr = MagicMock()
|
|
+ __zpr.nolock.xml.call.return_value = minidom.parseString(xmldoc)
|
|
+ _zpr = MagicMock(return_value=__zpr)
|
|
+
|
|
assert zypper.Wildcard(_zpr)("libzypp", None) is None
|
|
|
|
def test_wildcard_to_query_typecheck(self):
|
|
@@ -1787,8 +1797,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
- _zpr = MagicMock()
|
|
- _zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
+ __zpr = MagicMock()
|
|
+ __zpr.nolock.xml.call.return_value = minidom.parseString(xmldoc)
|
|
+ _zpr = MagicMock(return_value=__zpr)
|
|
assert isinstance(zypper.Wildcard(_zpr)("libzypp", "*.1"), str)
|
|
|
|
def test_wildcard_to_query_condition_preservation(self):
|
|
@@ -1804,8 +1815,9 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
- _zpr = MagicMock()
|
|
- _zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
+ __zpr = MagicMock()
|
|
+ __zpr.nolock.xml.call.return_value = minidom.parseString(xmldoc)
|
|
+ _zpr = MagicMock(return_value=__zpr)
|
|
|
|
for op in zypper.Wildcard.Z_OP:
|
|
assert zypper.Wildcard(_zpr)(
|
|
@@ -1831,8 +1843,10 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
- _zpr = MagicMock()
|
|
- _zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
+ __zpr = MagicMock()
|
|
+ __zpr.nolock.xml.call.return_value = minidom.parseString(xmldoc)
|
|
+ _zpr = MagicMock(return_value=__zpr)
|
|
+
|
|
with self.assertRaises(CommandExecutionError):
|
|
for op in [">>", "==", "<<", "+"]:
|
|
zypper.Wildcard(_zpr)("libzypp", "{}*.1".format(op))
|
|
@@ -1958,3 +1972,38 @@ pattern() = package-c"""
|
|
self.assertFalse(zypper.__zypper__._is_rpm_lock())
|
|
self.assertEqual(lockf_mock.call_count, 2)
|
|
zypper.__zypper__._reset()
|
|
+
|
|
+ def test_search(self):
|
|
+ """Test zypperpkg.search()"""
|
|
+ xml_mock = MagicMock(return_value=[])
|
|
+ zypp_mock = MagicMock(return_value=xml_mock)
|
|
+ ZyppCallMock(return_value=xml_mock)
|
|
+ with patch("salt.modules.zypperpkg.__zypper__", zypp_mock):
|
|
+ zypper.search("emacs")
|
|
+ zypp_mock.assert_called_with(root=None, ignore_not_found=True)
|
|
+ xml_mock.nolock.noraise.xml.call.assert_called_with("search", "emacs")
|
|
+
|
|
+ def test_search_not_found(self):
|
|
+ """Test zypperpkg.search()"""
|
|
+ ret = {
|
|
+ "stdout": "<?xml version='1.0'?><stream></stream>",
|
|
+ "stderr": None,
|
|
+ "retcode": 104,
|
|
+ }
|
|
+ run_all_mock = MagicMock(return_value=ret)
|
|
+ with patch.dict(zypper.__salt__, {"cmd.run_all": run_all_mock}):
|
|
+ self.assertRaises(CommandExecutionError, zypper.search, "vim")
|
|
+ run_all_mock.assert_called_with(
|
|
+ [
|
|
+ "zypper",
|
|
+ "--non-interactive",
|
|
+ "--xmlout",
|
|
+ "--no-refresh",
|
|
+ "search",
|
|
+ "vim",
|
|
+ ],
|
|
+ success_retcodes=[104],
|
|
+ output_loglevel="trace",
|
|
+ python_shell=False,
|
|
+ env={"ZYPP_READONLY_HACK": "1"},
|
|
+ )
|
|
--
|
|
2.39.2
|
|
|
|
|