fc16e6ca2c
OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=132
2148 lines
76 KiB
Diff
2148 lines
76 KiB
Diff
From e20116f09c1f68238008c13a0517a8d36a7be56a Mon Sep 17 00:00:00 2001
|
|
From: Alberto Planas <aplanas@gmail.com>
|
|
Date: Wed, 17 Oct 2018 11:58:04 +0200
|
|
Subject: [PATCH] zypper: add root configuration parameter
|
|
|
|
Fix typo in comment
|
|
|
|
lowpkg: add parameter to change root directory
|
|
|
|
The CLI rpm command allows the --root parameter to change the
|
|
expected location where the rpm database can be found.
|
|
|
|
This patch add a new optional parameter in the public interface
|
|
to allow the set of the new root location.
|
|
|
|
Update the tests to use the extra parameter.
|
|
|
|
Add root parameter into the zypper module
|
|
|
|
The zypper CLI provides a way to change the path where zypper expect
|
|
to find the required configuration files and repositories.
|
|
|
|
This feature is useful to bootstrap chroot environments, inspect
|
|
repositories and packages from locally mounted devices, or help
|
|
during the installation of a new OS from the SUSE family.
|
|
|
|
This patch add the root optional parameter for each command in the
|
|
public interface, and fix the tests.
|
|
|
|
pkg: Transfer optional parameters to lower levels.
|
|
|
|
pkgrepo: Transfer optional parameters to lower levels.
|
|
|
|
zypper: fix the reset after the call
|
|
|
|
_Zypper class take note when a .call() is done, to clean up the data
|
|
when we access to some attribute.
|
|
|
|
This produces a bug when two calls are one after another an we set
|
|
some attributes via the __call__ method, as whatever is set will be
|
|
cleared after the first attribute is accessed.
|
|
|
|
For example:
|
|
|
|
zypper.attrib.call(..)
|
|
zypper(root=root).otherattrib.call(..)
|
|
|
|
The first call will set __called as True, and the reset of the inner
|
|
state of zypper will be cleared when otherattrib is accessed,
|
|
cleanning the status for __root.
|
|
|
|
This patch makes sure to clean the status also during the __call__
|
|
method, avoiding the cleanning when the attribute is accessed.
|
|
|
|
zypper: add no_recommends parameter
|
|
|
|
Add no_recommends parameter to install and upgrade actions.
|
|
---
|
|
salt/modules/rpm_lowpkg.py | 101 +++++--
|
|
salt/modules/zypperpkg.py | 390 ++++++++++++++++++--------
|
|
salt/states/pkg.py | 28 +-
|
|
salt/states/pkgrepo.py | 14 +-
|
|
tests/unit/modules/test_rpm_lowpkg.py | 92 +++++-
|
|
tests/unit/modules/test_zypperpkg.py | 45 +--
|
|
tests/unit/states/test_pkg.py | 7 +-
|
|
7 files changed, 488 insertions(+), 189 deletions(-)
|
|
|
|
diff --git a/salt/modules/rpm_lowpkg.py b/salt/modules/rpm_lowpkg.py
|
|
index 893ae4f817..e577c4391a 100644
|
|
--- a/salt/modules/rpm_lowpkg.py
|
|
+++ b/salt/modules/rpm_lowpkg.py
|
|
@@ -76,7 +76,7 @@ def bin_pkg_info(path, saltenv='base'):
|
|
minion so that it can be examined.
|
|
|
|
saltenv : base
|
|
- Salt fileserver envrionment from which to retrieve the package. Ignored
|
|
+ Salt fileserver environment from which to retrieve the package. Ignored
|
|
if ``path`` is a local file path on the minion.
|
|
|
|
CLI Example:
|
|
@@ -128,12 +128,15 @@ def bin_pkg_info(path, saltenv='base'):
|
|
return ret
|
|
|
|
|
|
-def list_pkgs(*packages):
|
|
+def list_pkgs(*packages, **kwargs):
|
|
'''
|
|
List the packages currently installed in a dict::
|
|
|
|
{'<package_name>': '<version>'}
|
|
|
|
+ root
|
|
+ use root as top level directory (default: "/")
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
@@ -141,8 +144,11 @@ def list_pkgs(*packages):
|
|
salt '*' lowpkg.list_pkgs
|
|
'''
|
|
pkgs = {}
|
|
- cmd = ['rpm', '-q' if packages else '-qa',
|
|
- '--queryformat', r'%{NAME} %{VERSION}\n']
|
|
+ cmd = ['rpm']
|
|
+ if kwargs.get('root'):
|
|
+ cmd.extend(['--root', kwargs['root']])
|
|
+ cmd.extend(['-q' if packages else '-qa',
|
|
+ '--queryformat', r'%{NAME} %{VERSION}\n'])
|
|
if packages:
|
|
cmd.extend(packages)
|
|
out = __salt__['cmd.run'](cmd, output_loglevel='trace', python_shell=False)
|
|
@@ -158,6 +164,9 @@ def verify(*packages, **kwargs):
|
|
'''
|
|
Runs an rpm -Va on a system, and returns the results in a dict
|
|
|
|
+ root
|
|
+ use root as top level directory (default: "/")
|
|
+
|
|
Files with an attribute of config, doc, ghost, license or readme in the
|
|
package header can be ignored using the ``ignore_types`` keyword argument
|
|
|
|
@@ -199,6 +208,8 @@ def verify(*packages, **kwargs):
|
|
verify_options = [x.strip() for x in six.text_type(verify_options).split(',')]
|
|
|
|
cmd = ['rpm']
|
|
+ if kwargs.get('root'):
|
|
+ cmd.extend(['--root', kwargs['root']])
|
|
cmd.extend(['--' + x for x in verify_options])
|
|
if packages:
|
|
cmd.append('-V')
|
|
@@ -258,6 +269,9 @@ def modified(*packages, **flags):
|
|
|
|
.. versionadded:: 2015.5.0
|
|
|
|
+ root
|
|
+ use root as top level directory (default: "/")
|
|
+
|
|
CLI examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -266,10 +280,12 @@ def modified(*packages, **flags):
|
|
salt '*' lowpkg.modified httpd postfix
|
|
salt '*' lowpkg.modified
|
|
'''
|
|
- ret = __salt__['cmd.run_all'](
|
|
- ['rpm', '-Va'] + list(packages),
|
|
- output_loglevel='trace',
|
|
- python_shell=False)
|
|
+ cmd = ['rpm']
|
|
+ if flags.get('root'):
|
|
+ cmd.extend(['--root', flags.pop('root')])
|
|
+ cmd.append('-Va')
|
|
+ cmd.extend(packages)
|
|
+ ret = __salt__['cmd.run_all'](cmd, output_loglevel='trace', python_shell=False)
|
|
|
|
data = {}
|
|
|
|
@@ -324,12 +340,15 @@ def modified(*packages, **flags):
|
|
return filtered_data
|
|
|
|
|
|
-def file_list(*packages):
|
|
+def file_list(*packages, **kwargs):
|
|
'''
|
|
List the files that belong to a package. Not specifying any packages will
|
|
return a list of _every_ file on the system's rpm database (not generally
|
|
recommended).
|
|
|
|
+ root
|
|
+ use root as top level directory (default: "/")
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -338,12 +357,15 @@ def file_list(*packages):
|
|
salt '*' lowpkg.file_list httpd postfix
|
|
salt '*' lowpkg.file_list
|
|
'''
|
|
- if not packages:
|
|
- cmd = ['rpm', '-qla']
|
|
- else:
|
|
- cmd = ['rpm', '-ql']
|
|
+ cmd = ['rpm']
|
|
+ if kwargs.get('root'):
|
|
+ cmd.extend(['--root', kwargs['root']])
|
|
+
|
|
+ cmd.append('-ql' if packages else '-qla')
|
|
+ if packages:
|
|
# Can't concatenate a tuple, must do a list.extend()
|
|
cmd.extend(packages)
|
|
+
|
|
ret = __salt__['cmd.run'](
|
|
cmd,
|
|
output_loglevel='trace',
|
|
@@ -351,12 +373,15 @@ def file_list(*packages):
|
|
return {'errors': [], 'files': ret}
|
|
|
|
|
|
-def file_dict(*packages):
|
|
+def file_dict(*packages, **kwargs):
|
|
'''
|
|
List the files that belong to a package, sorted by group. Not specifying
|
|
any packages will return a list of _every_ file on the system's rpm
|
|
database (not generally recommended).
|
|
|
|
+ root
|
|
+ use root as top level directory (default: "/")
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -368,8 +393,11 @@ def file_dict(*packages):
|
|
errors = []
|
|
ret = {}
|
|
pkgs = {}
|
|
- cmd = ['rpm', '-q' if packages else '-qa',
|
|
- '--queryformat', r'%{NAME} %{VERSION}\n']
|
|
+ cmd = ['rpm']
|
|
+ if kwargs.get('root'):
|
|
+ cmd.extend(['--root', kwargs['root']])
|
|
+ cmd.extend(['-q' if packages else '-qa',
|
|
+ '--queryformat', r'%{NAME} %{VERSION}\n'])
|
|
if packages:
|
|
cmd.extend(packages)
|
|
out = __salt__['cmd.run'](cmd, output_loglevel='trace', python_shell=False)
|
|
@@ -380,8 +408,10 @@ def file_dict(*packages):
|
|
comps = line.split()
|
|
pkgs[comps[0]] = {'version': comps[1]}
|
|
for pkg in pkgs:
|
|
- files = []
|
|
- cmd = ['rpm', '-ql', pkg]
|
|
+ cmd = ['rpm']
|
|
+ if kwargs.get('root'):
|
|
+ cmd.extend(['--root', kwargs['root']])
|
|
+ cmd.extend(['-ql', pkg])
|
|
out = __salt__['cmd.run'](
|
|
['rpm', '-ql', pkg],
|
|
output_loglevel='trace',
|
|
@@ -390,7 +420,7 @@ def file_dict(*packages):
|
|
return {'errors': errors, 'packages': ret}
|
|
|
|
|
|
-def owner(*paths):
|
|
+def owner(*paths, **kwargs):
|
|
'''
|
|
Return the name of the package that owns the file. Multiple file paths can
|
|
be passed. If a single path is passed, a string will be returned,
|
|
@@ -400,6 +430,9 @@ def owner(*paths):
|
|
If the file is not owned by a package, or is not present on the minion,
|
|
then an empty string will be returned for that path.
|
|
|
|
+ root
|
|
+ use root as top level directory (default: "/")
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -411,7 +444,10 @@ def owner(*paths):
|
|
return ''
|
|
ret = {}
|
|
for path in paths:
|
|
- cmd = ['rpm', '-qf', '--queryformat', '%{name}', path]
|
|
+ cmd = ['rpm']
|
|
+ if kwargs.get('root'):
|
|
+ cmd.extend(['--root', kwargs['root']])
|
|
+ cmd.extend(['-qf', '--queryformat', '%{name}', path])
|
|
ret[path] = __salt__['cmd.run_stdout'](cmd,
|
|
output_loglevel='trace',
|
|
python_shell=False)
|
|
@@ -471,6 +507,9 @@ def info(*packages, **kwargs):
|
|
:param all_versions:
|
|
Return information for all installed versions of the packages
|
|
|
|
+ :param root:
|
|
+ use root as top level directory (default: "/")
|
|
+
|
|
:return:
|
|
|
|
CLI example:
|
|
@@ -493,7 +532,14 @@ def info(*packages, **kwargs):
|
|
else:
|
|
size_tag = '%{SIZE}'
|
|
|
|
- cmd = packages and "rpm -q {0}".format(' '.join(packages)) or "rpm -qa"
|
|
+ cmd = ['rpm']
|
|
+ if kwargs.get('root'):
|
|
+ cmd.extend(['--root', kwargs['root']])
|
|
+ if packages:
|
|
+ cmd.append('-q')
|
|
+ cmd.extend(packages)
|
|
+ else:
|
|
+ cmd.append('-qa')
|
|
|
|
# Construct query format
|
|
attr_map = {
|
|
@@ -544,6 +590,7 @@ def info(*packages, **kwargs):
|
|
query.append(attr_map['description'])
|
|
query.append("-----\\n")
|
|
|
|
+ cmd = ' '.join(cmd)
|
|
call = __salt__['cmd.run_all'](cmd + (" --queryformat '{0}'".format(''.join(query))),
|
|
output_loglevel='trace', env={'TZ': 'UTC'}, clean_env=True)
|
|
if call['retcode'] != 0:
|
|
@@ -744,10 +791,13 @@ def version_cmp(ver1, ver2, ignore_epoch=False):
|
|
return salt.utils.versions.version_cmp(ver1, ver2, ignore_epoch=False)
|
|
|
|
|
|
-def checksum(*paths):
|
|
+def checksum(*paths, **kwargs):
|
|
'''
|
|
Return if the signature of a RPM file is valid.
|
|
|
|
+ root
|
|
+ use root as top level directory (default: "/")
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
@@ -760,9 +810,14 @@ def checksum(*paths):
|
|
if not paths:
|
|
raise CommandExecutionError("No package files has been specified.")
|
|
|
|
+ cmd = ['rpm']
|
|
+ if kwargs.get('root'):
|
|
+ cmd.extend(['--root', kwargs['root']])
|
|
+ cmd.extend(['-K', '--quiet'])
|
|
for package_file in paths:
|
|
+ cmd_ = cmd + [package_file]
|
|
ret[package_file] = (bool(__salt__['file.file_exists'](package_file)) and
|
|
- not __salt__['cmd.retcode'](["rpm", "-K", "--quiet", package_file],
|
|
+ not __salt__['cmd.retcode'](cmd_,
|
|
ignore_retcode=True,
|
|
output_loglevel='trace',
|
|
python_shell=False))
|
|
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
|
|
index 92e7052020..c442337c58 100644
|
|
--- a/salt/modules/zypperpkg.py
|
|
+++ b/salt/modules/zypperpkg.py
|
|
@@ -99,6 +99,7 @@ class _Zypper(object):
|
|
|
|
LOCK_EXIT_CODE = 7
|
|
XML_DIRECTIVES = ['-x', '--xmlout']
|
|
+ # ZYPPER_LOCK is not affected by --root
|
|
ZYPPER_LOCK = '/var/run/zypp.pid'
|
|
TAG_RELEASED = 'zypper/released'
|
|
TAG_BLOCKED = 'zypper/blocked'
|
|
@@ -107,7 +108,6 @@ class _Zypper(object):
|
|
'''
|
|
Constructor
|
|
'''
|
|
- self.__called = False
|
|
self._reset()
|
|
|
|
def _reset(self):
|
|
@@ -129,6 +129,10 @@ class _Zypper(object):
|
|
self.__refresh = False
|
|
self.__ignore_repo_failure = False
|
|
self.__systemd_scope = False
|
|
+ self.__root = None
|
|
+
|
|
+ # Call status
|
|
+ self.__called = False
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
'''
|
|
@@ -136,11 +140,17 @@ class _Zypper(object):
|
|
:param kwargs:
|
|
:return:
|
|
'''
|
|
+ # Reset after the call
|
|
+ if self.__called:
|
|
+ self._reset()
|
|
+
|
|
# Ignore exit code for 106 (repo is not available)
|
|
if 'no_repo_failure' in kwargs:
|
|
self.__ignore_repo_failure = kwargs['no_repo_failure']
|
|
if 'systemd_scope' in kwargs:
|
|
self.__systemd_scope = kwargs['systemd_scope']
|
|
+ if 'root' in kwargs:
|
|
+ self.__root = kwargs['root']
|
|
return self
|
|
|
|
def __getattr__(self, item):
|
|
@@ -153,7 +163,6 @@ class _Zypper(object):
|
|
# Reset after the call
|
|
if self.__called:
|
|
self._reset()
|
|
- self.__called = False
|
|
|
|
if item == 'xml':
|
|
self.__xml = True
|
|
@@ -284,6 +293,8 @@ class _Zypper(object):
|
|
self.__cmd.append('--xmlout')
|
|
if not self.__refresh:
|
|
self.__cmd.append('--no-refresh')
|
|
+ if self.__root:
|
|
+ self.__cmd.extend(['--root', self.__root])
|
|
|
|
self.__cmd.extend(args)
|
|
kwargs['output_loglevel'] = 'trace'
|
|
@@ -442,7 +453,7 @@ def _clean_cache():
|
|
__context__.pop(cache_name, None)
|
|
|
|
|
|
-def list_upgrades(refresh=True, **kwargs):
|
|
+def list_upgrades(refresh=True, root=None, **kwargs):
|
|
'''
|
|
List all available package upgrades on this system
|
|
|
|
@@ -451,6 +462,9 @@ def list_upgrades(refresh=True, **kwargs):
|
|
If set to False it depends on zypper if a refresh is
|
|
executed.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
@@ -458,7 +472,7 @@ def list_upgrades(refresh=True, **kwargs):
|
|
salt '*' pkg.list_upgrades
|
|
'''
|
|
if refresh:
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
ret = dict()
|
|
cmd = ['list-updates']
|
|
@@ -467,7 +481,7 @@ def list_upgrades(refresh=True, **kwargs):
|
|
if not isinstance(repo_name, six.string_types):
|
|
repo_name = six.text_type(repo_name)
|
|
cmd.extend(['--repo', repo_name])
|
|
- for update_node in __zypper__.nolock.xml.call(*cmd).getElementsByTagName('update'):
|
|
+ for update_node in __zypper__(root=root).nolock.xml.call(*cmd).getElementsByTagName('update'):
|
|
if update_node.getAttribute('kind') == 'package':
|
|
ret[update_node.getAttribute('name')] = update_node.getAttribute('edition')
|
|
|
|
@@ -504,6 +518,9 @@ def info_installed(*names, **kwargs):
|
|
:param all_versions:
|
|
Include information for all versions of the packages installed on the minion.
|
|
|
|
+ :param root:
|
|
+ Operate on a different root directory.
|
|
+
|
|
CLI example:
|
|
|
|
.. code-block:: bash
|
|
@@ -544,6 +561,9 @@ def info_available(*names, **kwargs):
|
|
If set to False it depends on zypper if a refresh is
|
|
executed or not.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI example:
|
|
|
|
.. code-block:: bash
|
|
@@ -558,9 +578,11 @@ def info_available(*names, **kwargs):
|
|
else:
|
|
names = sorted(list(set(names)))
|
|
|
|
+ root = kwargs.get('root', None)
|
|
+
|
|
# Refresh db before extracting the latest package
|
|
if kwargs.get('refresh', True):
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
pkg_info = []
|
|
batch = names[:]
|
|
@@ -569,7 +591,8 @@ def info_available(*names, **kwargs):
|
|
# Run in batches
|
|
while batch:
|
|
pkg_info.extend(re.split(r"Information for package*",
|
|
- __zypper__.nolock.call('info', '-t', 'package', *batch[:batch_size])))
|
|
+ __zypper__(root=root).nolock.call('info', '-t', 'package',
|
|
+ *batch[:batch_size])))
|
|
batch = batch[batch_size:]
|
|
|
|
for pkg_data in pkg_info:
|
|
@@ -629,6 +652,9 @@ def latest_version(*names, **kwargs):
|
|
If set to False it depends on zypper if a refresh is
|
|
executed or not.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI example:
|
|
|
|
.. code-block:: bash
|
|
@@ -671,6 +697,9 @@ def upgrade_available(name, **kwargs):
|
|
If set to False it depends on zypper if a refresh is
|
|
executed or not.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
@@ -687,6 +716,9 @@ def version(*names, **kwargs):
|
|
installed. If more than one package name is specified, a dict of
|
|
name/version pairs is returned.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
@@ -719,7 +751,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False):
|
|
return __salt__['lowpkg.version_cmp'](ver1, ver2, ignore_epoch=ignore_epoch)
|
|
|
|
|
|
-def list_pkgs(versions_as_list=False, **kwargs):
|
|
+def list_pkgs(versions_as_list=False, root=None, **kwargs):
|
|
'''
|
|
List the packages currently installed as a dict. By default, the dict
|
|
contains versions as a comma separated string::
|
|
@@ -731,6 +763,9 @@ def list_pkgs(versions_as_list=False, **kwargs):
|
|
|
|
{'<package_name>': ['<version>', '<version>']}
|
|
|
|
+ root:
|
|
+ operate on a different root directory.
|
|
+
|
|
attr:
|
|
If a list of package attributes is specified, returned value will
|
|
contain them in addition to version, eg.::
|
|
@@ -770,10 +805,14 @@ def list_pkgs(versions_as_list=False, **kwargs):
|
|
|
|
contextkey = 'pkg.list_pkgs'
|
|
|
|
+ # TODO(aplanas): this cached value depends on the parameters
|
|
if contextkey not in __context__:
|
|
ret = {}
|
|
- cmd = ['rpm', '-qa', '--queryformat',
|
|
- salt.utils.pkg.rpm.QUERYFORMAT.replace('%{REPOID}', '(none)') + '\n']
|
|
+ cmd = ['rpm']
|
|
+ if root:
|
|
+ cmd.extend(['--root', root])
|
|
+ cmd.extend(['-qa', '--queryformat',
|
|
+ salt.utils.pkg.rpm.QUERYFORMAT.replace('%{REPOID}', '(none)') + '\n'])
|
|
output = __salt__['cmd.run'](cmd,
|
|
python_shell=False,
|
|
output_loglevel='trace')
|
|
@@ -859,6 +898,9 @@ def list_repo_pkgs(*args, **kwargs):
|
|
When ``True``, the return data for each package will be organized by
|
|
repository.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -891,7 +933,8 @@ def list_repo_pkgs(*args, **kwargs):
|
|
return True
|
|
return False
|
|
|
|
- for node in __zypper__.xml.call('se', '-s', *targets).getElementsByTagName('solvable'):
|
|
+ root = kwargs.get('root') or None
|
|
+ for node in __zypper__(root=root).xml.call('se', '-s', *targets).getElementsByTagName('solvable'):
|
|
pkginfo = dict(node.attributes.items())
|
|
try:
|
|
if pkginfo['kind'] != 'package':
|
|
@@ -933,23 +976,27 @@ def list_repo_pkgs(*args, **kwargs):
|
|
return byrepo_ret
|
|
|
|
|
|
-def _get_configured_repos():
|
|
+def _get_configured_repos(root=None):
|
|
'''
|
|
Get all the info about repositories from the configurations.
|
|
'''
|
|
|
|
+ repos = os.path.join(root, os.path.relpath(REPOS, os.path.sep)) if root else REPOS
|
|
repos_cfg = configparser.ConfigParser()
|
|
- repos_cfg.read([REPOS + '/' + fname for fname in os.listdir(REPOS) if fname.endswith(".repo")])
|
|
+ if os.path.exists(repos):
|
|
+ repos_cfg.read([repos + '/' + fname for fname in os.listdir(repos) if fname.endswith(".repo")])
|
|
+ else:
|
|
+ log.error('Repositories not found in {}'.format(repos))
|
|
|
|
return repos_cfg
|
|
|
|
|
|
-def _get_repo_info(alias, repos_cfg=None):
|
|
+def _get_repo_info(alias, repos_cfg=None, root=None):
|
|
'''
|
|
Get one repo meta-data.
|
|
'''
|
|
try:
|
|
- meta = dict((repos_cfg or _get_configured_repos()).items(alias))
|
|
+ meta = dict((repos_cfg or _get_configured_repos(root=root)).items(alias))
|
|
meta['alias'] = alias
|
|
for key, val in six.iteritems(meta):
|
|
if val in ['0', '1']:
|
|
@@ -961,51 +1008,60 @@ def _get_repo_info(alias, repos_cfg=None):
|
|
return {}
|
|
|
|
|
|
-def get_repo(repo, **kwargs): # pylint: disable=unused-argument
|
|
+def get_repo(repo, root=None, **kwargs): # pylint: disable=unused-argument
|
|
'''
|
|
Display a repo.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
|
|
salt '*' pkg.get_repo alias
|
|
'''
|
|
- return _get_repo_info(repo)
|
|
+ return _get_repo_info(repo, root=root)
|
|
|
|
|
|
-def list_repos():
|
|
+def list_repos(root=None):
|
|
'''
|
|
Lists all repos.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
|
|
salt '*' pkg.list_repos
|
|
'''
|
|
- repos_cfg = _get_configured_repos()
|
|
+ repos_cfg = _get_configured_repos(root=root)
|
|
all_repos = {}
|
|
for alias in repos_cfg.sections():
|
|
- all_repos[alias] = _get_repo_info(alias, repos_cfg=repos_cfg)
|
|
+ all_repos[alias] = _get_repo_info(alias, repos_cfg=repos_cfg, root=root)
|
|
|
|
return all_repos
|
|
|
|
|
|
-def del_repo(repo):
|
|
+def del_repo(repo, root=None):
|
|
'''
|
|
Delete a repo.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
|
|
salt '*' pkg.del_repo alias
|
|
'''
|
|
- repos_cfg = _get_configured_repos()
|
|
+ repos_cfg = _get_configured_repos(root=root)
|
|
for alias in repos_cfg.sections():
|
|
if alias == repo:
|
|
- doc = __zypper__.xml.call('rr', '--loose-auth', '--loose-query', alias)
|
|
+ doc = __zypper__(root=root).xml.call('rr', '--loose-auth', '--loose-query', alias)
|
|
msg = doc.getElementsByTagName('message')
|
|
if doc.getElementsByTagName('progress') and msg:
|
|
return {
|
|
@@ -1044,6 +1100,9 @@ def mod_repo(repo, **kwargs):
|
|
If set to True, automatically trust and import public GPG key for
|
|
the repository.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
Key/Value pairs may also be removed from a repo's configuration by setting
|
|
a key to a blank value. Bear in mind that a name cannot be deleted, and a
|
|
URL can only be deleted if a ``mirrorlist`` is specified (or vice versa).
|
|
@@ -1056,7 +1115,8 @@ def mod_repo(repo, **kwargs):
|
|
salt '*' pkg.mod_repo alias url= mirrorlist=http://host.com/
|
|
'''
|
|
|
|
- repos_cfg = _get_configured_repos()
|
|
+ root = kwargs.get('root') or None
|
|
+ repos_cfg = _get_configured_repos(root=root)
|
|
added = False
|
|
|
|
# An attempt to add new one?
|
|
@@ -1076,7 +1136,7 @@ def mod_repo(repo, **kwargs):
|
|
|
|
# Is there already such repo under different alias?
|
|
for alias in repos_cfg.sections():
|
|
- repo_meta = _get_repo_info(alias, repos_cfg=repos_cfg)
|
|
+ repo_meta = _get_repo_info(alias, repos_cfg=repos_cfg, root=root)
|
|
|
|
# Complete user URL, in case it is not
|
|
new_url = _urlparse(url)
|
|
@@ -1098,17 +1158,17 @@ def mod_repo(repo, **kwargs):
|
|
)
|
|
|
|
# Add new repo
|
|
- __zypper__.xml.call('ar', url, repo)
|
|
+ __zypper__(root=root).xml.call('ar', url, repo)
|
|
|
|
# Verify the repository has been added
|
|
- repos_cfg = _get_configured_repos()
|
|
+ repos_cfg = _get_configured_repos(root=root)
|
|
if repo not in repos_cfg.sections():
|
|
raise CommandExecutionError(
|
|
'Failed add new repository \'{0}\' for unspecified reason. '
|
|
'Please check zypper logs.'.format(repo))
|
|
added = True
|
|
|
|
- repo_info = _get_repo_info(repo)
|
|
+ repo_info = _get_repo_info(repo, root=root)
|
|
if (
|
|
not added and 'baseurl' in kwargs and
|
|
not (kwargs['baseurl'] == repo_info['baseurl'])
|
|
@@ -1117,8 +1177,8 @@ def mod_repo(repo, **kwargs):
|
|
# we need to remove the repository and add it again with the new baseurl
|
|
repo_info.update(kwargs)
|
|
repo_info.setdefault('cache', False)
|
|
- del_repo(repo)
|
|
- return mod_repo(repo, **repo_info)
|
|
+ del_repo(repo, root=root)
|
|
+ return mod_repo(repo, root=root, **repo_info)
|
|
|
|
# Modify added or existing repo according to the options
|
|
cmd_opt = []
|
|
@@ -1151,7 +1211,7 @@ def mod_repo(repo, **kwargs):
|
|
|
|
if cmd_opt:
|
|
cmd_opt = global_cmd_opt + ['mr'] + cmd_opt + [repo]
|
|
- __zypper__.refreshable.xml.call(*cmd_opt)
|
|
+ __zypper__(root=root).refreshable.xml.call(*cmd_opt)
|
|
|
|
comment = None
|
|
if call_refresh:
|
|
@@ -1159,23 +1219,26 @@ def mod_repo(repo, **kwargs):
|
|
# --gpg-auto-import-keys is not doing anything
|
|
# so we need to specifically refresh here with --gpg-auto-import-keys
|
|
refresh_opts = global_cmd_opt + ['refresh'] + [repo]
|
|
- __zypper__.xml.call(*refresh_opts)
|
|
+ __zypper__(root=root).xml.call(*refresh_opts)
|
|
elif not added and not cmd_opt:
|
|
comment = 'Specified arguments did not result in modification of repo'
|
|
|
|
- repo = get_repo(repo)
|
|
+ repo = get_repo(repo, root=root)
|
|
if comment:
|
|
repo['comment'] = comment
|
|
|
|
return repo
|
|
|
|
|
|
-def refresh_db():
|
|
+def refresh_db(root=None):
|
|
'''
|
|
Force a repository refresh by calling ``zypper refresh --force``, return a dict::
|
|
|
|
{'<database name>': Bool}
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
@@ -1185,7 +1248,7 @@ def refresh_db():
|
|
# Remove rtag file to keep multiple refreshes from happening in pkg states
|
|
salt.utils.pkg.clear_rtag(__opts__)
|
|
ret = {}
|
|
- out = __zypper__.refreshable.call('refresh', '--force')
|
|
+ out = __zypper__(root=root).refreshable.call('refresh', '--force')
|
|
|
|
for line in out.splitlines():
|
|
if not line:
|
|
@@ -1213,6 +1276,8 @@ def install(name=None,
|
|
skip_verify=False,
|
|
version=None,
|
|
ignore_repo_failure=False,
|
|
+ no_recommends=False,
|
|
+ root=None,
|
|
**kwargs):
|
|
'''
|
|
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
|
|
@@ -1301,6 +1366,12 @@ def install(name=None,
|
|
Zypper returns error code 106 if one of the repositories are not available for various reasons.
|
|
In case to set strict check, this parameter needs to be set to True. Default: False.
|
|
|
|
+ no_recommends
|
|
+ Do not install recommended packages, only required ones.
|
|
+
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
diff_attr:
|
|
If a list of package attributes is specified, returned value will
|
|
contain them, eg.::
|
|
@@ -1340,7 +1411,7 @@ def install(name=None,
|
|
'arch': '<new-arch>'}}}
|
|
'''
|
|
if refresh:
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
try:
|
|
pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](name, pkgs, sources, **kwargs)
|
|
@@ -1350,7 +1421,7 @@ def install(name=None,
|
|
if pkg_params is None or len(pkg_params) == 0:
|
|
return {}
|
|
|
|
- version_num = Wildcard(__zypper__)(name, version)
|
|
+ version_num = Wildcard(__zypper__(root=root))(name, version)
|
|
|
|
if version_num:
|
|
if pkgs is None and sources is None:
|
|
@@ -1375,7 +1446,7 @@ def install(name=None,
|
|
targets.append(target)
|
|
elif pkg_type == 'advisory':
|
|
targets = []
|
|
- cur_patches = list_patches()
|
|
+ cur_patches = list_patches(root=root)
|
|
for advisory_id in pkg_params:
|
|
if advisory_id not in cur_patches:
|
|
raise CommandExecutionError('Advisory id "{0}" not found'.format(advisory_id))
|
|
@@ -1385,7 +1456,7 @@ def install(name=None,
|
|
targets = pkg_params
|
|
|
|
diff_attr = kwargs.get("diff_attr")
|
|
- old = list_pkgs(attr=diff_attr) if not downloadonly else list_downloaded()
|
|
+ old = list_pkgs(attr=diff_attr, root=root) if not downloadonly else list_downloaded(root)
|
|
downgrades = []
|
|
if fromrepo:
|
|
fromrepoopt = ['--force', '--force-resolution', '--from', fromrepo]
|
|
@@ -1404,6 +1475,8 @@ def install(name=None,
|
|
cmd_install.append('--download-only')
|
|
if fromrepo:
|
|
cmd_install.extend(fromrepoopt)
|
|
+ if no_recommends:
|
|
+ cmd_install.append('--no-recommends')
|
|
|
|
errors = []
|
|
if pkg_type == 'advisory':
|
|
@@ -1415,7 +1488,7 @@ def install(name=None,
|
|
while targets:
|
|
cmd = cmd_install + targets[:500]
|
|
targets = targets[500:]
|
|
- for line in __zypper__(no_repo_failure=ignore_repo_failure, systemd_scope=systemd_scope).call(*cmd).splitlines():
|
|
+ for line in __zypper__(no_repo_failure=ignore_repo_failure, systemd_scope=systemd_scope, root=root).call(*cmd).splitlines():
|
|
match = re.match(r"^The selected package '([^']+)'.+has lower version", line)
|
|
if match:
|
|
downgrades.append(match.group(1))
|
|
@@ -1423,10 +1496,10 @@ def install(name=None,
|
|
while downgrades:
|
|
cmd = cmd_install + ['--force'] + downgrades[:500]
|
|
downgrades = downgrades[500:]
|
|
- __zypper__(no_repo_failure=ignore_repo_failure).call(*cmd)
|
|
+ __zypper__(no_repo_failure=ignore_repo_failure, root=root).call(*cmd)
|
|
|
|
_clean_cache()
|
|
- new = list_pkgs(attr=diff_attr) if not downloadonly else list_downloaded()
|
|
+ new = list_pkgs(attr=diff_attr, root=root) if not downloadonly else list_downloaded(root)
|
|
ret = salt.utils.data.compare_dicts(old, new)
|
|
|
|
if errors:
|
|
@@ -1446,6 +1519,8 @@ def upgrade(refresh=True,
|
|
fromrepo=None,
|
|
novendorchange=False,
|
|
skip_verify=False,
|
|
+ no_recommends=False,
|
|
+ root=None,
|
|
**kwargs): # pylint: disable=unused-argument
|
|
'''
|
|
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
|
|
@@ -1485,6 +1560,12 @@ def upgrade(refresh=True,
|
|
skip_verify
|
|
Skip the GPG verification check (e.g., ``--no-gpg-checks``)
|
|
|
|
+ no_recommends
|
|
+ Do not install recommended packages, only required ones.
|
|
+
|
|
+ root
|
|
+ Operate on a different root directory.
|
|
+
|
|
Returns a dictionary containing the changes:
|
|
|
|
.. code-block:: python
|
|
@@ -1507,7 +1588,7 @@ def upgrade(refresh=True,
|
|
cmd_update.insert(0, '--no-gpg-checks')
|
|
|
|
if refresh:
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
if dryrun:
|
|
cmd_update.append('--dry-run')
|
|
@@ -1526,16 +1607,20 @@ def upgrade(refresh=True,
|
|
else:
|
|
log.warning('Disabling vendor changes is not supported on this Zypper version')
|
|
|
|
+ if no_recommends:
|
|
+ cmd_update.append('--no-recommends')
|
|
+ log.info('Disabling recommendations')
|
|
+
|
|
if dryrun:
|
|
# Creates a solver test case for debugging.
|
|
log.info('Executing debugsolver and performing a dry-run dist-upgrade')
|
|
- __zypper__(systemd_scope=_systemd_scope()).noraise.call(*cmd_update + ['--debug-solver'])
|
|
+ __zypper__(systemd_scope=_systemd_scope(), root=root).noraise.call(*cmd_update + ['--debug-solver'])
|
|
|
|
- old = list_pkgs()
|
|
+ old = list_pkgs(root=root)
|
|
|
|
- __zypper__(systemd_scope=_systemd_scope()).noraise.call(*cmd_update)
|
|
+ __zypper__(systemd_scope=_systemd_scope(), root=root).noraise.call(*cmd_update)
|
|
_clean_cache()
|
|
- new = list_pkgs()
|
|
+ new = list_pkgs(root=root)
|
|
ret = salt.utils.data.compare_dicts(old, new)
|
|
|
|
if __zypper__.exit_code not in __zypper__.SUCCESS_EXIT_CODES:
|
|
@@ -1556,7 +1641,7 @@ def upgrade(refresh=True,
|
|
return ret
|
|
|
|
|
|
-def _uninstall(name=None, pkgs=None):
|
|
+def _uninstall(name=None, pkgs=None, root=None):
|
|
'''
|
|
Remove and purge do identical things but with different Zypper commands,
|
|
this function performs the common logic.
|
|
@@ -1566,7 +1651,7 @@ def _uninstall(name=None, pkgs=None):
|
|
except MinionError as exc:
|
|
raise CommandExecutionError(exc)
|
|
|
|
- old = list_pkgs()
|
|
+ old = list_pkgs(root=root)
|
|
targets = []
|
|
for target in pkg_params:
|
|
# Check if package version set to be removed is actually installed:
|
|
@@ -1582,11 +1667,11 @@ def _uninstall(name=None, pkgs=None):
|
|
|
|
errors = []
|
|
while targets:
|
|
- __zypper__(systemd_scope=systemd_scope).call('remove', *targets[:500])
|
|
+ __zypper__(systemd_scope=systemd_scope, root=root).call('remove', *targets[:500])
|
|
targets = targets[500:]
|
|
|
|
_clean_cache()
|
|
- ret = salt.utils.data.compare_dicts(old, list_pkgs())
|
|
+ ret = salt.utils.data.compare_dicts(old, list_pkgs(root=root))
|
|
|
|
if errors:
|
|
raise CommandExecutionError(
|
|
@@ -1623,7 +1708,7 @@ def normalize_name(name):
|
|
return name
|
|
|
|
|
|
-def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
|
|
+def remove(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused-argument
|
|
'''
|
|
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
|
|
On minions running systemd>=205, `systemd-run(1)`_ is now used to
|
|
@@ -1651,6 +1736,9 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
|
|
A list of packages to delete. Must be passed as a python list. The
|
|
``name`` parameter will be ignored if this option is passed.
|
|
|
|
+ root
|
|
+ Operate on a different root directory.
|
|
+
|
|
.. versionadded:: 0.16.0
|
|
|
|
|
|
@@ -1664,10 +1752,10 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
|
|
salt '*' pkg.remove <package1>,<package2>,<package3>
|
|
salt '*' pkg.remove pkgs='["foo", "bar"]'
|
|
'''
|
|
- return _uninstall(name=name, pkgs=pkgs)
|
|
+ return _uninstall(name=name, pkgs=pkgs, root=root)
|
|
|
|
|
|
-def purge(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
|
|
+def purge(name=None, pkgs=None, root=None, **kwargs): # pylint: disable=unused-argument
|
|
'''
|
|
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
|
|
On minions running systemd>=205, `systemd-run(1)`_ is now used to
|
|
@@ -1696,6 +1784,9 @@ def purge(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
|
|
A list of packages to delete. Must be passed as a python list. The
|
|
``name`` parameter will be ignored if this option is passed.
|
|
|
|
+ root
|
|
+ Operate on a different root directory.
|
|
+
|
|
.. versionadded:: 0.16.0
|
|
|
|
|
|
@@ -1709,13 +1800,16 @@ def purge(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
|
|
salt '*' pkg.purge <package1>,<package2>,<package3>
|
|
salt '*' pkg.purge pkgs='["foo", "bar"]'
|
|
'''
|
|
- return _uninstall(name=name, pkgs=pkgs)
|
|
+ return _uninstall(name=name, pkgs=pkgs, root=root)
|
|
|
|
|
|
-def list_locks():
|
|
+def list_locks(root=None):
|
|
'''
|
|
List current package locks.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
Return a dict containing the locked package with attributes::
|
|
|
|
{'<package>': {'case_sensitive': '<case_sensitive>',
|
|
@@ -1729,8 +1823,9 @@ def list_locks():
|
|
salt '*' pkg.list_locks
|
|
'''
|
|
locks = {}
|
|
- if os.path.exists(LOCKS):
|
|
- with salt.utils.files.fopen(LOCKS) as fhr:
|
|
+ _locks = os.path.join(root, os.path.relpath(LOCKS, os.path.sep)) if root else LOCKS
|
|
+ try:
|
|
+ with salt.utils.files.fopen(_locks) as fhr:
|
|
items = salt.utils.stringutils.to_unicode(fhr.read()).split('\n\n')
|
|
for meta in [item.split('\n') for item in items]:
|
|
lock = {}
|
|
@@ -1739,15 +1834,22 @@ def list_locks():
|
|
lock.update(dict([tuple([i.strip() for i in element.split(':', 1)]), ]))
|
|
if lock.get('solvable_name'):
|
|
locks[lock.pop('solvable_name')] = lock
|
|
+ except IOError:
|
|
+ pass
|
|
+ except Exception:
|
|
+ log.warning('Detected a problem when accessing {}'.format(_locks))
|
|
|
|
return locks
|
|
|
|
|
|
-def clean_locks():
|
|
+def clean_locks(root=None):
|
|
'''
|
|
Remove unused locks that do not currently (with regard to repositories
|
|
used) lock any package.
|
|
|
|
+ root
|
|
+ Operate on a different root directory.
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
@@ -1756,10 +1858,11 @@ def clean_locks():
|
|
'''
|
|
LCK = "removed"
|
|
out = {LCK: 0}
|
|
- if not os.path.exists("/etc/zypp/locks"):
|
|
+ locks = os.path.join(root, os.path.relpath(LOCKS, os.path.sep)) if root else LOCKS
|
|
+ if not os.path.exists(locks):
|
|
return out
|
|
|
|
- for node in __zypper__.xml.call('cl').getElementsByTagName("message"):
|
|
+ for node in __zypper__(root=root).xml.call('cl').getElementsByTagName("message"):
|
|
text = node.childNodes[0].nodeValue.lower()
|
|
if text.startswith(LCK):
|
|
out[LCK] = text.split(" ")[1]
|
|
@@ -1772,6 +1875,9 @@ def unhold(name=None, pkgs=None, **kwargs):
|
|
'''
|
|
Remove specified package lock.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
@@ -1781,12 +1887,13 @@ def unhold(name=None, pkgs=None, **kwargs):
|
|
salt '*' pkg.remove_lock pkgs='["foo", "bar"]'
|
|
'''
|
|
ret = {}
|
|
+ root = kwargs.get('root')
|
|
if (not name and not pkgs) or (name and pkgs):
|
|
raise CommandExecutionError('Name or packages must be specified.')
|
|
elif name:
|
|
pkgs = [name]
|
|
|
|
- locks = list_locks()
|
|
+ locks = list_locks(root)
|
|
try:
|
|
pkgs = list(__salt__['pkg_resource.parse_targets'](pkgs)[0].keys())
|
|
except MinionError as exc:
|
|
@@ -1803,12 +1910,12 @@ def unhold(name=None, pkgs=None, **kwargs):
|
|
ret[pkg]['comment'] = 'Package {0} unable to be unheld.'.format(pkg)
|
|
|
|
if removed:
|
|
- __zypper__.call('rl', *removed)
|
|
+ __zypper__(root=root).call('rl', *removed)
|
|
|
|
return ret
|
|
|
|
|
|
-def remove_lock(packages, **kwargs): # pylint: disable=unused-argument
|
|
+def remove_lock(packages, root=None, **kwargs): # pylint: disable=unused-argument
|
|
'''
|
|
Remove specified package lock.
|
|
|
|
@@ -1821,7 +1928,7 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument
|
|
salt '*' pkg.remove_lock pkgs='["foo", "bar"]'
|
|
'''
|
|
salt.utils.versions.warn_until('Sodium', 'This function is deprecated. Please use unhold() instead.')
|
|
- locks = list_locks()
|
|
+ locks = list_locks(root)
|
|
try:
|
|
packages = list(__salt__['pkg_resource.parse_targets'](packages)[0].keys())
|
|
except MinionError as exc:
|
|
@@ -1836,7 +1943,7 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument
|
|
missing.append(pkg)
|
|
|
|
if removed:
|
|
- __zypper__.call('rl', *removed)
|
|
+ __zypper__(root=root).call('rl', *removed)
|
|
|
|
return {'removed': len(removed), 'not_found': missing}
|
|
|
|
@@ -1859,12 +1966,13 @@ def hold(name=None, pkgs=None, **kwargs):
|
|
:return:
|
|
'''
|
|
ret = {}
|
|
+ root = kwargs.get('root')
|
|
if (not name and not pkgs) or (name and pkgs):
|
|
raise CommandExecutionError('Name or packages must be specified.')
|
|
elif name:
|
|
pkgs = [name]
|
|
|
|
- locks = list_locks()
|
|
+ locks = list_locks(root=root)
|
|
added = []
|
|
try:
|
|
pkgs = list(__salt__['pkg_resource.parse_targets'](pkgs)[0].keys())
|
|
@@ -1880,15 +1988,18 @@ def hold(name=None, pkgs=None, **kwargs):
|
|
ret[pkg]['comment'] = 'Package {0} is already set to be held.'.format(pkg)
|
|
|
|
if added:
|
|
- __zypper__.call('al', *added)
|
|
+ __zypper__(root=root).call('al', *added)
|
|
|
|
return ret
|
|
|
|
|
|
-def add_lock(packages, **kwargs): # pylint: disable=unused-argument
|
|
+def add_lock(packages, root=None, **kwargs): # pylint: disable=unused-argument
|
|
'''
|
|
Add a package lock. Specify packages to lock by exact name.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
@@ -1898,7 +2009,7 @@ def add_lock(packages, **kwargs): # pylint: disable=unused-argument
|
|
salt '*' pkg.add_lock pkgs='["foo", "bar"]'
|
|
'''
|
|
salt.utils.versions.warn_until('Sodium', 'This function is deprecated. Please use hold() instead.')
|
|
- locks = list_locks()
|
|
+ locks = list_locks(root)
|
|
added = []
|
|
try:
|
|
packages = list(__salt__['pkg_resource.parse_targets'](packages)[0].keys())
|
|
@@ -1910,7 +2021,7 @@ def add_lock(packages, **kwargs): # pylint: disable=unused-argument
|
|
added.append(pkg)
|
|
|
|
if added:
|
|
- __zypper__.call('al', *added)
|
|
+ __zypper__(root=root).call('al', *added)
|
|
|
|
return {'added': len(added), 'packages': added}
|
|
|
|
@@ -1920,7 +2031,9 @@ def verify(*names, **kwargs):
|
|
Runs an rpm -Va on a system, and returns the results in a dict
|
|
|
|
Files with an attribute of config, doc, ghost, license or readme in the
|
|
- package header can be ignored using the ``ignore_types`` keyword argument
|
|
+ package header can be ignored using the ``ignore_types`` keyword argument.
|
|
+
|
|
+ The root parameter can also be passed via the keyword argument.
|
|
|
|
CLI Example:
|
|
|
|
@@ -1934,12 +2047,14 @@ def verify(*names, **kwargs):
|
|
return __salt__['lowpkg.verify'](*names, **kwargs)
|
|
|
|
|
|
-def file_list(*packages):
|
|
+def file_list(*packages, **kwargs):
|
|
'''
|
|
List the files that belong to a package. Not specifying any packages will
|
|
return a list of *every* file on the system's rpm database (not generally
|
|
recommended).
|
|
|
|
+ The root parameter can also be passed via the keyword argument.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -1948,15 +2063,17 @@ def file_list(*packages):
|
|
salt '*' pkg.file_list httpd postfix
|
|
salt '*' pkg.file_list
|
|
'''
|
|
- return __salt__['lowpkg.file_list'](*packages)
|
|
+ return __salt__['lowpkg.file_list'](*packages, **kwargs)
|
|
|
|
|
|
-def file_dict(*packages):
|
|
+def file_dict(*packages, **kwargs):
|
|
'''
|
|
List the files that belong to a package, grouped by package. Not
|
|
specifying any packages will return a list of *every* file on the system's
|
|
rpm database (not generally recommended).
|
|
|
|
+ The root parameter can also be passed via the keyword argument.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -1965,7 +2082,7 @@ def file_dict(*packages):
|
|
salt '*' pkg.file_list httpd postfix
|
|
salt '*' pkg.file_list
|
|
'''
|
|
- return __salt__['lowpkg.file_dict'](*packages)
|
|
+ return __salt__['lowpkg.file_dict'](*packages, **kwargs)
|
|
|
|
|
|
def modified(*packages, **flags):
|
|
@@ -2004,6 +2121,9 @@ def modified(*packages, **flags):
|
|
capabilities
|
|
Include only files where capabilities differ or not. Note: supported only on newer RPM versions.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -2017,7 +2137,7 @@ def modified(*packages, **flags):
|
|
return __salt__['lowpkg.modified'](*packages, **flags)
|
|
|
|
|
|
-def owner(*paths):
|
|
+def owner(*paths, **kwargs):
|
|
'''
|
|
Return the name of the package that owns the file. Multiple file paths can
|
|
be passed. If a single path is passed, a string will be returned,
|
|
@@ -2027,6 +2147,8 @@ def owner(*paths):
|
|
If the file is not owned by a package, or is not present on the minion,
|
|
then an empty string will be returned for that path.
|
|
|
|
+ The root parameter can also be passed via the keyword argument.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -2034,15 +2156,15 @@ def owner(*paths):
|
|
salt '*' pkg.owner /usr/bin/apachectl
|
|
salt '*' pkg.owner /usr/bin/apachectl /etc/httpd/conf/httpd.conf
|
|
'''
|
|
- return __salt__['lowpkg.owner'](*paths)
|
|
+ return __salt__['lowpkg.owner'](*paths, **kwargs)
|
|
|
|
|
|
-def _get_patterns(installed_only=None):
|
|
+def _get_patterns(installed_only=None, root=None):
|
|
'''
|
|
List all known patterns in repos.
|
|
'''
|
|
patterns = {}
|
|
- for element in __zypper__.nolock.xml.call('se', '-t', 'pattern').getElementsByTagName('solvable'):
|
|
+ for element in __zypper__(root=root).nolock.xml.call('se', '-t', 'pattern').getElementsByTagName('solvable'):
|
|
installed = element.getAttribute('status') == 'installed'
|
|
if (installed_only and installed) or not installed_only:
|
|
patterns[element.getAttribute('name')] = {
|
|
@@ -2053,7 +2175,7 @@ def _get_patterns(installed_only=None):
|
|
return patterns
|
|
|
|
|
|
-def list_patterns(refresh=False):
|
|
+def list_patterns(refresh=False, root=None):
|
|
'''
|
|
List all known patterns from available repos.
|
|
|
|
@@ -2062,6 +2184,9 @@ def list_patterns(refresh=False):
|
|
If set to False (default) it depends on zypper if a refresh is
|
|
executed.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -2069,27 +2194,30 @@ def list_patterns(refresh=False):
|
|
salt '*' pkg.list_patterns
|
|
'''
|
|
if refresh:
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
- return _get_patterns()
|
|
+ return _get_patterns(root=root)
|
|
|
|
|
|
-def list_installed_patterns():
|
|
+def list_installed_patterns(root=None):
|
|
'''
|
|
List installed patterns on the system.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
|
|
salt '*' pkg.list_installed_patterns
|
|
'''
|
|
- return _get_patterns(installed_only=True)
|
|
+ return _get_patterns(installed_only=True, root=root)
|
|
|
|
|
|
def search(criteria, refresh=False, **kwargs):
|
|
'''
|
|
- List known packags, available to the system.
|
|
+ List known packages, available to the system.
|
|
|
|
refresh
|
|
force a refresh if set to True.
|
|
@@ -2137,6 +2265,9 @@ def search(criteria, refresh=False, **kwargs):
|
|
details (bool)
|
|
Show version and repository
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -2157,8 +2288,11 @@ def search(criteria, refresh=False, **kwargs):
|
|
'not_installed_only': '-u',
|
|
'details': '--details'
|
|
}
|
|
+
|
|
+ root = kwargs.get('root', None)
|
|
+
|
|
if refresh:
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
cmd = ['search']
|
|
if kwargs.get('match') == 'exact':
|
|
@@ -2173,7 +2307,7 @@ def search(criteria, refresh=False, **kwargs):
|
|
cmd.append(ALLOWED_SEARCH_OPTIONS.get(opt))
|
|
|
|
cmd.append(criteria)
|
|
- solvables = __zypper__.nolock.noraise.xml.call(*cmd).getElementsByTagName('solvable')
|
|
+ solvables = __zypper__(root=root).nolock.noraise.xml.call(*cmd).getElementsByTagName('solvable')
|
|
if not solvables:
|
|
raise CommandExecutionError(
|
|
'No packages found matching \'{0}\''.format(criteria)
|
|
@@ -2202,7 +2336,7 @@ def _get_first_aggregate_text(node_list):
|
|
return '\n'.join(out)
|
|
|
|
|
|
-def list_products(all=False, refresh=False):
|
|
+def list_products(all=False, refresh=False, root=None):
|
|
'''
|
|
List all available or installed SUSE products.
|
|
|
|
@@ -2214,6 +2348,9 @@ def list_products(all=False, refresh=False):
|
|
If set to False (default) it depends on zypper if a refresh is
|
|
executed.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
Includes handling for OEM products, which read the OEM productline file
|
|
and overwrite the release value.
|
|
|
|
@@ -2225,10 +2362,12 @@ def list_products(all=False, refresh=False):
|
|
salt '*' pkg.list_products all=True
|
|
'''
|
|
if refresh:
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
ret = list()
|
|
- OEM_PATH = "/var/lib/suseRegister/OEM"
|
|
+ OEM_PATH = '/var/lib/suseRegister/OEM'
|
|
+ if root:
|
|
+ OEM_PATH = os.path.join(root, os.path.relpath(OEM_PATH, os.path.sep))
|
|
cmd = list()
|
|
if not all:
|
|
cmd.append('--disable-repos')
|
|
@@ -2236,7 +2375,7 @@ def list_products(all=False, refresh=False):
|
|
if not all:
|
|
cmd.append('-i')
|
|
|
|
- product_list = __zypper__.nolock.xml.call(*cmd).getElementsByTagName('product-list')
|
|
+ product_list = __zypper__(root=root).nolock.xml.call(*cmd).getElementsByTagName('product-list')
|
|
if not product_list:
|
|
return ret # No products found
|
|
|
|
@@ -2278,6 +2417,9 @@ def download(*packages, **kwargs):
|
|
If set to False (default) it depends on zypper if a refresh is
|
|
executed.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI example:
|
|
|
|
.. code-block:: bash
|
|
@@ -2288,12 +2430,14 @@ def download(*packages, **kwargs):
|
|
if not packages:
|
|
raise SaltInvocationError('No packages specified')
|
|
|
|
+ root = kwargs.get('root', None)
|
|
+
|
|
refresh = kwargs.get('refresh', False)
|
|
if refresh:
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
pkg_ret = {}
|
|
- for dld_result in __zypper__.xml.call('download', *packages).getElementsByTagName("download-result"):
|
|
+ for dld_result in __zypper__(root=root).xml.call('download', *packages).getElementsByTagName("download-result"):
|
|
repo = dld_result.getElementsByTagName("repository")[0]
|
|
path = dld_result.getElementsByTagName("localfile")[0].getAttribute("path")
|
|
pkg_info = {
|
|
@@ -2304,7 +2448,7 @@ def download(*packages, **kwargs):
|
|
key = _get_first_aggregate_text(
|
|
dld_result.getElementsByTagName('name')
|
|
)
|
|
- if __salt__['lowpkg.checksum'](pkg_info['path']):
|
|
+ if __salt__['lowpkg.checksum'](pkg_info['path'], root=root):
|
|
pkg_ret[key] = pkg_info
|
|
|
|
if pkg_ret:
|
|
@@ -2318,12 +2462,15 @@ def download(*packages, **kwargs):
|
|
)
|
|
|
|
|
|
-def list_downloaded():
|
|
+def list_downloaded(root=None):
|
|
'''
|
|
.. versionadded:: 2017.7.0
|
|
|
|
List prefetched packages downloaded by Zypper in the local disk.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI example:
|
|
|
|
.. code-block:: bash
|
|
@@ -2331,6 +2478,8 @@ def list_downloaded():
|
|
salt '*' pkg.list_downloaded
|
|
'''
|
|
CACHE_DIR = '/var/cache/zypp/packages/'
|
|
+ if root:
|
|
+ CACHE_DIR = os.path.join(root, os.path.relpath(CACHE_DIR, os.path.sep))
|
|
|
|
ret = {}
|
|
for root, dirnames, filenames in salt.utils.path.os_walk(CACHE_DIR):
|
|
@@ -2347,12 +2496,14 @@ def list_downloaded():
|
|
return ret
|
|
|
|
|
|
-def diff(*paths):
|
|
+def diff(*paths, **kwargs):
|
|
'''
|
|
Return a formatted diff between current files and original in a package.
|
|
NOTE: this function includes all files (configuration and not), but does
|
|
not work on binary content.
|
|
|
|
+ The root parameter can also be passed via the keyword argument.
|
|
+
|
|
:param path: Full path to the installed file
|
|
:return: Difference string or raises and exception if examined file is binary.
|
|
|
|
@@ -2366,7 +2517,7 @@ def diff(*paths):
|
|
|
|
pkg_to_paths = {}
|
|
for pth in paths:
|
|
- pth_pkg = __salt__['lowpkg.owner'](pth)
|
|
+ pth_pkg = __salt__['lowpkg.owner'](pth, **kwargs)
|
|
if not pth_pkg:
|
|
ret[pth] = os.path.exists(pth) and 'Not managed' or 'N/A'
|
|
else:
|
|
@@ -2375,7 +2526,7 @@ def diff(*paths):
|
|
pkg_to_paths[pth_pkg].append(pth)
|
|
|
|
if pkg_to_paths:
|
|
- local_pkgs = __salt__['pkg.download'](*pkg_to_paths.keys())
|
|
+ local_pkgs = __salt__['pkg.download'](*pkg_to_paths.keys(), **kwargs)
|
|
for pkg, files in six.iteritems(pkg_to_paths):
|
|
for path in files:
|
|
ret[path] = __salt__['lowpkg.diff'](
|
|
@@ -2386,12 +2537,12 @@ def diff(*paths):
|
|
return ret
|
|
|
|
|
|
-def _get_patches(installed_only=False):
|
|
+def _get_patches(installed_only=False, root=None):
|
|
'''
|
|
List all known patches in repos.
|
|
'''
|
|
patches = {}
|
|
- for element in __zypper__.nolock.xml.call('se', '-t', 'patch').getElementsByTagName('solvable'):
|
|
+ for element in __zypper__(root=root).nolock.xml.call('se', '-t', 'patch').getElementsByTagName('solvable'):
|
|
installed = element.getAttribute('status') == 'installed'
|
|
if (installed_only and installed) or not installed_only:
|
|
patches[element.getAttribute('name')] = {
|
|
@@ -2402,7 +2553,7 @@ def _get_patches(installed_only=False):
|
|
return patches
|
|
|
|
|
|
-def list_patches(refresh=False):
|
|
+def list_patches(refresh=False, root=None):
|
|
'''
|
|
.. versionadded:: 2017.7.0
|
|
|
|
@@ -2413,6 +2564,9 @@ def list_patches(refresh=False):
|
|
If set to False (default) it depends on zypper if a refresh is
|
|
executed.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -2420,33 +2574,39 @@ def list_patches(refresh=False):
|
|
salt '*' pkg.list_patches
|
|
'''
|
|
if refresh:
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
- return _get_patches()
|
|
+ return _get_patches(root=root)
|
|
|
|
|
|
-def list_installed_patches():
|
|
+def list_installed_patches(root=None):
|
|
'''
|
|
.. versionadded:: 2017.7.0
|
|
|
|
List installed advisory patches on the system.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
|
|
salt '*' pkg.list_installed_patches
|
|
'''
|
|
- return _get_patches(installed_only=True)
|
|
+ return _get_patches(installed_only=True, root=root)
|
|
|
|
|
|
-def list_provides(**kwargs):
|
|
+def list_provides(root=None, **kwargs):
|
|
'''
|
|
.. versionadded:: 2018.3.0
|
|
|
|
List package provides of installed packages as a dict.
|
|
{'<provided_name>': ['<package_name>', '<package_name>', ...]}
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
CLI Examples:
|
|
|
|
.. code-block:: bash
|
|
@@ -2455,7 +2615,10 @@ def list_provides(**kwargs):
|
|
'''
|
|
ret = __context__.get('pkg.list_provides')
|
|
if not ret:
|
|
- cmd = ['rpm', '-qa', '--queryformat', '%{PROVIDES}_|-%{NAME}\n']
|
|
+ cmd = ['rpm']
|
|
+ if root:
|
|
+ cmd.extend(['--root', root])
|
|
+ cmd.extend(['-qa', '--queryformat', '%{PROVIDES}_|-%{NAME}\n'])
|
|
ret = dict()
|
|
for line in __salt__['cmd.run'](cmd, output_loglevel='trace', python_shell=False).splitlines():
|
|
provide, realname = line.split('_|-')
|
|
@@ -2471,7 +2634,7 @@ def list_provides(**kwargs):
|
|
return ret
|
|
|
|
|
|
-def resolve_capabilities(pkgs, refresh, **kwargs):
|
|
+def resolve_capabilities(pkgs, refresh=False, root=None, **kwargs):
|
|
'''
|
|
.. versionadded:: 2018.3.0
|
|
|
|
@@ -2485,6 +2648,9 @@ def resolve_capabilities(pkgs, refresh, **kwargs):
|
|
If set to False (default) it depends on zypper if a refresh is
|
|
executed.
|
|
|
|
+ root
|
|
+ operate on a different root directory.
|
|
+
|
|
resolve_capabilities
|
|
If this option is set to True the input will be checked if
|
|
a package with this name exists. If not, this function will
|
|
@@ -2500,7 +2666,7 @@ def resolve_capabilities(pkgs, refresh, **kwargs):
|
|
salt '*' pkg.resolve_capabilities resolve_capabilities=True w3m_ssl
|
|
'''
|
|
if refresh:
|
|
- refresh_db()
|
|
+ refresh_db(root)
|
|
|
|
ret = list()
|
|
for pkg in pkgs:
|
|
@@ -2513,12 +2679,12 @@ def resolve_capabilities(pkgs, refresh, **kwargs):
|
|
|
|
if kwargs.get('resolve_capabilities', False):
|
|
try:
|
|
- search(name, match='exact')
|
|
+ search(name, root=root, match='exact')
|
|
except CommandExecutionError:
|
|
# no package this such a name found
|
|
# search for a package which provides this name
|
|
try:
|
|
- result = search(name, provides=True, match='exact')
|
|
+ result = search(name, root=root, provides=True, match='exact')
|
|
if len(result) == 1:
|
|
name = next(iter(result.keys()))
|
|
elif len(result) > 1:
|
|
diff --git a/salt/states/pkg.py b/salt/states/pkg.py
|
|
index 0aca1e0af8..22a97fe98c 100644
|
|
--- a/salt/states/pkg.py
|
|
+++ b/salt/states/pkg.py
|
|
@@ -241,7 +241,7 @@ def _fulfills_version_spec(versions, oper, desired_version,
|
|
return False
|
|
|
|
|
|
-def _find_unpurge_targets(desired):
|
|
+def _find_unpurge_targets(desired, **kwargs):
|
|
'''
|
|
Find packages which are marked to be purged but can't yet be removed
|
|
because they are dependencies for other installed packages. These are the
|
|
@@ -250,7 +250,7 @@ def _find_unpurge_targets(desired):
|
|
'''
|
|
return [
|
|
x for x in desired
|
|
- if x in __salt__['pkg.list_pkgs'](purge_desired=True)
|
|
+ if x in __salt__['pkg.list_pkgs'](purge_desired=True, **kwargs)
|
|
]
|
|
|
|
|
|
@@ -265,7 +265,7 @@ def _find_download_targets(name=None,
|
|
Inspect the arguments to pkg.downloaded and discover what packages need to
|
|
be downloaded. Return a dict of packages to download.
|
|
'''
|
|
- cur_pkgs = __salt__['pkg.list_downloaded']()
|
|
+ cur_pkgs = __salt__['pkg.list_downloaded'](**kwargs)
|
|
if pkgs:
|
|
to_download = _repack_pkgs(pkgs, normalize=normalize)
|
|
|
|
@@ -383,7 +383,7 @@ def _find_advisory_targets(name=None,
|
|
Inspect the arguments to pkg.patch_installed and discover what advisory
|
|
patches need to be installed. Return a dict of advisory patches to install.
|
|
'''
|
|
- cur_patches = __salt__['pkg.list_installed_patches']()
|
|
+ cur_patches = __salt__['pkg.list_installed_patches'](**kwargs)
|
|
if advisory_ids:
|
|
to_download = advisory_ids
|
|
else:
|
|
@@ -587,7 +587,7 @@ def _find_install_targets(name=None,
|
|
'minion log.'.format('pkgs' if pkgs
|
|
else 'sources')}
|
|
|
|
- to_unpurge = _find_unpurge_targets(desired)
|
|
+ to_unpurge = _find_unpurge_targets(desired, **kwargs)
|
|
else:
|
|
if salt.utils.platform.is_windows():
|
|
pkginfo = _get_package_info(name, saltenv=kwargs['saltenv'])
|
|
@@ -607,7 +607,7 @@ def _find_install_targets(name=None,
|
|
else:
|
|
desired = {name: version}
|
|
|
|
- to_unpurge = _find_unpurge_targets(desired)
|
|
+ to_unpurge = _find_unpurge_targets(desired, **kwargs)
|
|
|
|
# FreeBSD pkg supports `openjdk` and `java/openjdk7` package names
|
|
origin = bool(re.search('/', name))
|
|
@@ -766,7 +766,8 @@ def _find_install_targets(name=None,
|
|
verify_result = __salt__['pkg.verify'](
|
|
package_name,
|
|
ignore_types=ignore_types,
|
|
- verify_options=verify_options
|
|
+ verify_options=verify_options,
|
|
+ **kwargs
|
|
)
|
|
except (CommandExecutionError, SaltInvocationError) as exc:
|
|
failed_verify = exc.strerror
|
|
@@ -795,7 +796,9 @@ def _find_install_targets(name=None,
|
|
verify_result = __salt__['pkg.verify'](
|
|
package_name,
|
|
ignore_types=ignore_types,
|
|
- verify_options=verify_options)
|
|
+ verify_options=verify_options,
|
|
+ **kwargs
|
|
+ )
|
|
except (CommandExecutionError, SaltInvocationError) as exc:
|
|
failed_verify = exc.strerror
|
|
continue
|
|
@@ -1910,7 +1913,8 @@ def installed(
|
|
# have caught invalid arguments earlier.
|
|
verify_result = __salt__['pkg.verify'](reinstall_pkg,
|
|
ignore_types=ignore_types,
|
|
- verify_options=verify_options)
|
|
+ verify_options=verify_options,
|
|
+ **kwargs)
|
|
if verify_result:
|
|
failed.append(reinstall_pkg)
|
|
altered_files[reinstall_pkg] = verify_result
|
|
@@ -2098,7 +2102,7 @@ def downloaded(name,
|
|
'package(s): {0}'.format(exc)
|
|
return ret
|
|
|
|
- new_pkgs = __salt__['pkg.list_downloaded']()
|
|
+ new_pkgs = __salt__['pkg.list_downloaded'](**kwargs)
|
|
ok, failed = _verify_install(targets, new_pkgs, ignore_epoch=ignore_epoch)
|
|
|
|
if failed:
|
|
@@ -2974,7 +2978,7 @@ def uptodate(name, refresh=False, pkgs=None, **kwargs):
|
|
pkgs, refresh = _resolve_capabilities(pkgs, refresh=refresh, **kwargs)
|
|
try:
|
|
packages = __salt__['pkg.list_upgrades'](refresh=refresh, **kwargs)
|
|
- expected = {pkgname: {'new': pkgver, 'old': __salt__['pkg.version'](pkgname)}
|
|
+ expected = {pkgname: {'new': pkgver, 'old': __salt__['pkg.version'](pkgname, **kwargs)}
|
|
for pkgname, pkgver in six.iteritems(packages)}
|
|
if isinstance(pkgs, list):
|
|
packages = [pkg for pkg in packages if pkg in pkgs]
|
|
@@ -3156,7 +3160,7 @@ def group_installed(name, skip=None, include=None, **kwargs):
|
|
.format(name, exc))
|
|
return ret
|
|
|
|
- failed = [x for x in targets if x not in __salt__['pkg.list_pkgs']()]
|
|
+ failed = [x for x in targets if x not in __salt__['pkg.list_pkgs'](**kwargs)]
|
|
if failed:
|
|
ret['comment'] = (
|
|
'Failed to install the following packages: {0}'
|
|
diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py
|
|
index 4d5e9eea92..6d8e94aa18 100644
|
|
--- a/salt/states/pkgrepo.py
|
|
+++ b/salt/states/pkgrepo.py
|
|
@@ -393,10 +393,7 @@ def managed(name, ppa=None, **kwargs):
|
|
kwargs.pop(kwarg, None)
|
|
|
|
try:
|
|
- pre = __salt__['pkg.get_repo'](
|
|
- repo,
|
|
- ppa_auth=kwargs.get('ppa_auth', None)
|
|
- )
|
|
+ pre = __salt__['pkg.get_repo'](repo=repo, **kwargs)
|
|
except CommandExecutionError as exc:
|
|
ret['result'] = False
|
|
ret['comment'] = \
|
|
@@ -512,10 +509,7 @@ def managed(name, ppa=None, **kwargs):
|
|
return ret
|
|
|
|
try:
|
|
- post = __salt__['pkg.get_repo'](
|
|
- repo,
|
|
- ppa_auth=kwargs.get('ppa_auth', None)
|
|
- )
|
|
+ post = __salt__['pkg.get_repo'](repo=repo, **kwargs)
|
|
if pre:
|
|
for kwarg in sanitizedkwargs:
|
|
if post.get(kwarg) != pre.get(kwarg):
|
|
@@ -608,9 +602,7 @@ def absent(name, **kwargs):
|
|
return ret
|
|
|
|
try:
|
|
- repo = __salt__['pkg.get_repo'](
|
|
- name, ppa_auth=kwargs.get('ppa_auth', None)
|
|
- )
|
|
+ repo = __salt__['pkg.get_repo'](name, **kwargs)
|
|
except CommandExecutionError as exc:
|
|
ret['result'] = False
|
|
ret['comment'] = \
|
|
diff --git a/tests/unit/modules/test_rpm_lowpkg.py b/tests/unit/modules/test_rpm_lowpkg.py
|
|
index 0a2359ccb2..dc9f52c572 100644
|
|
--- a/tests/unit/modules/test_rpm_lowpkg.py
|
|
+++ b/tests/unit/modules/test_rpm_lowpkg.py
|
|
@@ -20,6 +20,11 @@ from tests.support.mock import (
|
|
import salt.modules.rpm_lowpkg as rpm
|
|
|
|
|
|
+def _called_with_root(mock):
|
|
+ cmd = ' '.join(mock.call_args[0][0])
|
|
+ return cmd.startswith('rpm --root /')
|
|
+
|
|
+
|
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
|
class RpmTestCase(TestCase, LoaderModuleMockMixin):
|
|
'''
|
|
@@ -28,7 +33,7 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin):
|
|
def setup_loader_modules(self):
|
|
return {rpm: {'rpm': MagicMock(return_value=MagicMock)}}
|
|
|
|
- # 'list_pkgs' function tests: 1
|
|
+ # 'list_pkgs' function tests: 2
|
|
|
|
def test_list_pkgs(self):
|
|
'''
|
|
@@ -37,13 +42,24 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin):
|
|
mock = MagicMock(return_value='')
|
|
with patch.dict(rpm.__salt__, {'cmd.run': mock}):
|
|
self.assertDictEqual(rpm.list_pkgs(), {})
|
|
+ self.assertFalse(_called_with_root(mock))
|
|
+
|
|
+ def test_list_pkgs_root(self):
|
|
+ '''
|
|
+ Test if it list the packages currently installed in a dict,
|
|
+ called with root parameter
|
|
+ '''
|
|
+ mock = MagicMock(return_value='')
|
|
+ with patch.dict(rpm.__salt__, {'cmd.run': mock}):
|
|
+ rpm.list_pkgs(root='/')
|
|
+ self.assertTrue(_called_with_root(mock))
|
|
|
|
- # 'verify' function tests: 1
|
|
+ # 'verify' function tests: 2
|
|
|
|
def test_verify(self):
|
|
'''
|
|
- Test if it runs an rpm -Va on a system,
|
|
- and returns the results in a dict
|
|
+ Test if it runs an rpm -Va on a system, and returns the
|
|
+ results in a dict
|
|
'''
|
|
mock = MagicMock(return_value={'stdout': '',
|
|
'stderr': '',
|
|
@@ -51,8 +67,22 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin):
|
|
'pid': 12345})
|
|
with patch.dict(rpm.__salt__, {'cmd.run_all': mock}):
|
|
self.assertDictEqual(rpm.verify('httpd'), {})
|
|
+ self.assertFalse(_called_with_root(mock))
|
|
+
|
|
+ def test_verify_root(self):
|
|
+ '''
|
|
+ Test if it runs an rpm -Va on a system, and returns the
|
|
+ results in a dict, called with root parameter
|
|
+ '''
|
|
+ mock = MagicMock(return_value={'stdout': '',
|
|
+ 'stderr': '',
|
|
+ 'retcode': 0,
|
|
+ 'pid': 12345})
|
|
+ with patch.dict(rpm.__salt__, {'cmd.run_all': mock}):
|
|
+ rpm.verify('httpd', root='/')
|
|
+ self.assertTrue(_called_with_root(mock))
|
|
|
|
- # 'file_list' function tests: 1
|
|
+ # 'file_list' function tests: 2
|
|
|
|
def test_file_list(self):
|
|
'''
|
|
@@ -62,8 +92,20 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin):
|
|
with patch.dict(rpm.__salt__, {'cmd.run': mock}):
|
|
self.assertDictEqual(rpm.file_list('httpd'),
|
|
{'errors': [], 'files': []})
|
|
+ self.assertFalse(_called_with_root(mock))
|
|
|
|
- # 'file_dict' function tests: 1
|
|
+ def test_file_list_root(self):
|
|
+ '''
|
|
+ Test if it list the files that belong to a package, using the
|
|
+ root parameter.
|
|
+ '''
|
|
+
|
|
+ mock = MagicMock(return_value='')
|
|
+ with patch.dict(rpm.__salt__, {'cmd.run': mock}):
|
|
+ rpm.file_list('httpd', root='/')
|
|
+ self.assertTrue(_called_with_root(mock))
|
|
+
|
|
+ # 'file_dict' function tests: 2
|
|
|
|
def test_file_dict(self):
|
|
'''
|
|
@@ -73,6 +115,16 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin):
|
|
with patch.dict(rpm.__salt__, {'cmd.run': mock}):
|
|
self.assertDictEqual(rpm.file_dict('httpd'),
|
|
{'errors': [], 'packages': {}})
|
|
+ self.assertFalse(_called_with_root(mock))
|
|
+
|
|
+ def test_file_dict_root(self):
|
|
+ '''
|
|
+ Test if it list the files that belong to a package
|
|
+ '''
|
|
+ mock = MagicMock(return_value='')
|
|
+ with patch.dict(rpm.__salt__, {'cmd.run': mock}):
|
|
+ rpm.file_dict('httpd', root='/')
|
|
+ self.assertTrue(_called_with_root(mock))
|
|
|
|
# 'owner' function tests: 1
|
|
|
|
@@ -86,6 +138,7 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin):
|
|
mock = MagicMock(return_value=ret)
|
|
with patch.dict(rpm.__salt__, {'cmd.run_stdout': mock}):
|
|
self.assertEqual(rpm.owner('/usr/bin/salt-jenkins-build'), '')
|
|
+ self.assertFalse(_called_with_root(mock))
|
|
|
|
ret = {'/usr/bin/vim': 'vim-enhanced-7.4.160-1.e17.x86_64',
|
|
'/usr/bin/python': 'python-2.7.5-16.e17.x86_64'}
|
|
@@ -94,8 +147,22 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin):
|
|
with patch.dict(rpm.__salt__, {'cmd.run_stdout': mock}):
|
|
self.assertDictEqual(rpm.owner('/usr/bin/python', '/usr/bin/vim'),
|
|
ret)
|
|
+ self.assertFalse(_called_with_root(mock))
|
|
|
|
- # 'checksum' function tests: 1
|
|
+ def test_owner_root(self):
|
|
+ '''
|
|
+ Test if it return the name of the package that owns the file,
|
|
+ using the parameter root.
|
|
+ '''
|
|
+ self.assertEqual(rpm.owner(), '')
|
|
+
|
|
+ ret = 'file /usr/bin/salt-jenkins-build is not owned by any package'
|
|
+ mock = MagicMock(return_value=ret)
|
|
+ with patch.dict(rpm.__salt__, {'cmd.run_stdout': mock}):
|
|
+ rpm.owner('/usr/bin/salt-jenkins-build', root='/')
|
|
+ self.assertTrue(_called_with_root(mock))
|
|
+
|
|
+ # 'checksum' function tests: 2
|
|
|
|
def test_checksum(self):
|
|
'''
|
|
@@ -110,6 +177,17 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin):
|
|
mock = MagicMock(side_effect=[True, 0, True, 1, False, 0])
|
|
with patch.dict(rpm.__salt__, {'file.file_exists': mock, 'cmd.retcode': mock}):
|
|
self.assertDictEqual(rpm.checksum("file1.rpm", "file2.rpm", "file3.rpm"), ret)
|
|
+ self.assertFalse(_called_with_root(mock))
|
|
+
|
|
+ def test_checksum_root(self):
|
|
+ '''
|
|
+ Test if checksum validate as expected, using the parameter
|
|
+ root
|
|
+ '''
|
|
+ mock = MagicMock(side_effect=[True, 0])
|
|
+ with patch.dict(rpm.__salt__, {'file.file_exists': mock, 'cmd.retcode': mock}):
|
|
+ rpm.checksum("file1.rpm", root='/')
|
|
+ self.assertTrue(_called_with_root(mock))
|
|
|
|
def test_version_cmp_rpm(self):
|
|
'''
|
|
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
|
|
index f586c23fd0..e7474ff777 100644
|
|
--- a/tests/unit/modules/test_zypperpkg.py
|
|
+++ b/tests/unit/modules/test_zypperpkg.py
|
|
@@ -40,6 +40,9 @@ class ZyppCallMock(object):
|
|
return self
|
|
|
|
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')):
|
|
+ return self
|
|
return MagicMock(return_value=self.__return_value)()
|
|
|
|
|
|
@@ -925,7 +928,7 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
'pico': '0.1.1',
|
|
}
|
|
|
|
- def __call__(self):
|
|
+ def __call__(self, root=None):
|
|
pkgs = self._pkgs.copy()
|
|
for target in self._packages:
|
|
if self._pkgs.get(target):
|
|
@@ -991,10 +994,10 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{'url': url})
|
|
self.assertEqual(
|
|
- zypper.__zypper__.xml.call.call_args_list,
|
|
+ zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[call('ar', url, name)]
|
|
)
|
|
- self.assertTrue(zypper.__zypper__.refreshable.xml.call.call_count == 0)
|
|
+ self.assertTrue(zypper.__zypper__(root=None).refreshable.xml.call.call_count == 0)
|
|
|
|
def test_repo_noadd_nomod_noref(self):
|
|
'''
|
|
@@ -1016,8 +1019,8 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
self.assertEqual(
|
|
out['comment'],
|
|
'Specified arguments did not result in modification of repo')
|
|
- self.assertTrue(zypper.__zypper__.xml.call.call_count == 0)
|
|
- self.assertTrue(zypper.__zypper__.refreshable.xml.call.call_count == 0)
|
|
+ self.assertTrue(zypper.__zypper__(root=None).xml.call.call_count == 0)
|
|
+ self.assertTrue(zypper.__zypper__(root=None).refreshable.xml.call.call_count == 0)
|
|
|
|
def test_repo_noadd_modbaseurl_ref(self):
|
|
'''
|
|
@@ -1045,9 +1048,11 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
'priority': 1,
|
|
'cache': False,
|
|
'keeppackages': False,
|
|
- 'type': 'rpm-md'}
|
|
- self.assertTrue(zypper.mod_repo.call_count == 2)
|
|
- self.assertTrue(zypper.mod_repo.mock_calls[1] == call(name, **expected_params))
|
|
+ 'type': 'rpm-md',
|
|
+ 'root': None,
|
|
+ }
|
|
+ self.assertEqual(zypper.mod_repo.call_count, 2)
|
|
+ self.assertEqual(zypper.mod_repo.mock_calls[1], call(name, **expected_params))
|
|
|
|
def test_repo_add_mod_noref(self):
|
|
'''
|
|
@@ -1063,10 +1068,10 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{'url': url, 'refresh': True})
|
|
self.assertEqual(
|
|
- zypper.__zypper__.xml.call.call_args_list,
|
|
+ zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[call('ar', url, name)]
|
|
)
|
|
- zypper.__zypper__.refreshable.xml.call.assert_called_once_with(
|
|
+ zypper.__zypper__(root=None).refreshable.xml.call.assert_called_once_with(
|
|
'mr', '--refresh', name
|
|
)
|
|
|
|
@@ -1085,8 +1090,8 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
'salt.modules.zypperpkg', **self.zypper_patcher_config)
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{'url': url, 'refresh': True})
|
|
- self.assertTrue(zypper.__zypper__.xml.call.call_count == 0)
|
|
- zypper.__zypper__.refreshable.xml.call.assert_called_once_with(
|
|
+ self.assertTrue(zypper.__zypper__(root=None).xml.call.call_count == 0)
|
|
+ zypper.__zypper__(root=None).refreshable.xml.call.assert_called_once_with(
|
|
'mr', '--refresh', name
|
|
)
|
|
|
|
@@ -1105,13 +1110,13 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{'url': url, 'gpgautoimport': True})
|
|
self.assertEqual(
|
|
- zypper.__zypper__.xml.call.call_args_list,
|
|
+ zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[
|
|
call('ar', url, name),
|
|
call('--gpg-auto-import-keys', 'refresh', name)
|
|
]
|
|
)
|
|
- self.assertTrue(zypper.__zypper__.refreshable.xml.call.call_count == 0)
|
|
+ self.assertTrue(zypper.__zypper__(root=None).refreshable.xml.call.call_count == 0)
|
|
|
|
def test_repo_noadd_nomod_ref(self):
|
|
'''
|
|
@@ -1132,10 +1137,10 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{'url': url, 'gpgautoimport': True})
|
|
self.assertEqual(
|
|
- zypper.__zypper__.xml.call.call_args_list,
|
|
+ zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[call('--gpg-auto-import-keys', 'refresh', name)]
|
|
)
|
|
- self.assertTrue(zypper.__zypper__.refreshable.xml.call.call_count == 0)
|
|
+ self.assertTrue(zypper.__zypper__(root=None).refreshable.xml.call.call_count == 0)
|
|
|
|
def test_repo_add_mod_ref(self):
|
|
'''
|
|
@@ -1156,13 +1161,13 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
**{'url': url, 'refresh': True, 'gpgautoimport': True}
|
|
)
|
|
self.assertEqual(
|
|
- zypper.__zypper__.xml.call.call_args_list,
|
|
+ zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[
|
|
call('ar', url, name),
|
|
call('--gpg-auto-import-keys', 'refresh', name)
|
|
]
|
|
)
|
|
- zypper.__zypper__.refreshable.xml.call.assert_called_once_with(
|
|
+ zypper.__zypper__(root=None).refreshable.xml.call.assert_called_once_with(
|
|
'--gpg-auto-import-keys', 'mr', '--refresh', name
|
|
)
|
|
|
|
@@ -1188,10 +1193,10 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
|
**{'url': url, 'refresh': True, 'gpgautoimport': True}
|
|
)
|
|
self.assertEqual(
|
|
- zypper.__zypper__.xml.call.call_args_list,
|
|
+ zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[call('--gpg-auto-import-keys', 'refresh', name)]
|
|
)
|
|
- zypper.__zypper__.refreshable.xml.call.assert_called_once_with(
|
|
+ zypper.__zypper__(root=None).refreshable.xml.call.assert_called_once_with(
|
|
'--gpg-auto-import-keys', 'mr', '--refresh', name
|
|
)
|
|
|
|
diff --git a/tests/unit/states/test_pkg.py b/tests/unit/states/test_pkg.py
|
|
index 42fe6c6867..d30e064167 100644
|
|
--- a/tests/unit/states/test_pkg.py
|
|
+++ b/tests/unit/states/test_pkg.py
|
|
@@ -46,7 +46,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
|
|
pkgname: pkgver['new'] for pkgname, pkgver in six.iteritems(self.pkgs)
|
|
})
|
|
upgrade = MagicMock(return_value=self.pkgs)
|
|
- version = MagicMock(side_effect=lambda pkgname: self.pkgs[pkgname]['old'])
|
|
+ version = MagicMock(side_effect=lambda pkgname, **_: self.pkgs[pkgname]['old'])
|
|
|
|
with patch.dict(pkg.__salt__,
|
|
{'pkg.list_upgrades': list_upgrades,
|
|
@@ -55,7 +55,6 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
|
|
|
|
# Run state with test=false
|
|
with patch.dict(pkg.__opts__, {'test': False}):
|
|
-
|
|
ret = pkg.uptodate('dummy', test=True)
|
|
self.assertTrue(ret['result'])
|
|
self.assertDictEqual(ret['changes'], self.pkgs)
|
|
@@ -81,7 +80,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
|
|
pkgname: pkgver['new'] for pkgname, pkgver in six.iteritems(self.pkgs)
|
|
})
|
|
upgrade = MagicMock(return_value=self.pkgs)
|
|
- version = MagicMock(side_effect=lambda pkgname: pkgs[pkgname]['old'])
|
|
+ version = MagicMock(side_effect=lambda pkgname, **_: pkgs[pkgname]['old'])
|
|
|
|
with patch.dict(pkg.__salt__,
|
|
{'pkg.list_upgrades': list_upgrades,
|
|
@@ -160,7 +159,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
|
|
pkgname: pkgver['new'] for pkgname, pkgver in six.iteritems(self.pkgs)
|
|
})
|
|
upgrade = MagicMock(return_value={})
|
|
- version = MagicMock(side_effect=lambda pkgname: pkgs[pkgname]['old'])
|
|
+ version = MagicMock(side_effect=lambda pkgname, **_: pkgs[pkgname]['old'])
|
|
|
|
with patch.dict(pkg.__salt__,
|
|
{'pkg.list_upgrades': list_upgrades,
|
|
--
|
|
2.20.1
|
|
|
|
|