Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP1:GA
salt.10902
add-all_versions-parameter-to-include-all-insta...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File add-all_versions-parameter-to-include-all-installed-.patch of Package salt.10902
From 8d3b589b0ac9b5cda98d9ffe25c75d3ee387f898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= <psuarezhernandez@suse.com> Date: Mon, 14 May 2018 11:33:13 +0100 Subject: [PATCH] Add "all_versions" parameter to include all installed version on rpm.info Enable "all_versions" parameter for zypper.info_installed Enable "all_versions" parameter for yumpkg.info_installed Prevent adding failed packages when pkg name contains the arch (on SUSE) Add 'all_versions' documentation for info_installed on yum/zypper modules Add unit tests for info_installed with all_versions Refactor: use dict.setdefault instead if-else statement Allow removing only specific package versions with zypper and yum --- salt/modules/rpm.py | 18 ++++++++--- salt/modules/yumpkg.py | 49 ++++++++++++++++++++++-------- salt/modules/zypper.py | 64 ++++++++++++++++++++++++++++++++------- salt/states/pkg.py | 33 +++++++++++++++++++- tests/unit/modules/test_yumpkg.py | 50 ++++++++++++++++++++++++++++++ tests/unit/modules/test_zypper.py | 50 ++++++++++++++++++++++++++++++ 6 files changed, 236 insertions(+), 28 deletions(-) diff --git a/salt/modules/rpm.py b/salt/modules/rpm.py index d065f1e2d9..3683234f59 100644 --- a/salt/modules/rpm.py +++ b/salt/modules/rpm.py @@ -453,7 +453,7 @@ def diff(package, path): return res -def info(*packages, **attr): +def info(*packages, **kwargs): ''' Return a detailed package(s) summary information. If no packages specified, all packages will be returned. @@ -467,6 +467,9 @@ def info(*packages, **attr): version, vendor, release, build_date, build_date_time_t, install_date, install_date_time_t, build_host, group, source_rpm, arch, epoch, size, license, signature, packager, url, summary, description. + :param all_versions: + Return information for all installed versions of the packages + :return: CLI example: @@ -476,7 +479,9 @@ def info(*packages, **attr): salt '*' lowpkg.info apache2 bash salt '*' lowpkg.info apache2 bash attr=version salt '*' lowpkg.info apache2 bash attr=version,build_date_iso,size + salt '*' lowpkg.info apache2 bash attr=version,build_date_iso,size all_versions=True ''' + all_versions = kwargs.get('all_versions', False) # LONGSIZE is not a valid tag for all versions of rpm. If LONGSIZE isn't # available, then we can just use SIZE for older versions. See Issue #31366. rpm_tags = __salt__['cmd.run_stdout']( @@ -516,7 +521,7 @@ def info(*packages, **attr): "edition": "edition: %|EPOCH?{%{EPOCH}:}|%{VERSION}-%{RELEASE}\\n", } - attr = attr.get('attr', None) and attr['attr'].split(",") or None + attr = kwargs.get('attr', None) and kwargs['attr'].split(",") or None query = list() if attr: for attr_k in attr: @@ -610,8 +615,13 @@ def info(*packages, **attr): if pkg_name.startswith('gpg-pubkey'): continue if pkg_name not in ret: - ret[pkg_name] = pkg_data.copy() - del ret[pkg_name]['edition'] + if all_versions: + ret[pkg_name] = [pkg_data.copy()] + else: + ret[pkg_name] = pkg_data.copy() + del ret[pkg_name]['edition'] + elif all_versions: + ret[pkg_name].append(pkg_data.copy()) return ret diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 9eb27e7701..42eedca227 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -994,31 +994,39 @@ def list_downloaded(): return ret -def info_installed(*names): +def info_installed(*names, **kwargs): ''' .. versionadded:: 2015.8.1 Return the information of the named package(s), installed on the system. + :param all_versions: + Include information for all versions of the packages installed on the minion. + CLI example: .. code-block:: bash salt '*' pkg.info_installed <package1> salt '*' pkg.info_installed <package1> <package2> <package3> ... + salt '*' pkg.info_installed <package1> <package2> <package3> all_versions=True ''' + all_versions = kwargs.get('all_versions', False) ret = dict() - for pkg_name, pkg_nfo in __salt__['lowpkg.info'](*names).items(): - t_nfo = dict() - # Translate dpkg-specific keys to a common structure - for key, value in pkg_nfo.items(): - if key == 'source_rpm': - t_nfo['source'] = value + for pkg_name, pkgs_nfo in __salt__['lowpkg.info'](*names, **kwargs).items(): + pkg_nfo = pkgs_nfo if all_versions else [pkgs_nfo] + for _nfo in pkg_nfo: + t_nfo = dict() + # Translate dpkg-specific keys to a common structure + for key, value in _nfo.items(): + if key == 'source_rpm': + t_nfo['source'] = value + else: + t_nfo[key] = value + if not all_versions: + ret[pkg_name] = t_nfo else: - t_nfo[key] = value - - ret[pkg_name] = t_nfo - + ret.setdefault(pkg_name, []).append(t_nfo) return ret @@ -1919,7 +1927,24 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613 raise CommandExecutionError(exc) old = list_pkgs() - targets = [x for x in pkg_params if x in old] + targets = [] + for target in pkg_params: + # Check if package version set to be removed is actually installed: + # old[target] contains a comma-separated list of installed versions + if target in old and not pkg_params[target]: + targets.append(target) + elif target in old and pkg_params[target] in old[target].split(','): + arch = '' + pkgname = target + try: + namepart, archpart = target.rsplit('.', 1) + except ValueError: + pass + else: + if archpart in salt.utils.pkg.rpm.ARCHES: + arch = '.' + archpart + pkgname = namepart + targets.append('{0}-{1}{2}'.format(pkgname, pkg_params[target], arch)) if not targets: return {} diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py index 16fc877684..68dd37f1b7 100644 --- a/salt/modules/zypper.py +++ b/salt/modules/zypper.py @@ -470,28 +470,37 @@ def info_installed(*names, **kwargs): Valid attributes are: ignore, report + :param all_versions: + Include information for all versions of the packages installed on the minion. + CLI example: .. code-block:: bash salt '*' pkg.info_installed <package1> salt '*' pkg.info_installed <package1> <package2> <package3> ... - salt '*' pkg.info_installed <package1> attr=version,vendor + salt '*' pkg.info_installed <package1> <package2> <package3> all_versions=True + salt '*' pkg.info_installed <package1> attr=version,vendor all_versions=True salt '*' pkg.info_installed <package1> <package2> <package3> ... attr=version,vendor salt '*' pkg.info_installed <package1> <package2> <package3> ... attr=version,vendor errors=ignore salt '*' pkg.info_installed <package1> <package2> <package3> ... attr=version,vendor errors=report ''' + all_versions = kwargs.get('all_versions', False) ret = dict() - for pkg_name, pkg_nfo in __salt__['lowpkg.info'](*names, **kwargs).items(): - t_nfo = dict() - # Translate dpkg-specific keys to a common structure - for key, value in six.iteritems(pkg_nfo): - if key == 'source_rpm': - t_nfo['source'] = value + for pkg_name, pkgs_nfo in __salt__['lowpkg.info'](*names, **kwargs).items(): + pkg_nfo = pkgs_nfo if all_versions else [pkgs_nfo] + for _nfo in pkg_nfo: + t_nfo = dict() + # Translate dpkg-specific keys to a common structure + for key, value in six.iteritems(_nfo): + if key == 'source_rpm': + t_nfo['source'] = value + else: + t_nfo[key] = value + if not all_versions: + ret[pkg_name] = t_nfo else: - t_nfo[key] = value - ret[pkg_name] = t_nfo - + ret.setdefault(pkg_name, []).append(t_nfo) return ret @@ -1367,7 +1376,14 @@ def _uninstall(name=None, pkgs=None): raise CommandExecutionError(exc) old = list_pkgs() - targets = [target for target in pkg_params if target in old] + targets = [] + for target in pkg_params: + # Check if package version set to be removed is actually installed: + # old[target] contains a comma-separated list of installed versions + if target in old and pkg_params[target] in old[target].split(','): + targets.append(target + "-" + pkg_params[target]) + elif target in old and not pkg_params[target]: + targets.append(target) if not targets: return {} @@ -1390,6 +1406,32 @@ def _uninstall(name=None, pkgs=None): return ret +def normalize_name(name): + ''' + Strips the architecture from the specified package name, if necessary. + Circumstances where this would be done include: + + * If the arch is 32 bit and the package name ends in a 32-bit arch. + * If the arch matches the OS arch, or is ``noarch``. + + CLI Example: + + .. code-block:: bash + + salt '*' pkg.normalize_name zsh.x86_64 + ''' + try: + arch = name.rsplit('.', 1)[-1] + if arch not in salt.utils.pkg.rpm.ARCHES + ('noarch',): + return name + except ValueError: + return name + if arch in (__grains__['osarch'], 'noarch') \ + or salt.utils.pkg.rpm.check_32(arch, osarch=__grains__['osarch']): + return name[:-(len(arch) + 1)] + return name + + def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument ''' .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 4c406aa04e..58a5896a6a 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -405,6 +405,16 @@ def _find_remove_targets(name=None, if __grains__['os'] == 'FreeBSD' and origin: cver = [k for k, v in six.iteritems(cur_pkgs) if v['origin'] == pkgname] + elif __grains__['os_family'] == 'Suse': + # On SUSE systems. Zypper returns packages without "arch" in name + try: + namepart, archpart = pkgname.rsplit('.', 1) + except ValueError: + cver = cur_pkgs.get(pkgname, []) + else: + if archpart in salt.utils.pkg.rpm.ARCHES + ("noarch",): + pkgname = namepart + cver = cur_pkgs.get(pkgname, []) else: cver = cur_pkgs.get(pkgname, []) @@ -812,6 +822,17 @@ def _verify_install(desired, new_pkgs, ignore_epoch=False, new_caps=None): cver = new_pkgs.get(pkgname.split('%')[0]) elif __grains__['os_family'] == 'Debian': cver = new_pkgs.get(pkgname.split('=')[0]) + elif __grains__['os_family'] == 'Suse': + # On SUSE systems. Zypper returns packages without "arch" in name + try: + namepart, archpart = pkgname.rsplit('.', 1) + except ValueError: + cver = new_pkgs.get(pkgname) + else: + if archpart in salt.utils.pkg.rpm.ARCHES + ("noarch",): + cver = new_pkgs.get(namepart) + else: + cver = new_pkgs.get(pkgname) else: cver = new_pkgs.get(pkgname) if not cver and pkgname in new_caps: @@ -2610,7 +2631,17 @@ def _uninstall( changes = __salt__['pkg.{0}'.format(action)](name, pkgs=pkgs, version=version, **kwargs) new = __salt__['pkg.list_pkgs'](versions_as_list=True, **kwargs) - failed = [x for x in pkg_params if x in new] + failed = [] + for x in pkg_params: + if __grains__['os_family'] in ['Suse', 'RedHat']: + # Check if the package version set to be removed is actually removed: + if x in new and not pkg_params[x]: + failed.append(x) + elif x in new and pkg_params[x] in new[x]: + failed.append(x + "-" + pkg_params[x]) + elif x in new: + failed.append(x) + if action == 'purge': new_removed = __salt__['pkg.list_pkgs'](versions_as_list=True, removed=True, diff --git a/tests/unit/modules/test_yumpkg.py b/tests/unit/modules/test_yumpkg.py index 9b2d39b4dd..74992071a1 100644 --- a/tests/unit/modules/test_yumpkg.py +++ b/tests/unit/modules/test_yumpkg.py @@ -602,3 +602,53 @@ class YumTestCase(TestCase, LoaderModuleMockMixin): '--branch=foo', '--exclude=kernel*', 'upgrade'], output_loglevel='trace', python_shell=False) + + def test_info_installed_with_all_versions(self): + ''' + Test the return information of all versions for the named package(s), installed on the system. + + :return: + ''' + run_out = { + 'virgo-dummy': [ + {'build_date': '2015-07-09T10:55:19Z', + 'vendor': 'openSUSE Build Service', + 'description': 'This is the Virgo dummy package used for testing SUSE Manager', + 'license': 'GPL-2.0', 'build_host': 'sheep05', 'url': 'http://www.suse.com', + 'build_date_time_t': 1436432119, 'relocations': '(not relocatable)', + 'source_rpm': 'virgo-dummy-1.0-1.1.src.rpm', 'install_date': '2016-02-23T16:31:57Z', + 'install_date_time_t': 1456241517, 'summary': 'Virgo dummy package', 'version': '1.0', + 'signature': 'DSA/SHA1, Thu Jul 9 08:55:33 2015, Key ID 27fa41bd8a7c64f9', + 'release': '1.1', 'group': 'Applications/System', 'arch': 'i686', 'size': '17992'}, + {'build_date': '2015-07-09T10:15:19Z', + 'vendor': 'openSUSE Build Service', + 'description': 'This is the Virgo dummy package used for testing SUSE Manager', + 'license': 'GPL-2.0', 'build_host': 'sheep05', 'url': 'http://www.suse.com', + 'build_date_time_t': 1436432119, 'relocations': '(not relocatable)', + 'source_rpm': 'virgo-dummy-1.0-1.1.src.rpm', 'install_date': '2016-02-23T16:31:57Z', + 'install_date_time_t': 14562415127, 'summary': 'Virgo dummy package', 'version': '1.0', + 'signature': 'DSA/SHA1, Thu Jul 9 08:55:33 2015, Key ID 27fa41bd8a7c64f9', + 'release': '1.1', 'group': 'Applications/System', 'arch': 'x86_64', 'size': '13124'} + ], + 'libopenssl1_0_0': [ + {'build_date': '2015-11-04T23:20:34Z', 'vendor': 'SUSE LLC <https://www.suse.com/>', + 'description': 'The OpenSSL Project is a collaborative effort.', + 'license': 'OpenSSL', 'build_host': 'sheep11', 'url': 'https://www.openssl.org/', + 'build_date_time_t': 1446675634, 'relocations': '(not relocatable)', + 'source_rpm': 'openssl-1.0.1i-34.1.src.rpm', 'install_date': '2016-02-23T16:31:35Z', + 'install_date_time_t': 1456241495, 'summary': 'Secure Sockets and Transport Layer Security', + 'version': '1.0.1i', 'signature': 'RSA/SHA256, Wed Nov 4 22:21:34 2015, Key ID 70af9e8139db7c82', + 'release': '34.1', 'group': 'Productivity/Networking/Security', 'packager': 'https://www.suse.com/', + 'arch': 'x86_64', 'size': '2576912'} + ] + } + with patch.dict(yumpkg.__salt__, {'lowpkg.info': MagicMock(return_value=run_out)}): + installed = yumpkg.info_installed(all_versions=True) + # Test overall products length + self.assertEqual(len(installed), 2) + + # Test multiple versions for the same package + for pkg_name, pkg_info_list in installed.items(): + self.assertEqual(len(pkg_info_list), 2 if pkg_name == "virgo-dummy" else 1) + for info in pkg_info_list: + self.assertTrue(info['arch'] in ('x86_64', 'i686')) diff --git a/tests/unit/modules/test_zypper.py b/tests/unit/modules/test_zypper.py index 539a950252..6eccee568b 100644 --- a/tests/unit/modules/test_zypper.py +++ b/tests/unit/modules/test_zypper.py @@ -327,6 +327,56 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin): installed = zypper.info_installed() self.assertEqual(installed['vīrgô']['description'], 'vīrgô d€šçripţiǫñ') + def test_info_installed_with_all_versions(self): + ''' + Test the return information of all versions for the named package(s), installed on the system. + + :return: + ''' + run_out = { + 'virgo-dummy': [ + {'build_date': '2015-07-09T10:55:19Z', + 'vendor': 'openSUSE Build Service', + 'description': 'This is the Virgo dummy package used for testing SUSE Manager', + 'license': 'GPL-2.0', 'build_host': 'sheep05', 'url': 'http://www.suse.com', + 'build_date_time_t': 1436432119, 'relocations': '(not relocatable)', + 'source_rpm': 'virgo-dummy-1.0-1.1.src.rpm', 'install_date': '2016-02-23T16:31:57Z', + 'install_date_time_t': 1456241517, 'summary': 'Virgo dummy package', 'version': '1.0', + 'signature': 'DSA/SHA1, Thu Jul 9 08:55:33 2015, Key ID 27fa41bd8a7c64f9', + 'release': '1.1', 'group': 'Applications/System', 'arch': 'i686', 'size': '17992'}, + {'build_date': '2015-07-09T10:15:19Z', + 'vendor': 'openSUSE Build Service', + 'description': 'This is the Virgo dummy package used for testing SUSE Manager', + 'license': 'GPL-2.0', 'build_host': 'sheep05', 'url': 'http://www.suse.com', + 'build_date_time_t': 1436432119, 'relocations': '(not relocatable)', + 'source_rpm': 'virgo-dummy-1.0-1.1.src.rpm', 'install_date': '2016-02-23T16:31:57Z', + 'install_date_time_t': 14562415127, 'summary': 'Virgo dummy package', 'version': '1.0', + 'signature': 'DSA/SHA1, Thu Jul 9 08:55:33 2015, Key ID 27fa41bd8a7c64f9', + 'release': '1.1', 'group': 'Applications/System', 'arch': 'x86_64', 'size': '13124'} + ], + 'libopenssl1_0_0': [ + {'build_date': '2015-11-04T23:20:34Z', 'vendor': 'SUSE LLC <https://www.suse.com/>', + 'description': 'The OpenSSL Project is a collaborative effort.', + 'license': 'OpenSSL', 'build_host': 'sheep11', 'url': 'https://www.openssl.org/', + 'build_date_time_t': 1446675634, 'relocations': '(not relocatable)', + 'source_rpm': 'openssl-1.0.1i-34.1.src.rpm', 'install_date': '2016-02-23T16:31:35Z', + 'install_date_time_t': 1456241495, 'summary': 'Secure Sockets and Transport Layer Security', + 'version': '1.0.1i', 'signature': 'RSA/SHA256, Wed Nov 4 22:21:34 2015, Key ID 70af9e8139db7c82', + 'release': '34.1', 'group': 'Productivity/Networking/Security', 'packager': 'https://www.suse.com/', + 'arch': 'x86_64', 'size': '2576912'} + ] + } + with patch.dict(zypper.__salt__, {'lowpkg.info': MagicMock(return_value=run_out)}): + installed = zypper.info_installed(all_versions=True) + # Test overall products length + self.assertEqual(len(installed), 2) + + # Test multiple versions for the same package + for pkg_name, pkg_info_list in installed.items(): + self.assertEqual(len(pkg_info_list), 2 if pkg_name == "virgo-dummy" else 1) + for info in pkg_info_list: + self.assertTrue(info['arch'] in ('x86_64', 'i686')) + def test_info_available(self): ''' Test return the information of the named package available for the system. -- 2.15.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor