From deaee93b2f83f1524ec136afc1a5198b33d293d2 Mon Sep 17 00:00:00 2001 From: Alberto Planas 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): """ - _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): """ - _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): """ - _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): """ - _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): """ - _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): """ - _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): """ - _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): """ - _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): """ - _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": "", + "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