SHA256
1
0
forked from pool/salt
salt/provide-the-missing-features-required-for-yomi-yet-o.patch

1758 lines
67 KiB
Diff

From 2a682f5ea32f6e37e778040032aff9332aac1a0e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Thu, 20 Jun 2019 12:52:45 +0100
Subject: [PATCH] Provide the missing features required for Yomi (Yet
one more installer)
---
salt/grains/core.py | 6 +-
salt/modules/kubeadm.py | 91 +++++++++------
salt/modules/rpm_lowpkg.py | 42 +++----
salt/modules/systemd_service.py | 24 ++--
salt/modules/zypperpkg.py | 87 ++++++++------
salt/states/btrfs.py | 44 +++++--
salt/states/file.py | 7 +-
salt/states/loop.py | 15 +--
salt/states/pkgrepo.py | 5 -
salt/utils/oset.py | 8 +-
tests/unit/modules/test_kubeadm.py | 43 ++++---
tests/unit/modules/test_rpm_lowpkg.py | 15 ++-
tests/unit/modules/test_systemd_service.py | 13 +--
tests/unit/modules/test_zypperpkg.py | 60 ++--------
tests/unit/states/test_btrfs.py | 130 ++++++---------------
tests/unit/states/test_pkg.py | 39 ++-----
tests/unit/test_loader.py | 97 ++++++++++++++-
17 files changed, 373 insertions(+), 353 deletions(-)
diff --git a/salt/grains/core.py b/salt/grains/core.py
index bebb4581bc..d7d03c5e70 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -2759,7 +2759,7 @@ def _hw_data(osdata):
contents_file = os.path.join("/sys/class/dmi/id", fw_file)
if os.path.exists(contents_file):
try:
- with salt.utils.files.fopen(contents_file, "rb") as ifile:
+ with salt.utils.files.fopen(contents_file, "r") as ifile:
grains[key] = salt.utils.stringutils.to_unicode(
ifile.read().strip(), errors="replace"
)
@@ -2768,9 +2768,7 @@ def _hw_data(osdata):
except UnicodeDecodeError:
# Some firmwares provide non-valid 'product_name'
# files, ignore them
- log.debug(
- "The content in /sys/devices/virtual/dmi/id/product_name is not valid"
- )
+ pass
except OSError as err:
# PermissionError is new to Python 3, but corresponds to the EACESS and
# EPERM error numbers. Use those instead here for PY2 compatibility.
diff --git a/salt/modules/kubeadm.py b/salt/modules/kubeadm.py
index 8baf5f85fd..966e9e848f 100644
--- a/salt/modules/kubeadm.py
+++ b/salt/modules/kubeadm.py
@@ -1,3 +1,25 @@
+#
+# Author: Alberto Planas <aplanas@suse.com>
+#
+# Copyright 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
"""
:maintainer: Alberto Planas <aplanas@suse.com>
:maturity: new
@@ -11,6 +33,7 @@ import re
import salt.utils.files
from salt.exceptions import CommandExecutionError
+from salt.ext.six.moves import zip
ADMIN_CFG = "/etc/kubernetes/admin.conf"
@@ -37,23 +60,22 @@ def _api_server_endpoint(config=None):
endpoint = re.search(
r"^\s*server: https?://(.*)$", fp_.read(), re.MULTILINE
).group(1)
- # pylint:disable=broad-except
except Exception:
# Any error or exception is mapped to None
pass
return endpoint
-def _token(create_if_needed=False):
+def _token(create_if_needed=True):
"""
Return a valid bootstrap token
"""
tokens = token_list()
- if not tokens and create_if_needed:
+ if not tokens:
token_create(description="Token created by kubeadm salt module")
tokens = token_list()
- # We expect that the token is valid for authentication and signing
- return tokens[0]["token"] if tokens else None
+ # We expect that the token is valid for authestication and signing
+ return tokens[0]["token"]
def _discovery_token_ca_cert_hash():
@@ -92,10 +114,6 @@ def join_params(create_if_needed=False):
Return the parameters required for joining into the cluster
- create_if_needed
- If the token bucket is empty and this parameter is True, a new
- token will be created.
-
CLI Example:
.. code-block:: bash
@@ -169,7 +187,7 @@ def token_create(
Create bootstrap tokens on the server
token
- Token to write, if None one will be generated. The token must
+ Token to write, if None one will be gerenared. The token must
match a regular expression, that by default is
[a-z0-9]{6}.[a-z0-9]{16}
@@ -180,7 +198,7 @@ def token_create(
A human friendly description of how this token is used
groups
- List of extra groups that this token will authenticate, default
+ List of extra groups that this token will authenticate, defaut
to ['system:bootstrappers:kubeadm:default-node-token']
ttl
@@ -189,7 +207,7 @@ def token_create(
is 24h0m0s
usages
- Describes the ways in which this token can be used. The default
+ Describes the ways in wich this token can be used. The default
value is ['signing', 'authentication']
kubeconfig
@@ -239,7 +257,7 @@ def token_delete(token, kubeconfig=None, rootfs=None):
Delete bootstrap tokens on the server
token
- Token to write, if None one will be generated. The token must
+ Token to write, if None one will be gerenared. The token must
match a regular expression, that by default is
[a-z0-9]{6}.[a-z0-9]{16}
@@ -328,21 +346,20 @@ def token_list(kubeconfig=None, rootfs=None):
lines = _cmd(cmd).splitlines()
+ # Find the header and parse it. We do not need to validate the
+ # content, as the regex will take care of future changes.
+ header = lines.pop(0)
+ header = [i.lower() for i in re.findall(r"(\w+(?:\s\w+)*)", header)]
+
tokens = []
- if lines:
- # Find the header and parse it. We do not need to validate
- # the content, as the regex will take care of future changes.
- header = lines.pop(0)
- header = [i.lower() for i in re.findall(r"(\w+(?:\s\w+)*)", header)]
-
- for line in lines:
- # TODO(aplanas): descriptions with multiple spaces can
- # break the parser.
- values = re.findall(r"(\S+(?:\s\S+)*)", line)
- if len(header) != len(values):
- log.error("Error parsing line: {}".format(line))
- continue
- tokens.append({key: value for key, value in zip(header, values)})
+ for line in lines:
+ # TODO(aplanas): descriptions with multiple spaces can break
+ # the parser.
+ values = re.findall(r"(\S+(?:\s\S+)*)", line)
+ if len(header) != len(values):
+ log.error("Error parsing line: {}".format(line))
+ continue
+ tokens.append({key: value for key, value in zip(header, values)})
return tokens
@@ -869,7 +886,7 @@ def config_upload_from_flags(
flags
apiserver_advertise_address
- The IP address the API server will advertise it's listening on
+ The IP address the API server will adversite it's listening on
apiserver_bind_port
The port the API server is accessible on (default 6443)
@@ -900,11 +917,11 @@ def config_upload_from_flags(
Specify range of IP addresses for the pod network
service_cidr
- Use alternative range of IP address for service VIPs (default
+ Use alternative range of IP address dor service VIPs (default
"10.96.0.0/12")
service_dns_domain
- Use alternative domain for services (default "cluster.local")
+ Use alternative domain for serivces (default "cluster.local")
kubeconfig
The kubeconfig file to use when talking to the cluster. The
@@ -1004,7 +1021,7 @@ def init(
Command to set up the Kubernetes control plane
apiserver_advertise_address
- The IP address the API server will advertise it's listening on
+ The IP address the API server will adversite it's listening on
apiserver_bind_port
The port the API server is accessible on (default 6443)
@@ -1035,10 +1052,10 @@ def init(
various features
ignore_preflight_errors
- A list of checks whose errors will be shown as warnings
+ A list of checkt whose errors will be shown as warnings
image_repository
- Choose a container registry to pull control plane images from
+ Choose a container registry to pull controll plane images from
kubernetes_version
Choose a specifig Kubernetes version for the control plane
@@ -1051,11 +1068,11 @@ def init(
Specify range of IP addresses for the pod network
service_cidr
- Use alternative range of IP address for service VIPs (default
+ Use alternative range of IP address dor service VIPs (default
"10.96.0.0/12")
service_dns_domain
- Use alternative domain for services (default "cluster.local")
+ Use alternative domain for serivces (default "cluster.local")
skip_certificate_key_print
Don't print the key used to encrypt the control-plane
@@ -1190,10 +1207,10 @@ def join(
apiserver_advertise_address
If the node should host a new control plane instance, the IP
- address the API Server will advertise it's listening on
+ address the API Server will adversise it's listening on
apiserver_bind_port
- If the node should host a new control plane instance, the port
+ If the node shoult host a new control plane instance, the port
the API Server to bind to (default 6443)
certificate_key
diff --git a/salt/modules/rpm_lowpkg.py b/salt/modules/rpm_lowpkg.py
index 54b7014440..393b0f453a 100644
--- a/salt/modules/rpm_lowpkg.py
+++ b/salt/modules/rpm_lowpkg.py
@@ -1,17 +1,13 @@
-# -*- coding: utf-8 -*-
"""
Support for rpm
"""
-# Import python libs
-from __future__ import absolute_import, print_function, unicode_literals
import datetime
import logging
import os
import re
-# Import Salt libs
import salt.utils.decorators.path
import salt.utils.itertools
import salt.utils.path
@@ -105,14 +101,14 @@ def bin_pkg_info(path, saltenv="base"):
newpath = __salt__["cp.cache_file"](path, saltenv)
if not newpath:
raise CommandExecutionError(
- "Unable to retrieve {0} from saltenv '{1}'".format(path, saltenv)
+ "Unable to retrieve {} from saltenv '{}'".format(path, saltenv)
)
path = newpath
else:
if not os.path.exists(path):
- raise CommandExecutionError("{0} does not exist on minion".format(path))
+ raise CommandExecutionError("{} does not exist on minion".format(path))
elif not os.path.isabs(path):
- raise SaltInvocationError("{0} does not exist on minion".format(path))
+ raise SaltInvocationError("{} does not exist on minion".format(path))
# REPOID is not a valid tag for the rpm command. Remove it and replace it
# with 'none'
@@ -187,28 +183,26 @@ def verify(*packages, **kwargs):
ftypes = {"c": "config", "d": "doc", "g": "ghost", "l": "license", "r": "readme"}
ret = {}
ignore_types = kwargs.get("ignore_types", [])
- if not isinstance(ignore_types, (list, six.string_types)):
+ if not isinstance(ignore_types, (list, (str,))):
raise SaltInvocationError(
"ignore_types must be a list or a comma-separated string"
)
- if isinstance(ignore_types, six.string_types):
+ if isinstance(ignore_types, str):
try:
ignore_types = [x.strip() for x in ignore_types.split(",")]
except AttributeError:
- ignore_types = [x.strip() for x in six.text_type(ignore_types).split(",")]
+ ignore_types = [x.strip() for x in str(ignore_types).split(",")]
verify_options = kwargs.get("verify_options", [])
- if not isinstance(verify_options, (list, six.string_types)):
+ if not isinstance(verify_options, (list, (str,))):
raise SaltInvocationError(
"verify_options must be a list or a comma-separated string"
)
- if isinstance(verify_options, six.string_types):
+ if isinstance(verify_options, str):
try:
verify_options = [x.strip() for x in verify_options.split(",")]
except AttributeError:
- verify_options = [
- x.strip() for x in six.text_type(verify_options).split(",")
- ]
+ verify_options = [x.strip() for x in str(verify_options).split(",")]
cmd = ["rpm"]
if kwargs.get("root"):
@@ -229,7 +223,7 @@ def verify(*packages, **kwargs):
# succeeded, but if the retcode is nonzero, then the command failed.
msg = "Failed to verify package(s)"
if out["stderr"]:
- msg += ": {0}".format(out["stderr"])
+ msg += ": {}".format(out["stderr"])
raise CommandExecutionError(msg)
for line in salt.utils.itertools.split(out["stdout"], "\n"):
@@ -492,7 +486,7 @@ def diff(package_path, path):
)
res = __salt__["cmd.shell"](cmd.format(package_path, path), output_loglevel="trace")
if res and res.startswith("Binary file"):
- return "File '{0}' is binary and its content has been " "modified.".format(path)
+ return "File '{}' is binary and its content has been " "modified.".format(path)
return res
@@ -590,7 +584,7 @@ def info(*packages, **kwargs):
attr.append("edition")
query.append(attr_map["edition"])
else:
- for attr_k, attr_v in six.iteritems(attr_map):
+ for attr_k, attr_v in attr_map.items():
if attr_k != "description":
query.append(attr_v)
if attr and "description" in attr or not attr:
@@ -599,7 +593,7 @@ def info(*packages, **kwargs):
cmd = " ".join(cmd)
call = __salt__["cmd.run_all"](
- cmd + (" --queryformat '{0}'".format("".join(query))),
+ cmd + (" --queryformat '{}'".format("".join(query))),
output_loglevel="trace",
env={"TZ": "UTC"},
clean_env=True,
@@ -706,11 +700,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False):
salt '*' pkg.version_cmp '0.2-001' '0.2.0.1-002'
"""
- normalize = (
- lambda x: six.text_type(x).split(":", 1)[-1]
- if ignore_epoch
- else six.text_type(x)
- )
+ normalize = lambda x: str(x).split(":", 1)[-1] if ignore_epoch else str(x)
ver1 = normalize(ver1)
ver2 = normalize(ver2)
@@ -747,7 +737,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False):
# rpmdev-vercmp always uses epochs, even when zero
def _ensure_epoch(ver):
def _prepend(ver):
- return "0:{0}".format(ver)
+ return "0:{}".format(ver)
try:
if ":" not in ver:
@@ -798,7 +788,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False):
cmp_result = cmp_func((ver1_e, ver1_v, ver1_r), (ver2_e, ver2_v, ver2_r))
if cmp_result not in (-1, 0, 1):
raise CommandExecutionError(
- "Comparison result '{0}' is invalid".format(cmp_result)
+ "Comparison result '{}' is invalid".format(cmp_result)
)
return cmp_result
diff --git a/salt/modules/systemd_service.py b/salt/modules/systemd_service.py
index 176e1dabaa..03e7268cd4 100644
--- a/salt/modules/systemd_service.py
+++ b/salt/modules/systemd_service.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
Provides the service module for systemd
@@ -15,8 +14,6 @@ Provides the service module for systemd
call it under the name 'service' and NOT 'systemd'. You can see that also
in the examples below.
"""
-# Import Python libs
-from __future__ import absolute_import, print_function, unicode_literals
import errno
import fnmatch
@@ -26,15 +23,12 @@ import os
import re
import shlex
-# Import Salt libs
import salt.utils.files
import salt.utils.itertools
import salt.utils.path
import salt.utils.stringutils
import salt.utils.systemd
from salt.exceptions import CommandExecutionError
-
-# Import 3rd-party libs
from salt.ext import six
log = logging.getLogger(__name__)
@@ -94,8 +88,8 @@ def _canonical_unit_name(name):
Build a canonical unit name treating unit names without one
of the valid suffixes as a service.
"""
- if not isinstance(name, six.string_types):
- name = six.text_type(name)
+ if not isinstance(name, str):
+ name = str(name)
if any(name.endswith(suffix) for suffix in VALID_UNIT_TYPES):
return name
return "%s.service" % name
@@ -137,7 +131,7 @@ def _check_for_unit_changes(name):
Check for modified/updated unit files, and run a daemon-reload if any are
found.
"""
- contextkey = "systemd._check_for_unit_changes.{0}".format(name)
+ contextkey = "systemd._check_for_unit_changes.{}".format(name)
if contextkey not in __context__:
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
systemctl_reload()
@@ -199,9 +193,7 @@ def _default_runlevel():
# The default runlevel can also be set via the kernel command-line.
try:
- valid_strings = set(
- ("0", "1", "2", "3", "4", "5", "6", "s", "S", "-s", "single")
- )
+ valid_strings = {"0", "1", "2", "3", "4", "5", "6", "s", "S", "-s", "single"}
with salt.utils.files.fopen("/proc/cmdline") as fp_:
for line in fp_:
line = salt.utils.stringutils.to_unicode(line)
@@ -291,7 +283,7 @@ def _get_service_exec():
break
else:
raise CommandExecutionError(
- "Unable to find sysv service manager (tried {0})".format(
+ "Unable to find sysv service manager (tried {})".format(
", ".join(executables)
)
)
@@ -345,7 +337,7 @@ def _systemctl_cmd(action, name=None, systemd_scope=False, no_block=False, root=
ret.append("--no-block")
if root:
ret.extend(["--root", root])
- if isinstance(action, six.string_types):
+ if isinstance(action, str):
action = shlex.split(action)
ret.extend(action)
if name is not None:
@@ -507,7 +499,7 @@ def get_enabled(root=None):
ret.add(unit_name if unit_type == "service" else fullname)
# Add in any sysvinit services that are enabled
- ret.update(set([x for x in _get_sysv_services(root) if _sysv_enabled(x, root)]))
+ ret.update({x for x in _get_sysv_services(root) if _sysv_enabled(x, root)})
return sorted(ret)
@@ -549,7 +541,7 @@ def get_disabled(root=None):
ret.add(unit_name if unit_type == "service" else fullname)
# Add in any sysvinit services that are disabled
- ret.update(set([x for x in _get_sysv_services(root) if not _sysv_enabled(x, root)]))
+ ret.update({x for x in _get_sysv_services(root) if not _sysv_enabled(x, root)})
return sorted(ret)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index dfaaf420a1..75cb5ce4a8 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -879,6 +879,7 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs):
# inclusion types are passed
contextkey = "pkg.list_pkgs_{}_{}".format(root, includes)
+ # TODO(aplanas): this cached value depends on the parameters
if contextkey not in __context__:
ret = {}
cmd = ["rpm"]
@@ -958,6 +959,28 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs):
}
]
+ for include in includes:
+ if include in ("pattern", "patch"):
+ if include == "pattern":
+ pkgs = list_installed_patterns(root=root)
+ elif include == "patch":
+ pkgs = list_installed_patches(root=root)
+ else:
+ pkgs = []
+ for pkg in pkgs:
+ pkg_extended_name = "{}:{}".format(include, pkg)
+ info = info_available(pkg_extended_name, refresh=False, root=root)
+ _ret[pkg_extended_name] = [
+ {
+ "epoch": None,
+ "version": info[pkg]["version"],
+ "release": None,
+ "arch": info[pkg]["arch"],
+ "install_date": None,
+ "install_date_time_t": None,
+ }
+ ]
+
__context__[contextkey] = _ret
return __salt__["pkg_resource.format_pkg_list"](
@@ -1401,7 +1424,9 @@ def refresh_db(force=None, root=None):
def _find_types(pkgs):
- """Form a package names list, find prefixes of packages types."""
+ """
+ Form a package names list, find prefixes of packages types.
+ """
return sorted({pkg.split(":", 1)[0] for pkg in pkgs if len(pkg.split(":", 1)) == 2})
@@ -1596,12 +1621,7 @@ def install(
'Advisory id "{}" not found'.format(advisory_id)
)
else:
- # If we add here the `patch:` prefix, the
- # `_find_types` helper will take the patches into the
- # list of packages. Usually this is the correct thing
- # to do, but we can break software the depends on the
- # old behaviour.
- targets.append(advisory_id)
+ targets.append("patch:{}".format(advisory_id))
else:
targets = pkg_params
@@ -1639,16 +1659,6 @@ def install(
errors = []
- # If the type is 'advisory', we manually add the 'patch:'
- # prefix. This kind of package will not appear in pkg_list in this
- # way.
- #
- # Note that this enable a different mechanism to install a patch;
- # if the name of the package is already prefixed with 'patch:' we
- # can avoid listing them in the `advisory_ids` field.
- if pkg_type == "advisory":
- targets = ["patch:{}".format(t) for t in targets]
-
# Split the targets into batches of 500 packages each, so that
# the maximal length of the command line is not broken
systemd_scope = _systemd_scope()
@@ -1805,6 +1815,10 @@ def upgrade(
cmd_update.append("--no-recommends")
log.info("Disabling recommendations")
+ 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")
@@ -2035,13 +2049,13 @@ def list_locks(root=None):
for element in [el for el in meta if el]:
if ":" in element:
lock.update(
- dict([tuple([i.strip() for i in element.split(":", 1)])])
+ dict([tuple([i.strip() for i in element.split(":", 1)]),])
)
if lock.get("solvable_name"):
locks[lock.pop("solvable_name")] = lock
except OSError:
pass
- except Exception: # pylint: disable=broad-except
+ except Exception:
log.warning("Detected a problem when accessing {}".format(_locks))
return locks
@@ -2092,12 +2106,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:
@@ -2114,15 +2129,18 @@ def unhold(name=None, pkgs=None, **kwargs):
ret[pkg]["comment"] = "Package {} 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.
+ root
+ operate on a different root directory.
+
CLI Example:
.. code-block:: bash
@@ -2134,7 +2152,7 @@ def remove_lock(packages, **kwargs): # pylint: disable=unused-argument
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:
@@ -2158,6 +2176,9 @@ def hold(name=None, pkgs=None, **kwargs):
"""
Add a package lock. Specify packages to lock by exact name.
+ root
+ operate on a different root directory.
+
CLI Example:
.. code-block:: bash
@@ -2172,12 +2193,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())
@@ -2193,12 +2215,12 @@ def hold(name=None, pkgs=None, **kwargs):
ret[pkg]["comment"] = "Package {} 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.
@@ -2216,7 +2238,7 @@ def add_lock(packages, **kwargs): # pylint: disable=unused-argument
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())
@@ -2410,14 +2432,11 @@ def _get_installed_patterns(root=None):
# a real error.
output = __salt__["cmd.run"](cmd, ignore_retcode=True)
- # On <= SLE12SP4 we have patterns that have multiple names (alias)
- # and that are duplicated. The alias start with ".", so we filter
- # them.
- installed_patterns = {
+ installed_patterns = [
_pattern_name(line)
for line in output.splitlines()
- if line.startswith("pattern() = ") and not _pattern_name(line).startswith(".")
- }
+ if line.startswith("pattern() = ")
+ ]
patterns = {
k: v for k, v in _get_visible_patterns(root=root).items() if v["installed"]
@@ -2735,7 +2754,7 @@ def download(*packages, **kwargs):
)
-def list_downloaded(root=None, **kwargs):
+def list_downloaded(root=None):
"""
.. versionadded:: 2017.7.0
diff --git a/salt/states/btrfs.py b/salt/states/btrfs.py
index ec84d862c3..1374bbffb4 100644
--- a/salt/states/btrfs.py
+++ b/salt/states/btrfs.py
@@ -1,10 +1,31 @@
+#
+# Author: Alberto Planas <aplanas@suse.com>
+#
+# Copyright 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
"""
:maintainer: Alberto Planas <aplanas@suse.com>
:maturity: new
:depends: None
:platform: Linux
"""
-
import functools
import logging
import os.path
@@ -22,7 +43,7 @@ def _mount(device, use_default):
"""
Mount the device in a temporary place.
"""
- opts = "defaults" if use_default else "subvol=/"
+ opts = "subvol=/" if not use_default else "defaults"
dest = tempfile.mkdtemp()
res = __states__["mount.mounted"](
dest, device=device, fstype="btrfs", opts=opts, persist=False
@@ -82,8 +103,8 @@ def __mount_device(action):
@functools.wraps(action)
def wrapper(*args, **kwargs):
- name = kwargs.get("name", args[0] if args else None)
- device = kwargs.get("device", args[1] if len(args) > 1 else None)
+ name = kwargs["name"]
+ device = kwargs["device"]
use_default = kwargs.get("use_default", False)
ret = {
@@ -100,9 +121,10 @@ def __mount_device(action):
ret["comment"].append(msg)
kwargs["__dest"] = dest
ret = action(*args, **kwargs)
- except Exception as e: # pylint: disable=broad-except
- log.error("""Traceback: {}""".format(traceback.format_exc()))
- ret["comment"].append(e)
+ except Exception:
+ tb = str(traceback.format_exc())
+ log.exception("Exception captured in wrapper %s", tb)
+ ret["comment"].append(tb)
finally:
if device:
_umount(dest)
@@ -165,7 +187,7 @@ def subvolume_created(
if __opts__["test"]:
ret["result"] = None
if not exists:
- ret["changes"][name] = "Subvolume {} will be created".format(name)
+ ret["comment"].append("Subvolume {} will be created".format(name))
return ret
if not exists:
@@ -231,7 +253,7 @@ def subvolume_deleted(name, device, commit=False, __dest=None):
if __opts__["test"]:
ret["result"] = None
if exists:
- ret["changes"][name] = "Subvolume {} will be removed".format(name)
+ ret["comment"].append("Subvolume {} will be removed".format(name))
return ret
# If commit is set, we wait until all is over
@@ -344,10 +366,10 @@ def properties(name, device, use_default=False, __dest=None, **properties):
if __opts__["test"]:
ret["result"] = None
if properties_to_set:
- ret["changes"] = properties_to_set
+ msg = "Properties {} will be changed in {}".format(properties_to_set, name)
else:
msg = "No properties will be changed in {}".format(name)
- ret["comment"].append(msg)
+ ret["comment"].append(msg)
return ret
if properties_to_set:
diff --git a/salt/states/file.py b/salt/states/file.py
index 9873f8dcc7..9e24e389d8 100644
--- a/salt/states/file.py
+++ b/salt/states/file.py
@@ -290,7 +290,6 @@ import sys
import time
import traceback
from collections import defaultdict
-from collections.abc import Iterable, Mapping
from datetime import date, datetime # python3 problem in the making?
import salt.loader
@@ -312,6 +311,12 @@ from salt.ext.six.moves.urllib.parse import urlparse as _urlparse
from salt.serializers import DeserializationError
from salt.state import get_accumulator_dir as _get_accumulator_dir
+try:
+ from collections.abc import Iterable, Mapping
+except ImportError:
+ from collections import Iterable, Mapping
+
+
if salt.utils.platform.is_windows():
import salt.utils.win_dacl
import salt.utils.win_functions
diff --git a/salt/states/loop.py b/salt/states/loop.py
index 25e54e1faf..de37b7d60c 100644
--- a/salt/states/loop.py
+++ b/salt/states/loop.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
Loop state
@@ -58,8 +57,6 @@ The function :py:func:`data.subdict_match <salt.utils.data.subdict_match>` check
instances: "{{ instance }}"
"""
-# Import python libs
-from __future__ import absolute_import, print_function, unicode_literals
import logging
import operator
@@ -99,7 +96,7 @@ def until(name, m_args=None, m_kwargs=None, condition=None, period=1, timeout=60
m_kwargs = {}
if name not in __salt__:
- ret["comment"] = "Cannot find module {0}".format(name)
+ ret["comment"] = "Cannot find module {}".format(name)
elif condition is None:
ret["comment"] = "An exit condition must be specified"
elif not isinstance(period, (int, float)):
@@ -107,7 +104,7 @@ def until(name, m_args=None, m_kwargs=None, condition=None, period=1, timeout=60
elif not isinstance(timeout, (int, float)):
ret["comment"] = "Timeout must be specified as a float in seconds"
elif __opts__["test"]:
- ret["comment"] = "The execution module {0} will be run".format(name)
+ ret["comment"] = "The execution module {} will be run".format(name)
ret["result"] = None
else:
if m_args is None:
@@ -120,11 +117,11 @@ def until(name, m_args=None, m_kwargs=None, condition=None, period=1, timeout=60
m_ret = __salt__[name](*m_args, **m_kwargs)
if eval(condition): # pylint: disable=W0123
ret["result"] = True
- ret["comment"] = "Condition {0} was met".format(condition)
+ ret["comment"] = "Condition {} was met".format(condition)
break
time.sleep(period)
else:
- ret["comment"] = "Timed out while waiting for condition {0}".format(
+ ret["comment"] = "Timed out while waiting for condition {}".format(
condition
)
return ret
@@ -185,6 +182,10 @@ def until_no_eval(
)
if ret["comment"]:
return ret
+ if not m_args:
+ m_args = []
+ if not m_kwargs:
+ m_kwargs = {}
if init_wait:
time.sleep(init_wait)
diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py
index 99440874c2..70cb7a1c7e 100644
--- a/salt/states/pkgrepo.py
+++ b/salt/states/pkgrepo.py
@@ -92,7 +92,6 @@ package managers are APT, DNF, YUM and Zypper. Here is some example SLS:
"""
-# Import Python libs
import sys
@@ -101,11 +100,7 @@ import salt.utils.files
import salt.utils.pkg.deb
import salt.utils.pkg.rpm
import salt.utils.versions
-
-# Import salt libs
from salt.exceptions import CommandExecutionError, SaltInvocationError
-
-# Import 3rd-party libs
from salt.state import STATE_INTERNAL_KEYWORDS as _STATE_INTERNAL_KEYWORDS
diff --git a/salt/utils/oset.py b/salt/utils/oset.py
index d6fb961ede..31a6a4acca 100644
--- a/salt/utils/oset.py
+++ b/salt/utils/oset.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
Available at repository https://github.com/LuminosoInsight/ordered-set
@@ -21,9 +20,10 @@ Rob Speer's changes are as follows:
- added a __getstate__ and __setstate__ so it can be pickled
- added __getitem__
"""
-from __future__ import absolute_import, print_function, unicode_literals
-
-from collections.abc import MutableSet
+try:
+ from collections.abc import MutableSet
+except ImportError:
+ from collections import MutableSet
SLICE_ALL = slice(None)
__version__ = "2.0.1"
diff --git a/tests/unit/modules/test_kubeadm.py b/tests/unit/modules/test_kubeadm.py
index af319e01b1..91e4a9e68e 100644
--- a/tests/unit/modules/test_kubeadm.py
+++ b/tests/unit/modules/test_kubeadm.py
@@ -1,20 +1,41 @@
+#
+# Author: Alberto Planas <aplanas@suse.com>
+#
+# Copyright 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
import pytest
import salt.modules.kubeadm as kubeadm
from salt.exceptions import CommandExecutionError
-
-# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
-from tests.support.mock import MagicMock, patch
-from tests.support.unit import TestCase
+from tests.support.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch
+from tests.support.unit import TestCase, skipIf
+@skipIf(NO_MOCK, NO_MOCK_REASON)
class KubeAdmTestCase(TestCase, LoaderModuleMockMixin):
"""
Test cases for salt.modules.kubeadm
"""
def setup_loader_modules(self):
- return {kubeadm: {"__salt__": {}, "__utils__": {}}}
+ return {kubeadm: {"__salt__": {}, "__utils__": {},}}
def test_version(self):
"""
@@ -223,18 +244,6 @@ class KubeAdmTestCase(TestCase, LoaderModuleMockMixin):
with pytest.raises(CommandExecutionError):
assert kubeadm.token_generate()
- def test_token_empty(self):
- """
- Test kuebadm.token_list when no outout
- """
- result = {"retcode": 0, "stdout": ""}
- salt_mock = {
- "cmd.run_all": MagicMock(return_value=result),
- }
- with patch.dict(kubeadm.__salt__, salt_mock):
- assert kubeadm.token_list() == []
- salt_mock["cmd.run_all"].assert_called_with(["kubeadm", "token", "list"])
-
def test_token_list(self):
"""
Test kuebadm.token_list without parameters
diff --git a/tests/unit/modules/test_rpm_lowpkg.py b/tests/unit/modules/test_rpm_lowpkg.py
index e7e8230510..b41e8daf17 100644
--- a/tests/unit/modules/test_rpm_lowpkg.py
+++ b/tests/unit/modules/test_rpm_lowpkg.py
@@ -1,15 +1,9 @@
-# -*- coding: utf-8 -*-
"""
:codeauthor: Jayesh Kariya <jayeshk@saltstack.com>
"""
-# Import Python Libs
-from __future__ import absolute_import
-# Import Salt Libs
import salt.modules.rpm_lowpkg as rpm
-
-# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
@@ -108,6 +102,15 @@ class RpmTestCase(TestCase, LoaderModuleMockMixin):
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}):
+ 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
diff --git a/tests/unit/modules/test_systemd_service.py b/tests/unit/modules/test_systemd_service.py
index 32741969ce..bbd89bb3d0 100644
--- a/tests/unit/modules/test_systemd_service.py
+++ b/tests/unit/modules/test_systemd_service.py
@@ -1,23 +1,16 @@
-# -*- coding: utf-8 -*-
"""
:codeauthor: Rahul Handay <rahulha@saltstack.com>
"""
-# Import Python libs
-from __future__ import absolute_import, print_function, unicode_literals
import os
import pytest
-
-# Import Salt Libs
import salt.modules.systemd_service as systemd
import salt.utils.systemd
from salt.exceptions import CommandExecutionError
from tests.support.mixins import LoaderModuleMockMixin
-from tests.support.mock import MagicMock, patch
-
-# Import Salt Testing Libs
+from tests.support.mock import MagicMock, Mock, patch
from tests.support.unit import TestCase
_SYSTEMCTL_STATUS = {
@@ -93,7 +86,7 @@ class SystemdTestCase(TestCase, LoaderModuleMockMixin):
cmd_mock = MagicMock(return_value=_LIST_UNIT_FILES)
listdir_mock = MagicMock(return_value=["foo", "bar", "baz", "README"])
sd_mock = MagicMock(
- return_value=set([x.replace(".service", "") for x in _SYSTEMCTL_STATUS])
+ return_value={x.replace(".service", "") for x in _SYSTEMCTL_STATUS}
)
access_mock = MagicMock(
side_effect=lambda x, y: x
@@ -124,7 +117,7 @@ class SystemdTestCase(TestCase, LoaderModuleMockMixin):
# only 'baz' will be considered an enabled sysv service).
listdir_mock = MagicMock(return_value=["foo", "bar", "baz", "README"])
sd_mock = MagicMock(
- return_value=set([x.replace(".service", "") for x in _SYSTEMCTL_STATUS])
+ return_value={x.replace(".service", "") for x in _SYSTEMCTL_STATUS}
)
access_mock = MagicMock(
side_effect=lambda x, y: x
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
index b07f9a3af7..032785395e 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -1639,6 +1639,9 @@ Repository 'DUMMY' not found by its alias, number, or URI.
self.assertTrue(
zypper.__zypper__(root=None).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):
"""
@@ -1919,8 +1922,8 @@ Repository 'DUMMY' not found by its alias, number, or URI.
def test__get_installed_patterns(self, get_visible_patterns):
"""Test installed patterns in the system"""
get_visible_patterns.return_value = {
- "package-a": {"installed": True, "summary": "description a"},
- "package-b": {"installed": False, "summary": "description b"},
+ "package-a": {"installed": True, "summary": "description a",},
+ "package-b": {"installed": False, "summary": "description b",},
}
salt_mock = {
@@ -1932,59 +1935,18 @@ pattern() = package-c"""
}
with patch.dict("salt.modules.zypperpkg.__salt__", salt_mock):
assert zypper._get_installed_patterns() == {
- "package-a": {"installed": True, "summary": "description a"},
- "package-c": {"installed": True, "summary": "Non-visible pattern"},
- }
-
- @patch("salt.modules.zypperpkg._get_visible_patterns")
- def test__get_installed_patterns_with_alias(self, get_visible_patterns):
- """Test installed patterns in the system if they have alias"""
- get_visible_patterns.return_value = {
- "package-a": {"installed": True, "summary": "description a"},
- "package-b": {"installed": False, "summary": "description b"},
- }
-
- salt_mock = {
- "cmd.run": MagicMock(
- return_value="""pattern() = .package-a-alias
-pattern() = package-a
-pattern-visible()
-pattern() = package-c"""
- ),
- }
- with patch.dict("salt.modules.zypperpkg.__salt__", salt_mock):
- assert zypper._get_installed_patterns() == {
- "package-a": {"installed": True, "summary": "description a"},
- "package-c": {"installed": True, "summary": "Non-visible pattern"},
+ "package-a": {"installed": True, "summary": "description a",},
+ "package-c": {"installed": True, "summary": "Non-visible pattern",},
}
@patch("salt.modules.zypperpkg._get_visible_patterns")
def test_list_patterns(self, get_visible_patterns):
"""Test available patterns in the repo"""
get_visible_patterns.return_value = {
- "package-a": {"installed": True, "summary": "description a"},
- "package-b": {"installed": False, "summary": "description b"},
+ "package-a": {"installed": True, "summary": "description a",},
+ "package-b": {"installed": False, "summary": "description b",},
}
assert zypper.list_patterns() == {
- "package-a": {"installed": True, "summary": "description a"},
- "package-b": {"installed": False, "summary": "description b"},
- }
-
- def test__clean_cache_empty(self):
- """Test that an empty cached can be cleaned"""
- context = {}
- with patch.dict(zypper.__context__, context):
- zypper._clean_cache()
- assert context == {}
-
- def test__clean_cache_filled(self):
- """Test that a filled cached can be cleaned"""
- context = {
- "pkg.list_pkgs_/mnt_[]": None,
- "pkg.list_pkgs_/mnt_[patterns]": None,
- "pkg.list_provides": None,
- "pkg.other_data": None,
+ "package-a": {"installed": True, "summary": "description a",},
+ "package-b": {"installed": False, "summary": "description b",},
}
- with patch.dict(zypper.__context__, context):
- zypper._clean_cache()
- self.assertEqual(zypper.__context__, {"pkg.other_data": None})
diff --git a/tests/unit/states/test_btrfs.py b/tests/unit/states/test_btrfs.py
index fdbf06bd13..74e44641b8 100644
--- a/tests/unit/states/test_btrfs.py
+++ b/tests/unit/states/test_btrfs.py
@@ -1,27 +1,45 @@
+#
+# Author: Alberto Planas <aplanas@suse.com>
+#
+# Copyright 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
"""
:maintainer: Alberto Planas <aplanas@suse.com>
:platform: Linux
"""
-
import pytest
import salt.states.btrfs as btrfs
-import salt.utils.platform
from salt.exceptions import CommandExecutionError
-
-# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
-from tests.support.mock import MagicMock, patch
+from tests.support.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch
from tests.support.unit import TestCase, skipIf
-@skipIf(salt.utils.platform.is_windows(), "Non-Windows feature")
+@skipIf(NO_MOCK, NO_MOCK_REASON)
class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"""
Test cases for salt.states.btrfs
"""
def setup_loader_modules(self):
- return {btrfs: {"__salt__": {}, "__states__": {}, "__utils__": {}}}
+ return {btrfs: {"__salt__": {}, "__states__": {}, "__utils__": {},}}
@patch("salt.states.btrfs._umount")
@patch("tempfile.mkdtemp")
@@ -112,9 +130,9 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"""
salt_mock = {
"btrfs.subvolume_show": MagicMock(
- return_value={"@/var": {"subvolume id": "256"}}
+ return_value={"@/var": {"subvolume id": "256"},}
),
- "btrfs.subvolume_get_default": MagicMock(return_value={"id": "5"}),
+ "btrfs.subvolume_get_default": MagicMock(return_value={"id": "5",}),
}
with patch.dict(btrfs.__salt__, salt_mock):
assert not btrfs._is_default("/tmp/xxx/@/var", "/tmp/xxx", "@/var")
@@ -127,9 +145,9 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"""
salt_mock = {
"btrfs.subvolume_show": MagicMock(
- return_value={"@/var": {"subvolume id": "256"}}
+ return_value={"@/var": {"subvolume id": "256"},}
),
- "btrfs.subvolume_get_default": MagicMock(return_value={"id": "256"}),
+ "btrfs.subvolume_get_default": MagicMock(return_value={"id": "256",}),
}
with patch.dict(btrfs.__salt__, salt_mock):
assert btrfs._is_default("/tmp/xxx/@/var", "/tmp/xxx", "@/var")
@@ -142,7 +160,7 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"""
salt_mock = {
"btrfs.subvolume_show": MagicMock(
- return_value={"@/var": {"subvolume id": "256"}}
+ return_value={"@/var": {"subvolume id": "256"},}
),
"btrfs.subvolume_set_default": MagicMock(return_value=True),
}
@@ -158,7 +176,7 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
Test if the subvolume is copy on write.
"""
salt_mock = {
- "file.lsattr": MagicMock(return_value={"/tmp/xxx/@/var": ["C"]}),
+ "file.lsattr": MagicMock(return_value={"/tmp/xxx/@/var": ["C"],}),
}
with patch.dict(btrfs.__salt__, salt_mock):
assert not btrfs._is_cow("/tmp/xxx/@/var")
@@ -169,7 +187,7 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
Test if the subvolume is copy on write.
"""
salt_mock = {
- "file.lsattr": MagicMock(return_value={"/tmp/xxx/@/var": []}),
+ "file.lsattr": MagicMock(return_value={"/tmp/xxx/@/var": [],}),
}
with patch.dict(btrfs.__salt__, salt_mock):
assert btrfs._is_cow("/tmp/xxx/@/var")
@@ -188,7 +206,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"/tmp/xxx/@/var", operator="add", attributes="C"
)
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._umount")
@patch("salt.states.btrfs._mount")
def test_subvolume_created_exists(self, mount, umount):
@@ -215,34 +232,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
mount.assert_called_once()
umount.assert_called_once()
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
- @patch("salt.states.btrfs._umount")
- @patch("salt.states.btrfs._mount")
- def test_subvolume_created_exists_decorator(self, mount, umount):
- """
- Test creating a subvolume using a non-kwargs call
- """
- mount.return_value = "/tmp/xxx"
- salt_mock = {
- "btrfs.subvolume_exists": MagicMock(return_value=True),
- }
- opts_mock = {
- "test": False,
- }
- with patch.dict(btrfs.__salt__, salt_mock), patch.dict(
- btrfs.__opts__, opts_mock
- ):
- assert btrfs.subvolume_created("@/var", "/dev/sda1") == {
- "name": "@/var",
- "result": True,
- "changes": {},
- "comment": ["Subvolume @/var already present"],
- }
- salt_mock["btrfs.subvolume_exists"].assert_called_with("/tmp/xxx/@/var")
- mount.assert_called_once()
- umount.assert_called_once()
-
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._umount")
@patch("salt.states.btrfs._mount")
def test_subvolume_created_exists_test(self, mount, umount):
@@ -269,7 +258,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
mount.assert_called_once()
umount.assert_called_once()
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._is_default")
@patch("salt.states.btrfs._umount")
@patch("salt.states.btrfs._mount")
@@ -300,7 +288,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
mount.assert_called_once()
umount.assert_called_once()
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._set_default")
@patch("salt.states.btrfs._is_default")
@patch("salt.states.btrfs._umount")
@@ -335,7 +322,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
mount.assert_called_once()
umount.assert_called_once()
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._set_default")
@patch("salt.states.btrfs._is_default")
@patch("salt.states.btrfs._umount")
@@ -373,7 +359,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
mount.assert_called_once()
umount.assert_called_once()
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._is_cow")
@patch("salt.states.btrfs._umount")
@patch("salt.states.btrfs._mount")
@@ -404,7 +389,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
mount.assert_called_once()
umount.assert_called_once()
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._unset_cow")
@patch("salt.states.btrfs._is_cow")
@patch("salt.states.btrfs._umount")
@@ -437,7 +421,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
mount.assert_called_once()
umount.assert_called_once()
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._umount")
@patch("salt.states.btrfs._mount")
def test_subvolume_created(self, mount, umount):
@@ -469,7 +452,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
mount.assert_called_once()
umount.assert_called_once()
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._umount")
@patch("salt.states.btrfs._mount")
def test_subvolume_created_fails_directory(self, mount, umount):
@@ -499,7 +481,6 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
mount.assert_called_once()
umount.assert_called_once()
- @skipIf(salt.utils.platform.is_windows(), "Skip on Windows")
@patch("salt.states.btrfs._umount")
@patch("salt.states.btrfs._mount")
def test_subvolume_created_fails(self, mount, umount):
@@ -541,7 +522,7 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"description": "Set/get compression for a file or directory",
"value": "N/A",
},
- "label": {"description": "Set/get label of device.", "value": "N/A"},
+ "label": {"description": "Set/get label of device.", "value": "N/A",},
"ro": {
"description": "Set/get read-only flag or subvolume",
"value": "N/A",
@@ -560,7 +541,7 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"description": "Set/get compression for a file or directory",
"value": "N/A",
},
- "label": {"description": "Set/get label of device.", "value": "N/A"},
+ "label": {"description": "Set/get label of device.", "value": "N/A",},
"ro": {
"description": "Set/get read-only flag or subvolume",
"value": "N/A",
@@ -578,7 +559,7 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"description": "Set/get compression for a file or directory",
"value": "N/A",
},
- "label": {"description": "Set/get label of device.", "value": "mylabel"},
+ "label": {"description": "Set/get label of device.", "value": "mylabel",},
"ro": {
"description": "Set/get read-only flag or subvolume",
"value": "N/A",
@@ -596,7 +577,7 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"description": "Set/get compression for a file or directory",
"value": "N/A",
},
- "label": {"description": "Set/get label of device.", "value": "N/A"},
+ "label": {"description": "Set/get label of device.", "value": "N/A",},
"ro": {
"description": "Set/get read-only flag or subvolume",
"value": True,
@@ -614,7 +595,7 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
"description": "Set/get compression for a file or directory",
"value": "N/A",
},
- "label": {"description": "Set/get label of device.", "value": "N/A"},
+ "label": {"description": "Set/get label of device.", "value": "N/A",},
"ro": {
"description": "Set/get read-only flag or subvolume",
"value": "N/A",
@@ -755,40 +736,3 @@ class BtrfsTestCase(TestCase, LoaderModuleMockMixin):
)
mount.assert_called_once()
umount.assert_called_once()
-
- @patch("salt.states.btrfs._umount")
- @patch("salt.states.btrfs._mount")
- @patch("os.path.exists")
- def test_properties_test(self, exists, mount, umount):
- """
- Test setting a property in test mode.
- """
- exists.return_value = True
- mount.return_value = "/tmp/xxx"
- salt_mock = {
- "btrfs.properties": MagicMock(
- side_effect=[
- {
- "ro": {
- "description": "Set/get read-only flag or subvolume",
- "value": "N/A",
- },
- },
- ]
- ),
- }
- opts_mock = {
- "test": True,
- }
- with patch.dict(btrfs.__salt__, salt_mock), patch.dict(
- btrfs.__opts__, opts_mock
- ):
- assert btrfs.properties(name="@/var", device="/dev/sda1", ro=True) == {
- "name": "@/var",
- "result": None,
- "changes": {"ro": "true"},
- "comment": [],
- }
- salt_mock["btrfs.properties"].assert_called_with("/tmp/xxx/@/var")
- mount.assert_called_once()
- umount.assert_called_once()
diff --git a/tests/unit/states/test_pkg.py b/tests/unit/states/test_pkg.py
index 15ca937e13..a7ddfece14 100644
--- a/tests/unit/states/test_pkg.py
+++ b/tests/unit/states/test_pkg.py
@@ -1,15 +1,6 @@
-# -*- coding: utf-8 -*-
-
-# Import Python libs
-from __future__ import absolute_import
-
import salt.states.pkg as pkg
-
-# Import Salt Libs
from salt.ext import six
from salt.ext.six.moves import zip
-
-# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
@@ -35,7 +26,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
"""
list_upgrades = MagicMock(
return_value={
- pkgname: pkgver["new"] for pkgname, pkgver in six.iteritems(self.pkgs)
+ pkgname: pkgver["new"] for pkgname, pkgver in self.pkgs.items()
}
)
upgrade = MagicMock(return_value=self.pkgs)
@@ -75,7 +66,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
list_upgrades = MagicMock(
return_value={
- pkgname: pkgver["new"] for pkgname, pkgver in six.iteritems(self.pkgs)
+ pkgname: pkgver["new"] for pkgname, pkgver in self.pkgs.items()
}
)
upgrade = MagicMock(return_value=self.pkgs)
@@ -92,9 +83,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
# Run state with test=false
with patch.dict(pkg.__opts__, {"test": False}):
ret = pkg.uptodate(
- "dummy",
- test=True,
- pkgs=[pkgname for pkgname in six.iterkeys(self.pkgs)],
+ "dummy", test=True, pkgs=[pkgname for pkgname in self.pkgs.keys()],
)
self.assertTrue(ret["result"])
self.assertDictEqual(ret["changes"], pkgs)
@@ -102,9 +91,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
# Run state with test=true
with patch.dict(pkg.__opts__, {"test": True}):
ret = pkg.uptodate(
- "dummy",
- test=True,
- pkgs=[pkgname for pkgname in six.iterkeys(self.pkgs)],
+ "dummy", test=True, pkgs=[pkgname for pkgname in self.pkgs.keys()],
)
self.assertIsNone(ret["result"])
self.assertDictEqual(ret["changes"], pkgs)
@@ -146,9 +133,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
# Run state with test=false
with patch.dict(pkg.__opts__, {"test": False}):
ret = pkg.uptodate(
- "dummy",
- test=True,
- pkgs=[pkgname for pkgname in six.iterkeys(self.pkgs)],
+ "dummy", test=True, pkgs=[pkgname for pkgname in self.pkgs.keys()],
)
self.assertTrue(ret["result"])
self.assertDictEqual(ret["changes"], {})
@@ -156,9 +141,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
# Run state with test=true
with patch.dict(pkg.__opts__, {"test": True}):
ret = pkg.uptodate(
- "dummy",
- test=True,
- pkgs=[pkgname for pkgname in six.iterkeys(self.pkgs)],
+ "dummy", test=True, pkgs=[pkgname for pkgname in self.pkgs.keys()],
)
self.assertTrue(ret["result"])
self.assertDictEqual(ret["changes"], {})
@@ -176,7 +159,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
list_upgrades = MagicMock(
return_value={
- pkgname: pkgver["new"] for pkgname, pkgver in six.iteritems(self.pkgs)
+ pkgname: pkgver["new"] for pkgname, pkgver in self.pkgs.items()
}
)
upgrade = MagicMock(return_value={})
@@ -193,9 +176,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
# Run state with test=false
with patch.dict(pkg.__opts__, {"test": False}):
ret = pkg.uptodate(
- "dummy",
- test=True,
- pkgs=[pkgname for pkgname in six.iterkeys(self.pkgs)],
+ "dummy", test=True, pkgs=[pkgname for pkgname in self.pkgs.keys()],
)
self.assertFalse(ret["result"])
self.assertDictEqual(ret["changes"], {})
@@ -203,9 +184,7 @@ class PkgTestCase(TestCase, LoaderModuleMockMixin):
# Run state with test=true
with patch.dict(pkg.__opts__, {"test": True}):
ret = pkg.uptodate(
- "dummy",
- test=True,
- pkgs=[pkgname for pkgname in six.iterkeys(self.pkgs)],
+ "dummy", test=True, pkgs=[pkgname for pkgname in self.pkgs.keys()],
)
self.assertIsNone(ret["result"])
self.assertDictEqual(ret["changes"], pkgs)
diff --git a/tests/unit/test_loader.py b/tests/unit/test_loader.py
index 9f826e007f..863e2182b9 100644
--- a/tests/unit/test_loader.py
+++ b/tests/unit/test_loader.py
@@ -215,6 +215,96 @@ class LazyLoaderUtilsTest(TestCase):
self.assertTrue(self.module_name + ".run" not in loader)
+loader_template_module = """
+import my_utils
+
+def run():
+ return my_utils.run()
+"""
+
+loader_template_utils = """
+def run():
+ return True
+"""
+
+
+class LazyLoaderUtilsTest(TestCase):
+ """
+ Test the loader
+ """
+
+ module_name = "lazyloaderutilstest"
+ utils_name = "my_utils"
+
+ @classmethod
+ def setUpClass(cls):
+ cls.opts = salt.config.minion_config(None)
+ cls.opts["grains"] = salt.loader.grains(cls.opts)
+ if not os.path.isdir(TMP):
+ os.makedirs(TMP)
+
+ def setUp(self):
+ # Setup the module
+ self.module_dir = tempfile.mkdtemp(dir=TMP)
+ self.module_file = os.path.join(
+ self.module_dir, "{}.py".format(self.module_name)
+ )
+ with salt.utils.files.fopen(self.module_file, "w") as fh:
+ fh.write(salt.utils.stringutils.to_str(loader_template_module))
+ fh.flush()
+ os.fsync(fh.fileno())
+
+ self.utils_dir = tempfile.mkdtemp(dir=TMP)
+ self.utils_file = os.path.join(self.utils_dir, "{}.py".format(self.utils_name))
+ with salt.utils.files.fopen(self.utils_file, "w") as fh:
+ fh.write(salt.utils.stringutils.to_str(loader_template_utils))
+ fh.flush()
+ os.fsync(fh.fileno())
+
+ def tearDown(self):
+ shutil.rmtree(self.module_dir)
+ if os.path.isdir(self.module_dir):
+ shutil.rmtree(self.module_dir)
+ shutil.rmtree(self.utils_dir)
+ if os.path.isdir(self.utils_dir):
+ shutil.rmtree(self.utils_dir)
+ del self.module_dir
+ del self.module_file
+ del self.utils_dir
+ del self.utils_file
+
+ if self.module_name in sys.modules:
+ del sys.modules[self.module_name]
+ if self.utils_name in sys.modules:
+ del sys.modules[self.utils_name]
+
+ @classmethod
+ def tearDownClass(cls):
+ del cls.opts
+
+ def test_utils_found(self):
+ """
+ Test that the extra module directory is available for imports
+ """
+ loader = salt.loader.LazyLoader(
+ [self.module_dir],
+ copy.deepcopy(self.opts),
+ tag="module",
+ extra_module_dirs=[self.utils_dir],
+ )
+ self.assertTrue(inspect.isfunction(loader[self.module_name + ".run"]))
+ self.assertTrue(loader[self.module_name + ".run"]())
+
+ def test_utils_not_found(self):
+ """
+ Test that the extra module directory is not available for imports
+ """
+ loader = salt.loader.LazyLoader(
+ [self.module_dir], copy.deepcopy(self.opts), tag="module"
+ )
+ self.assertTrue(self.module_name + ".run" not in loader)
+
+
class LazyLoaderVirtualEnabledTest(TestCase):
"""
Test the base loader of salt.
@@ -1342,9 +1432,10 @@ class LoaderGlobalsTest(ModuleCase):
)
# Now, test each module!
- for item in global_vars.values():
- for name in names:
- self.assertIn(name, list(item.keys()))
+ for item in global_vars:
+ if item["__name__"].startswith("salt.loaded"):
+ for name in names:
+ self.assertIn(name, list(item.keys()))
def test_auth(self):
"""
--
2.29.2