6430be99be
OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=194
285 lines
12 KiB
Diff
285 lines
12 KiB
Diff
From 48306a830d37e64b5275f48e25c315e658ee37e6 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 | 89 +++++++++++++++++++++-------
|
|
2 files changed, 90 insertions(+), 27 deletions(-)
|
|
|
|
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
|
|
index c7228bf712..4af29652d9 100644
|
|
--- a/salt/modules/zypperpkg.py
|
|
+++ b/salt/modules/zypperpkg.py
|
|
@@ -99,6 +99,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"
|
|
@@ -129,6 +131,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
|
|
|
|
@@ -148,6 +151,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:
|
|
@@ -306,6 +312,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
|
|
@@ -447,9 +457,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)
|
|
@@ -1054,7 +1066,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")
|
|
):
|
|
@@ -2431,7 +2443,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")] = {
|
|
@@ -2628,7 +2642,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")
|
|
)
|
|
@@ -2880,7 +2894,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 47fca906a7..671adc2779 100644
|
|
--- a/tests/unit/modules/test_zypperpkg.py
|
|
+++ b/tests/unit/modules/test_zypperpkg.py
|
|
@@ -14,7 +14,7 @@ import salt.utils.files
|
|
import salt.utils.pkg
|
|
from salt.exceptions import CommandExecutionError
|
|
from tests.support.mixins import LoaderModuleMockMixin
|
|
-from tests.support.mock import MagicMock, Mock, call, patch
|
|
+from tests.support.mock import MagicMock, Mock, call, mock_open, patch
|
|
from tests.support.unit import TestCase
|
|
|
|
|
|
@@ -27,7 +27,10 @@ class ZyppCallMock:
|
|
|
|
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)()
|
|
|
|
@@ -1801,8 +1804,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
<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()) == [
|
|
@@ -1824,8 +1828,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
</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()) == [
|
|
@@ -1846,8 +1851,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
</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()) == [
|
|
@@ -1867,8 +1873,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
</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()) == [
|
|
@@ -1889,8 +1896,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
<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"
|
|
@@ -1909,8 +1917,10 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
<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):
|
|
@@ -1926,8 +1936,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
<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):
|
|
@@ -1943,8 +1954,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
<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)(
|
|
@@ -1970,8 +1982,10 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
<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))
|
|
@@ -2063,3 +2077,38 @@ pattern() = package-c"""
|
|
with patch("salt.modules.zypperpkg.__zypper__", zypper_mock):
|
|
assert zypper.services_need_restart() == expected
|
|
zypper_mock(root=None).nolock.call.assert_called_with("ps", "-sss")
|
|
+
|
|
+ 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.34.1
|
|
|
|
|