SHA256
1
0
forked from pool/salt
salt/add-hold-unhold-functions.patch

470 lines
17 KiB
Diff
Raw Normal View History

From 6176ef8aa39626dcb450a1665231a796e9544342 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Thu, 6 Dec 2018 16:26:23 +0100
Subject: [PATCH] Add hold/unhold functions
Add unhold function
Add warnings
---
salt/modules/zypperpkg.py | 186 +++++++++++++++++++++++++++-----------
1 file changed, 131 insertions(+), 55 deletions(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index 44bcbbf2f2..6fa6e3e0a1 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
Package support for openSUSE via the zypper package manager
@@ -12,8 +11,6 @@ Package support for openSUSE via the zypper package manager
"""
-# Import python libs
-from __future__ import absolute_import, print_function, unicode_literals
import datetime
import fnmatch
@@ -24,7 +21,6 @@ import time
from xml.dom import minidom as dom
from xml.parsers.expat import ExpatError
-# Import salt libs
import salt.utils.data
import salt.utils.environment
import salt.utils.event
@@ -35,9 +31,9 @@ import salt.utils.pkg
import salt.utils.pkg.rpm
import salt.utils.stringutils
import salt.utils.systemd
+import salt.utils.versions
from salt.exceptions import CommandExecutionError, MinionError, SaltInvocationError
-# Import 3rd-party libs
# pylint: disable=import-error,redefined-builtin,no-name-in-module
from salt.ext import six
from salt.ext.six.moves import configparser
@@ -51,8 +47,8 @@ log = logging.getLogger(__name__)
HAS_ZYPP = False
ZYPP_HOME = "/etc/zypp"
-LOCKS = "{0}/locks".format(ZYPP_HOME)
-REPOS = "{0}/repos.d".format(ZYPP_HOME)
+LOCKS = "{}/locks".format(ZYPP_HOME)
+REPOS = "{}/repos.d".format(ZYPP_HOME)
DEFAULT_PRIORITY = 99
PKG_ARCH_SEPARATOR = "."
@@ -75,7 +71,7 @@ def __virtual__():
return __virtualname__
-class _Zypper(object):
+class _Zypper:
"""
Zypper parallel caller.
Validates the result and either raises an exception or reports an error.
@@ -339,7 +335,7 @@ class _Zypper(object):
attrs=["pid", "name", "cmdline", "create_time"],
)
data["cmdline"] = " ".join(data["cmdline"])
- data["info"] = "Blocking process created at {0}.".format(
+ data["info"] = "Blocking process created at {}.".format(
datetime.datetime.utcfromtimestamp(
data["create_time"]
).isoformat()
@@ -347,7 +343,7 @@ class _Zypper(object):
data["success"] = True
except Exception as err: # pylint: disable=broad-except
data = {
- "info": "Unable to retrieve information about blocking process: {0}".format(
+ "info": "Unable to retrieve information about blocking process: {}".format(
err.message
),
"success": False,
@@ -382,7 +378,7 @@ class _Zypper(object):
)
if self.error_msg and not self.__no_raise and not self.__ignore_repo_failure:
raise CommandExecutionError(
- "Zypper command failure: {0}".format(self.error_msg)
+ "Zypper command failure: {}".format(self.error_msg)
)
return (
@@ -397,7 +393,7 @@ class _Zypper(object):
__zypper__ = _Zypper()
-class Wildcard(object):
+class Wildcard:
"""
.. versionadded:: 2017.7.0
@@ -439,7 +435,7 @@ class Wildcard(object):
for vrs in self._get_scope_versions(self._get_available_versions())
]
)
- return versions and "{0}{1}".format(self._op or "", versions[-1]) or None
+ return versions and "{}{}".format(self._op or "", versions[-1]) or None
def _get_available_versions(self):
"""
@@ -451,17 +447,15 @@ class Wildcard(object):
).getElementsByTagName("solvable")
if not solvables:
raise CommandExecutionError(
- "No packages found matching '{0}'".format(self.name)
+ "No packages found matching '{}'".format(self.name)
)
return sorted(
- set(
- [
- slv.getAttribute(self._attr_solvable_version)
- for slv in solvables
- if slv.getAttribute(self._attr_solvable_version)
- ]
- )
+ {
+ slv.getAttribute(self._attr_solvable_version)
+ for slv in solvables
+ if slv.getAttribute(self._attr_solvable_version)
+ }
)
def _get_scope_versions(self, pkg_versions):
@@ -489,7 +483,7 @@ class Wildcard(object):
self._op = version.replace(exact_version, "") or None
if self._op and self._op not in self.Z_OP:
raise CommandExecutionError(
- 'Zypper do not supports operator "{0}".'.format(self._op)
+ 'Zypper do not supports operator "{}".'.format(self._op)
)
self.version = exact_version
@@ -539,14 +533,11 @@ def list_upgrades(refresh=True, root=None, **kwargs):
cmd = ["list-updates"]
if "fromrepo" in kwargs:
repos = kwargs["fromrepo"]
- if isinstance(repos, six.string_types):
+ if isinstance(repos, str):
repos = [repos]
for repo in repos:
cmd.extend(
- [
- "--repo",
- repo if isinstance(repo, six.string_types) else six.text_type(repo),
- ]
+ ["--repo", repo if isinstance(repo, str) else str(repo),]
)
log.debug("Targeting repos: %s", repos)
for update_node in (
@@ -610,7 +601,7 @@ def info_installed(*names, **kwargs):
for _nfo in pkg_nfo:
t_nfo = dict()
# Translate dpkg-specific keys to a common structure
- for key, value in six.iteritems(_nfo):
+ for key, value in _nfo.items():
if key == "source_rpm":
t_nfo["source"] = value
else:
@@ -1033,9 +1024,7 @@ def list_repo_pkgs(*args, **kwargs):
fromrepo = kwargs.pop("fromrepo", "") or ""
ret = {}
- targets = [
- arg if isinstance(arg, six.string_types) else six.text_type(arg) for arg in args
- ]
+ targets = [arg if isinstance(arg, str) else str(arg) for arg in args]
def _is_match(pkgname):
"""
@@ -1124,7 +1113,7 @@ def _get_repo_info(alias, repos_cfg=None, root=None):
try:
meta = dict((repos_cfg or _get_configured_repos(root=root)).items(alias))
meta["alias"] = alias
- for key, val in six.iteritems(meta):
+ for key, val in meta.items():
if val in ["0", "1"]:
meta[key] = int(meta[key]) == 1
elif val == "NONE":
@@ -1197,7 +1186,7 @@ def del_repo(repo, root=None):
"message": msg[0].childNodes[0].nodeValue,
}
- raise CommandExecutionError("Repository '{0}' not found.".format(repo))
+ raise CommandExecutionError("Repository '{}' not found.".format(repo))
def mod_repo(repo, **kwargs):
@@ -1252,13 +1241,13 @@ def mod_repo(repo, **kwargs):
url = kwargs.get("url", kwargs.get("mirrorlist", kwargs.get("baseurl")))
if not url:
raise CommandExecutionError(
- "Repository '{0}' not found, and neither 'baseurl' nor "
+ "Repository '{}' not found, and neither 'baseurl' nor "
"'mirrorlist' was specified".format(repo)
)
if not _urlparse(url).scheme:
raise CommandExecutionError(
- "Repository '{0}' not found and URL for baseurl/mirrorlist "
+ "Repository '{}' not found and URL for baseurl/mirrorlist "
"is malformed".format(repo)
)
@@ -1281,7 +1270,7 @@ def mod_repo(repo, **kwargs):
if new_url == base_url:
raise CommandExecutionError(
- "Repository '{0}' already exists as '{1}'.".format(repo, alias)
+ "Repository '{}' already exists as '{}'.".format(repo, alias)
)
# Add new repo
@@ -1291,7 +1280,7 @@ def mod_repo(repo, **kwargs):
repos_cfg = _get_configured_repos(root=root)
if repo not in repos_cfg.sections():
raise CommandExecutionError(
- "Failed add new repository '{0}' for unspecified reason. "
+ "Failed add new repository '{}' for unspecified reason. "
"Please check zypper logs.".format(repo)
)
added = True
@@ -1327,12 +1316,10 @@ def mod_repo(repo, **kwargs):
cmd_opt.append(kwargs["gpgcheck"] and "--gpgcheck" or "--no-gpgcheck")
if "priority" in kwargs:
- cmd_opt.append(
- "--priority={0}".format(kwargs.get("priority", DEFAULT_PRIORITY))
- )
+ cmd_opt.append("--priority={}".format(kwargs.get("priority", DEFAULT_PRIORITY)))
if "humanname" in kwargs:
- cmd_opt.append("--name='{0}'".format(kwargs.get("humanname")))
+ cmd_opt.append("--name='{}'".format(kwargs.get("humanname")))
if kwargs.get("gpgautoimport") is True:
global_cmd_opt.append("--gpg-auto-import-keys")
@@ -1589,7 +1576,7 @@ def install(
if pkg_type == "repository":
targets = []
- for param, version_num in six.iteritems(pkg_params):
+ for param, version_num in pkg_params.items():
if version_num is None:
log.debug("targeting package: %s", param)
targets.append(param)
@@ -1597,7 +1584,7 @@ def install(
prefix, verstr = salt.utils.pkg.split_comparison(version_num)
if not prefix:
prefix = "="
- target = "{0}{1}{2}".format(param, prefix, verstr)
+ target = "{}{}{}".format(param, prefix, verstr)
log.debug("targeting package: %s", target)
targets.append(target)
elif pkg_type == "advisory":
@@ -1606,7 +1593,7 @@ def install(
for advisory_id in pkg_params:
if advisory_id not in cur_patches:
raise CommandExecutionError(
- 'Advisory id "{0}" not found'.format(advisory_id)
+ 'Advisory id "{}" not found'.format(advisory_id)
)
else:
# If we add here the `patch:` prefix, the
@@ -1703,7 +1690,7 @@ def install(
if errors:
raise CommandExecutionError(
- "Problem encountered {0} package(s)".format(
+ "Problem encountered {} package(s)".format(
"downloading" if downloadonly else "installing"
),
info={"errors": errors, "changes": ret},
@@ -1797,7 +1784,7 @@ def upgrade(
cmd_update.append("--dry-run")
if fromrepo:
- if isinstance(fromrepo, six.string_types):
+ if isinstance(fromrepo, str):
fromrepo = [fromrepo]
for repo in fromrepo:
cmd_update.extend(["--from" if dist_upgrade else "--repo", repo])
@@ -2052,7 +2039,7 @@ def list_locks(root=None):
)
if lock.get("solvable_name"):
locks[lock.pop("solvable_name")] = lock
- except IOError:
+ except OSError:
pass
except Exception: # pylint: disable=broad-except
log.warning("Detected a problem when accessing {}".format(_locks))
@@ -2089,7 +2076,7 @@ def clean_locks(root=None):
return out
-def remove_lock(packages, root=None, **kwargs): # pylint: disable=unused-argument
+def unhold(name=None, pkgs=None, **kwargs):
"""
Remove specified package lock.
@@ -2104,8 +2091,50 @@ def remove_lock(packages, root=None, **kwargs): # pylint: disable=unused-argume
salt '*' pkg.remove_lock <package1>,<package2>,<package3>
salt '*' pkg.remove_lock pkgs='["foo", "bar"]'
"""
+ ret = {}
+ 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()
+ try:
+ pkgs = list(__salt__["pkg_resource.parse_targets"](pkgs)[0].keys())
+ except MinionError as exc:
+ raise CommandExecutionError(exc)
+
+ removed = []
+ missing = []
+ for pkg in pkgs:
+ if locks.get(pkg):
+ removed.append(pkg)
+ ret[pkg]["comment"] = "Package {} is no longer held.".format(pkg)
+ else:
+ missing.append(pkg)
+ ret[pkg]["comment"] = "Package {} unable to be unheld.".format(pkg)
+
+ if removed:
+ __zypper__.call("rl", *removed)
+
+ return ret
+
+
+def remove_lock(packages, **kwargs): # pylint: disable=unused-argument
+ """
+ Remove specified package lock.
+
+ CLI Example:
+
+ .. code-block:: bash
- locks = list_locks(root)
+ salt '*' pkg.remove_lock <package name>
+ salt '*' pkg.remove_lock <package1>,<package2>,<package3>
+ salt '*' pkg.remove_lock pkgs='["foo", "bar"]'
+ """
+ salt.utils.versions.warn_until(
+ "Sodium", "This function is deprecated. Please use unhold() instead."
+ )
+ locks = list_locks()
try:
packages = list(__salt__["pkg_resource.parse_targets"](packages)[0].keys())
except MinionError as exc:
@@ -2125,7 +2154,51 @@ def remove_lock(packages, root=None, **kwargs): # pylint: disable=unused-argume
return {"removed": len(removed), "not_found": missing}
-def add_lock(packages, root=None, **kwargs): # pylint: disable=unused-argument
+def hold(name=None, pkgs=None, **kwargs):
+ """
+ Add a package lock. Specify packages to lock by exact name.
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt '*' pkg.add_lock <package name>
+ salt '*' pkg.add_lock <package1>,<package2>,<package3>
+ salt '*' pkg.add_lock pkgs='["foo", "bar"]'
+
+ :param name:
+ :param pkgs:
+ :param kwargs:
+ :return:
+ """
+ ret = {}
+ 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()
+ added = []
+ try:
+ pkgs = list(__salt__["pkg_resource.parse_targets"](pkgs)[0].keys())
+ except MinionError as exc:
+ raise CommandExecutionError(exc)
+
+ for pkg in pkgs:
+ ret[pkg] = {"name": pkg, "changes": {}, "result": False, "comment": ""}
+ if not locks.get(pkg):
+ added.append(pkg)
+ ret[pkg]["comment"] = "Package {} is now being held.".format(pkg)
+ else:
+ ret[pkg]["comment"] = "Package {} is already set to be held.".format(pkg)
+
+ if added:
+ __zypper__.call("al", *added)
+
+ return ret
+
+
+def add_lock(packages, **kwargs): # pylint: disable=unused-argument
"""
Add a package lock. Specify packages to lock by exact name.
@@ -2140,7 +2213,10 @@ def add_lock(packages, root=None, **kwargs): # pylint: disable=unused-argument
salt '*' pkg.add_lock <package1>,<package2>,<package3>
salt '*' pkg.add_lock pkgs='["foo", "bar"]'
"""
- locks = list_locks(root)
+ salt.utils.versions.warn_until(
+ "Sodium", "This function is deprecated. Please use hold() instead."
+ )
+ locks = list_locks()
added = []
try:
packages = list(__salt__["pkg_resource.parse_targets"](packages)[0].keys())
@@ -2495,7 +2571,7 @@ def search(criteria, refresh=False, **kwargs):
.getElementsByTagName("solvable")
)
if not solvables:
- raise CommandExecutionError("No packages found matching '{0}'".format(criteria))
+ raise CommandExecutionError("No packages found matching '{}'".format(criteria))
out = {}
for solvable in solvables:
@@ -2649,13 +2725,13 @@ def download(*packages, **kwargs):
if failed:
pkg_ret[
"_error"
- ] = "The following package(s) failed to download: {0}".format(
+ ] = "The following package(s) failed to download: {}".format(
", ".join(failed)
)
return pkg_ret
raise CommandExecutionError(
- "Unable to download packages: {0}".format(", ".join(packages))
+ "Unable to download packages: {}".format(", ".join(packages))
)
@@ -2726,7 +2802,7 @@ def diff(*paths, **kwargs):
if pkg_to_paths:
local_pkgs = __salt__["pkg.download"](*pkg_to_paths.keys(), **kwargs)
- for pkg, files in six.iteritems(pkg_to_paths):
+ for pkg, files in pkg_to_paths.items():
for path in files:
ret[path] = (
__salt__["lowpkg.diff"](local_pkgs[pkg]["path"], path)
--
2.29.2