From 10c728215f4b01210753add829f941d746ac3607 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 ffcd1dfa4f..5369a0342e 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py @@ -98,6 +98,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" @@ -128,6 +130,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 @@ -147,6 +150,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: @@ -305,6 +311,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 @@ -442,9 +452,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) @@ -1042,7 +1054,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") ): @@ -2381,7 +2393,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")] = { @@ -2578,7 +2592,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") ) @@ -2830,7 +2844,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 b346ef9ebd..a60b1546c6 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py @@ -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)() @@ -1782,8 +1785,9 @@ Repository 'DUMMY' not found by its alias, number, or URI. """ - _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()) == [ @@ -1805,8 +1809,9 @@ Repository 'DUMMY' not found by its alias, number, or URI. """ - _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()) == [ @@ -1827,8 +1832,9 @@ Repository 'DUMMY' not found by its alias, number, or URI. """ - _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()) == [ @@ -1848,8 +1854,9 @@ Repository 'DUMMY' not found by its alias, number, or URI. """ - _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()) == [ @@ -1870,8 +1877,9 @@ Repository 'DUMMY' not found by its alias, number, or URI. """ - _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" @@ -1890,8 +1898,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. """ - _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): @@ -1907,8 +1917,9 @@ Repository 'DUMMY' not found by its alias, number, or URI. """ - _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): @@ -1924,8 +1935,9 @@ Repository 'DUMMY' not found by its alias, number, or URI. """ - _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)( @@ -1951,8 +1963,10 @@ Repository 'DUMMY' not found by its alias, number, or URI. """ - _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)) @@ -2030,3 +2044,38 @@ pattern() = package-c""" with patch.dict(zypper.__context__, context): zypper._clean_cache() self.assertEqual(zypper.__context__, {"pkg.other_data": None}) + + 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.29.2