Merge branch 'develop' into improvement-spm-base_paths

This commit is contained in:
plastikos 2018-05-15 10:36:03 -06:00 committed by GitHub
commit 52248ff433
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 1317 additions and 800 deletions

View File

@ -1,5 +1,5 @@
---
<% vagrant = system('which vagrant 2>/dev/null >/dev/null') %>
<% vagrant = system('gem list -i kitchen-vagrant 2>/dev/null >/dev/null') %>
<% version = '2017.7.4' %>
<% platformsfile = ENV['SALT_KITCHEN_PLATFORMS'] || '.kitchen/platforms.yml' %>
<% driverfile = ENV['SALT_KITCHEN_DRIVER'] || '.kitchen/driver.yml' %>
@ -94,12 +94,9 @@ platforms:
- yum install -y upstart
provisioner:
salt_bootstrap_options: -P -p rsync -y -x python2.7 -X git v<%= version %> >/dev/null
- name: ubuntu-rolling
- name: ubuntu-18.04
driver_config:
image: ubuntu:rolling
run_command: /lib/systemd/systemd
provisioner:
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.sh
- name: ubuntu-16.04
driver_config:
run_command: /lib/systemd/systemd

View File

@ -38,7 +38,10 @@ from __future__ import division
import re
from docutils import nodes
from docutils.parsers.rst import directives
from sphinx.util.compat import Directive
try:
from sphinx.util.compat import Directive
except ImportError:
from docutils.parsers.rst import Directive
CONTROL_HEIGHT = 30

View File

@ -17,3 +17,4 @@ roster modules
flat
range
scan
sshconfig

View File

@ -0,0 +1,6 @@
=====================
salt.roster.sshconfig
=====================
.. automodule:: salt.roster.sshconfig
:members:

View File

@ -314,11 +314,14 @@ state modules
winrepo
x509
xmpp
zabbix_action
zabbix_host
zabbix_hostgroup
zabbix_mediatype
zabbix_template
zabbix_user
zabbix_usergroup
zabbix_valuemap
zcbuildout
zenoss
zk_concurrency

View File

@ -1,5 +1,5 @@
salt.states.zabbix_action module
==============================
salt.states.zabbix_action
=========================
.. automodule:: salt.states.zabbix_action
:members:

View File

@ -1,5 +1,5 @@
salt.states.zabbix_template module
==============================
salt.states.zabbix_template
===========================
.. automodule:: salt.states.zabbix_template
:members:

View File

@ -1,5 +1,5 @@
salt.states.zabbix_valuemap module
==============================
salt.states.zabbix_valuemap
===========================
.. automodule:: salt.states.zabbix_valuemap
:members:

View File

@ -1,8 +1,9 @@
===========================
Salt 2017.7.6 Release Notes
In Progress: Salt 2017.7.6 Release Notes
===========================
Version 2017.7.6 is a bugfix release for :ref:`2017.7.0 <release-2017-7-0>`.
Version 2017.7.6 is an **unreleased** bugfix release for :ref:`2017.7.0 <release-2017-7-0>`.
This release is still in progress and has not been released yet.
Option to Return to Previous Pillar Include Behavior
----------------------------------------------------

View File

@ -59,11 +59,13 @@ To match a nodegroup on the CLI, use the ``-N`` command-line option:
salt -N group1 test.ping
.. versionadded:: Fluorine
.. note::
The ``N@`` classifier cannot be used in compound matches within the CLI or
:term:`top file`, it is only recognized in the :conf_master:`nodegroups`
master config file parameter.
The ``N@`` classifier historically could not be used in compound matches
within the CLI or :term:`top file`, it was only recognized in the
:conf_master:`nodegroups` master config file parameter. As of Fluorine
release, this limitation no longer exists.
To match a nodegroup in your :term:`top file`, make sure to put ``- match:
nodegroup`` on the line directly following the nodegroup name.

View File

@ -740,7 +740,7 @@ Function ${un}uninstallSalt
# Remove files
Delete "$INSTDIR\uninst.exe"
Delete "$INSTDIR\nssm.exe"
Delete "$INSTDIR\ssm.exe"
Delete "$INSTDIR\salt*"
Delete "$INSTDIR\vcredist.exe"
RMDir /r "$INSTDIR\bin"

View File

@ -35,7 +35,7 @@ Function Get-Settings {
# Prerequisite software
$Prerequisites = @{
"NSIS" = "nsis-3.02.1-setup.exe"
"NSIS" = "nsis-3.03-setup.exe"
"VCforPython" = "VCForPython27.msi"
"VCppBuildTools" = "visualcppbuildtools_full.exe"
}
@ -59,21 +59,15 @@ Function Get-Settings {
# Filenames for 64 bit Windows
$64bitPrograms = @{
"PyCrypto2" = "pycrypto-2.6.1-cp27-none-win_amd64.whl"
"Python2" = "python-2.7.14.amd64.msi"
"PyWin322" = "pywin32-221-cp27-cp27m-win_amd64.whl"
"Python3" = "python-3.5.3-amd64.exe"
"PyWin323" = "pywin32-221-cp35-cp35m-win_amd64.whl"
}
$ini.Add("64bitPrograms", $64bitPrograms)
# Filenames for 32 bit Windows
$32bitPrograms = @{
"PyCrypto2" = "pycrypto-2.6.1-cp27-none-win32.whl"
"Python2" = "python-2.7.14.msi"
"PyWin322" = "pywin32-221-cp27-cp27m-win32.whl"
"Python3" = "python-3.5.3.exe"
"PyWin323" = "pywin32-221-cp35-cp35m-win32.whl"
}
$ini.Add("32bitPrograms", $32bitPrograms)

View File

@ -0,0 +1,4 @@
-r base.txt
# Required by Tornado to handle threads stuff.
futures>=2.0

View File

@ -0,0 +1 @@
-r base.txt

View File

@ -135,9 +135,9 @@ def lowstate_file_refs(chunks, extras=''):
elif state.startswith('__'):
continue
crefs.extend(salt_refs(chunk[state]))
if saltenv not in refs:
refs[saltenv] = []
if crefs:
if saltenv not in refs:
refs[saltenv] = []
refs[saltenv].append(crefs)
if extras:
extra_refs = extras.split(',')

View File

@ -3699,6 +3699,25 @@ def enable_term_protect(name, call=None):
return _toggle_term_protect(name, 'true')
def disable_term_protect(name, call=None):
'''
Disable termination protection on a node
CLI Example:
.. code-block:: bash
salt-cloud -a disable_term_protect mymachine
'''
if call != 'action':
raise SaltCloudSystemExit(
'The enable_term_protect action must be called with '
'-a or --action.'
)
return _toggle_term_protect(name, 'false')
def disable_detailed_monitoring(name, call=None):
'''
Enable/disable detailed monitoring on a node

View File

@ -3421,7 +3421,7 @@ def is_profile_configured(opts, provider, profile_name, vm_=None):
# Most drivers need a size, but some do not.
non_size_drivers = ['opennebula', 'parallels', 'proxmox', 'scaleway',
'softlayer', 'softlayer_hw', 'vmware', 'vsphere',
'virtualbox', 'libvirt', 'oneandone']
'virtualbox', 'libvirt', 'oneandone', 'profitbricks']
provider_key = opts['providers'][alias][driver]
profile_key = opts['providers'][alias][driver]['profiles'][profile_name]

View File

@ -459,7 +459,11 @@ def _bsd_memdata(osdata):
if osdata['kernel'] in ['OpenBSD', 'NetBSD']:
swapctl = salt.utils.path.which('swapctl')
swap_total = __salt__['cmd.run']('{0} -sk'.format(swapctl)).split(' ')[1]
swap_data = __salt__['cmd.run']('{0} -sk'.format(swapctl))
if swap_data == 'no swap devices configured':
swap_total = 0
else:
swap_total = swap_data.split(' ')[1]
else:
swap_total = __salt__['cmd.run']('{0} -n vm.swap_total'.format(sysctl))
grains['swap_total'] = int(swap_total) // 1024 // 1024

View File

@ -3370,6 +3370,8 @@ class Matcher(object):
'''
Runs the compound target check
'''
nodegroups = self.opts.get('nodegroups', {})
if not isinstance(tgt, six.string_types) and not isinstance(tgt, (list, tuple)):
log.error('Compound target received that is neither string, list nor tuple')
return False
@ -3391,9 +3393,11 @@ class Matcher(object):
if isinstance(tgt, six.string_types):
words = tgt.split()
else:
words = tgt
# we make a shallow copy in order to not affect the passed in arg
words = tgt[:]
for word in words:
while words:
word = words.pop(0)
target_info = salt.utils.minions.parse_target(word)
# Easy check first
@ -3415,10 +3419,12 @@ class Matcher(object):
elif target_info and target_info['engine']:
if 'N' == target_info['engine']:
# Nodegroups should already be expanded/resolved to other engines
log.error(
'Detected nodegroup expansion failure of "%s"', word)
return False
# if we encounter a node group, just evaluate it in-place
decomposed = salt.utils.minions.nodegroup_comp(target_info['pattern'], nodegroups)
if decomposed:
words = decomposed + words
continue
engine = ref.get(target_info['engine'])
if not engine:
# If an unknown engine is called at any time, fail out

View File

@ -36,6 +36,7 @@ import salt.utils.timed_subprocess
import salt.utils.user
import salt.utils.versions
import salt.utils.vt
import salt.utils.win_dacl
import salt.utils.win_reg
import salt.grains.extra
from salt.ext import six
@ -542,6 +543,7 @@ def _run(cmd,
env.setdefault('LC_TELEPHONE', 'C')
env.setdefault('LC_MEASUREMENT', 'C')
env.setdefault('LC_IDENTIFICATION', 'C')
env.setdefault('LANGUAGE', 'C')
else:
# On Windows set the codepage to US English.
if python_shell:
@ -2415,11 +2417,14 @@ def script(source,
# "env" is not supported; Use "saltenv".
kwargs.pop('__env__')
win_cwd = False
if salt.utils.platform.is_windows() and runas and cwd is None:
# Create a temp working directory
cwd = tempfile.mkdtemp(dir=__opts__['cachedir'])
__salt__['win_dacl.add_ace'](
cwd, 'File', runas, 'READ&EXECUTE', 'ALLOW',
'FOLDER&SUBFOLDERS&FILES')
win_cwd = True
salt.utils.win_dacl.set_permissions(obj_name=cwd,
principal=runas,
permissions='full_control')
path = salt.utils.files.mkstemp(dir=cwd, suffix=os.path.splitext(source)[1])
@ -2433,10 +2438,10 @@ def script(source,
saltenv,
**kwargs)
if not fn_:
if salt.utils.platform.is_windows() and runas:
_cleanup_tempfile(path)
# If a temp working directory was created (Windows), let's remove that
if win_cwd:
_cleanup_tempfile(cwd)
else:
_cleanup_tempfile(path)
return {'pid': 0,
'retcode': 1,
'stdout': '',
@ -2445,10 +2450,10 @@ def script(source,
else:
fn_ = __salt__['cp.cache_file'](source, saltenv)
if not fn_:
if salt.utils.platform.is_windows() and runas:
_cleanup_tempfile(path)
# If a temp working directory was created (Windows), let's remove that
if win_cwd:
_cleanup_tempfile(cwd)
else:
_cleanup_tempfile(path)
return {'pid': 0,
'retcode': 1,
'stdout': '',
@ -2481,10 +2486,10 @@ def script(source,
password=password,
success_retcodes=success_retcodes,
**kwargs)
if salt.utils.platform.is_windows() and runas:
_cleanup_tempfile(path)
# If a temp working directory was created (Windows), let's remove that
if win_cwd:
_cleanup_tempfile(cwd)
else:
_cleanup_tempfile(path)
if hide_output:
ret['stdout'] = ret['stderr'] = ''

View File

@ -867,7 +867,7 @@ def _network_conf(conf_tuples=None, **kwargs):
# on old versions of lxc, still support the gateway auto mode
# if we didn't explicitly say no to
# (lxc.network.ipv4.gateway: auto)
if _LooseVersion(version()) <= '1.0.7' and \
if _LooseVersion(version()) <= _LooseVersion('1.0.7') and \
True not in ['lxc.network.ipv4.gateway' in a for a in ret] and \
True in ['lxc.network.ipv4' in a for a in ret]:
ret.append({'lxc.network.ipv4.gateway': 'auto'})
@ -2077,7 +2077,7 @@ def clone(name,
if backing in ('dir', 'overlayfs', 'btrfs'):
size = None
# LXC commands and options changed in 2.0 - CF issue #34086 for details
if version() >= _LooseVersion('2.0'):
if _LooseVersion(version()) >= _LooseVersion('2.0'):
# https://linuxcontainers.org/lxc/manpages//man1/lxc-copy.1.html
cmd = 'lxc-copy'
cmd += ' {0} -n {1} -N {2}'.format(snapshot, orig, name)

View File

@ -119,40 +119,82 @@ def __virtual__():
return 'pip'
def _clear_context(bin_env=None):
'''
Remove the cached pip version
'''
contextkey = 'pip.version'
if bin_env is not None:
contextkey = '{0}.{1}'.format(contextkey, bin_env)
__context__.pop(contextkey, None)
def _get_pip_bin(bin_env):
'''
Locate the pip binary, either from `bin_env` as a virtualenv, as the
executable itself, or from searching conventional filesystem locations
'''
if not bin_env:
which_result = __salt__['cmd.which_bin'](
['pip{0}.{1}'.format(*sys.version_info[:2]),
'pip{0}'.format(sys.version_info[0]),
'pip', 'pip-python']
)
if salt.utils.platform.is_windows() and six.PY2 \
and isinstance(which_result, str):
which_result.encode('string-escape')
if which_result is None:
raise CommandNotFoundError('Could not find a `pip` binary')
return which_result
logger.debug('pip: Using pip from currently-running Python')
return [os.path.normpath(sys.executable), '-m', 'pip']
# try to get pip bin from virtualenv, bin_env
python_bin = 'python.exe' if salt.utils.platform.is_windows() else 'python'
def _search_paths(*basedirs):
ret = []
for path in basedirs:
ret.extend([
os.path.join(path, python_bin),
os.path.join(path, 'bin', python_bin),
os.path.join(path, 'Scripts', python_bin)
])
return ret
# try to get python bin from virtualenv (i.e. bin_env)
if os.path.isdir(bin_env):
if salt.utils.platform.is_windows():
pip_bin = os.path.join(bin_env, 'Scripts', 'pip.exe')
else:
pip_bin = os.path.join(bin_env, 'bin', 'pip')
if os.path.isfile(pip_bin):
return pip_bin
msg = 'Could not find a `pip` binary in virtualenv {0}'.format(bin_env)
raise CommandNotFoundError(msg)
# bin_env is the pip binary
for bin_path in _search_paths(bin_env):
if os.path.isfile(bin_path):
if os.access(bin_path, os.X_OK):
logger.debug('pip: Found python binary: %s', bin_path)
return [os.path.normpath(bin_path), '-m', 'pip']
else:
logger.debug(
'pip: Found python binary by name but it is not '
'executable: %s', bin_path
)
raise CommandNotFoundError(
'Could not find a pip binary in virtualenv {0}'.format(bin_env)
)
# bin_env is the python or pip binary
elif os.access(bin_env, os.X_OK):
if os.path.isfile(bin_env) or os.path.islink(bin_env):
return bin_env
if os.path.isfile(bin_env):
# If the python binary was passed, return it
if 'python' in os.path.basename(bin_env):
return [os.path.normpath(bin_env), '-m', 'pip']
# Try to find the python binary based on the location of pip in a
# virtual environment, should be relative
if 'pip' in os.path.basename(bin_env):
# Look in the same directory as the pip binary, and also its
# parent directories.
pip_dirname = os.path.dirname(bin_env)
pip_parent_dir = os.path.dirname(pip_dirname)
for bin_path in _search_paths(pip_dirname, pip_parent_dir):
if os.path.isfile(bin_path):
logger.debug('pip: Found python binary: %s', bin_path)
return [os.path.normpath(bin_path), '-m', 'pip']
# Couldn't find python, use the passed pip binary
# This has the limitation of being unable to update pip itself
return [os.path.normpath(bin_env)]
raise CommandExecutionError(
'Could not find a pip binary within {0}'.format(bin_env)
)
else:
raise CommandNotFoundError('Could not find a `pip` binary')
raise CommandNotFoundError(
'Access denied to {0}, could not find a pip binary'.format(bin_env)
)
def _get_cached_requirements(requirements, saltenv):
@ -271,15 +313,21 @@ def _process_requirements(requirements, cmd, cwd, saltenv, user):
treq = tempfile.mkdtemp()
__salt__['file.chown'](treq, user, None)
# In Windows, just being owner of a file isn't enough. You also
# need permissions
if salt.utils.platform.is_windows():
__utils__['win_dacl.set_permissions'](
obj_name=treq,
principal=user,
permissions='read_execute')
current_directory = None
if not current_directory:
current_directory = os.path.abspath(os.curdir)
logger.info('_process_requirements from directory,' +
'%s -- requirement: %s', cwd, requirement
)
logger.info('_process_requirements from directory, '
'%s -- requirement: %s', cwd, requirement)
if cwd is None:
r = requirement
@ -384,7 +432,6 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
global_options=None,
install_options=None,
user=None,
no_chown=False,
cwd=None,
pre_releases=False,
cert=None,
@ -398,7 +445,8 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
trusted_host=None,
no_cache_dir=False,
cache_dir=None,
no_binary=None):
no_binary=None,
**kwargs):
'''
Install packages with pip
@ -520,10 +568,6 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
user
The user under which to run pip
no_chown
When user is given, do not attempt to copy and chown a requirements
file
cwd
Current working directory to run pip from
@ -584,9 +628,14 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
editable=git+https://github.com/worldcompany/djangoembed.git#egg=djangoembed upgrade=True no_deps=True
'''
pip_bin = _get_pip_bin(bin_env)
cmd = [pip_bin, 'install']
if 'no_chown' in kwargs:
salt.utils.versions.warn_until(
'Flourine',
'The no_chown argument has been deprecated and is no longer used. '
'Its functionality was removed in Boron.')
kwargs.pop('no_chown')
cmd = _get_pip_bin(bin_env)
cmd.append('install')
cleanup_requirements, error = _process_requirements(
requirements=requirements,
@ -599,10 +648,11 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
if error:
return error
cur_version = version(bin_env)
if use_wheel:
min_version = '1.4'
max_version = '9.0.3'
cur_version = __salt__['pip.version'](bin_env)
too_low = salt.utils.versions.compare(ver1=cur_version, oper='<', ver2=min_version)
too_high = salt.utils.versions.compare(ver1=cur_version, oper='>', ver2=max_version)
if too_low or too_high:
@ -617,7 +667,6 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
if no_use_wheel:
min_version = '1.4'
max_version = '9.0.3'
cur_version = __salt__['pip.version'](bin_env)
too_low = salt.utils.versions.compare(ver1=cur_version, oper='<', ver2=min_version)
too_high = salt.utils.versions.compare(ver1=cur_version, oper='>', ver2=max_version)
if too_low or too_high:
@ -631,7 +680,6 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
if no_binary:
min_version = '7.0.0'
cur_version = __salt__['pip.version'](bin_env)
too_low = salt.utils.versions.compare(ver1=cur_version, oper='<', ver2=min_version)
if too_low:
logger.error(
@ -706,8 +754,7 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
if mirrors:
# https://github.com/pypa/pip/pull/2641/files#diff-3ef137fb9ffdd400f117a565cd94c188L216
pip_version = version(pip_bin)
if salt.utils.versions.compare(ver1=pip_version, oper='>=', ver2='7.0.0'):
if salt.utils.versions.compare(ver1=cur_version, oper='>=', ver2='7.0.0'):
raise CommandExecutionError(
'pip >= 7.0.0 does not support mirror argument:'
' use index_url and/or extra_index_url instead'
@ -735,7 +782,7 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
if download_cache or cache_dir:
cmd.extend(['--cache-dir' if salt.utils.versions.compare(
ver1=version(bin_env), oper='>=', ver2='6.0'
ver1=cur_version, oper='>=', ver2='6.0'
) else '--download-cache', download_cache or cache_dir])
if source:
@ -772,7 +819,7 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
if pre_releases:
# Check the locally installed pip version
pip_version = version(pip_bin)
pip_version = cur_version
# From pip v1.4 the --pre flag is available
if salt.utils.versions.compare(ver1=pip_version, oper='>=', ver2='1.4'):
@ -857,6 +904,9 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
cmd_kwargs = dict(saltenv=saltenv, use_vt=use_vt, runas=user)
if kwargs:
cmd_kwargs.update(kwargs)
if env_vars:
cmd_kwargs.setdefault('env', {}).update(_format_env_vars(env_vars))
@ -874,6 +924,7 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
return __salt__['cmd.run_all'](cmd, python_shell=False, **cmd_kwargs)
finally:
_clear_context(bin_env)
for tempdir in [cr for cr in cleanup_requirements if cr is not None]:
if os.path.isdir(tempdir):
shutil.rmtree(tempdir)
@ -886,7 +937,6 @@ def uninstall(pkgs=None,
proxy=None,
timeout=None,
user=None,
no_chown=False,
cwd=None,
saltenv='base',
use_vt=False):
@ -919,11 +969,6 @@ def uninstall(pkgs=None,
Set the socket timeout (default 15 seconds)
user
The user under which to run pip
no_chown
When user is given, do not attempt to copy and chown
a requirements file (needed if the requirements file refers to other
files via relative paths, as the copy-and-chown procedure does not
account for such files)
cwd
Current working directory to run pip from
use_vt
@ -939,9 +984,8 @@ def uninstall(pkgs=None,
salt '*' pip.uninstall <package name> bin_env=/path/to/pip_bin
'''
pip_bin = _get_pip_bin(bin_env)
cmd = [pip_bin, 'uninstall', '-y']
cmd = _get_pip_bin(bin_env)
cmd.extend(['uninstall', '-y'])
cleanup_requirements, error = _process_requirements(
requirements=requirements, cmd=cmd, saltenv=saltenv, user=user,
@ -1001,6 +1045,7 @@ def uninstall(pkgs=None,
try:
return __salt__['cmd.run_all'](cmd, **cmd_kwargs)
finally:
_clear_context(bin_env)
for requirement in cleanup_requirements:
if requirement:
try:
@ -1013,7 +1058,8 @@ def freeze(bin_env=None,
user=None,
cwd=None,
use_vt=False,
env_vars=None):
env_vars=None,
**kwargs):
'''
Return a list of installed packages either globally or in the specified
virtualenv
@ -1046,15 +1092,13 @@ def freeze(bin_env=None,
The packages pip, wheel, setuptools, and distribute are included if the
installed pip is new enough.
'''
pip_bin = _get_pip_bin(bin_env)
cmd = [pip_bin, 'freeze']
cmd = _get_pip_bin(bin_env)
cmd.append('freeze')
# Include pip, setuptools, distribute, wheel
min_version = '8.0.3'
cur_version = version(bin_env)
if not salt.utils.versions.compare(ver1=cur_version, oper='>=',
ver2=min_version):
if salt.utils.versions.compare(ver1=cur_version, oper='<', ver2=min_version):
logger.warning(
'The version of pip installed is %s, which is older than %s. '
'The packages pip, wheel, setuptools, and distribute will not be '
@ -1064,14 +1108,16 @@ def freeze(bin_env=None,
cmd.append('--all')
cmd_kwargs = dict(runas=user, cwd=cwd, use_vt=use_vt, python_shell=False)
if kwargs:
cmd_kwargs.update(**kwargs)
if bin_env and os.path.isdir(bin_env):
cmd_kwargs['env'] = {'VIRTUAL_ENV': bin_env}
if env_vars:
cmd_kwargs.setdefault('env', {}).update(_format_env_vars(env_vars))
result = __salt__['cmd.run_all'](cmd, **cmd_kwargs)
if result['retcode'] > 0:
raise CommandExecutionError(result['stderr'])
if result['retcode']:
raise CommandExecutionError(result['stderr'], info=result)
return result['stdout'].splitlines()
@ -1080,7 +1126,8 @@ def list_(prefix=None,
bin_env=None,
user=None,
cwd=None,
env_vars=None):
env_vars=None,
**kwargs):
'''
Filter list of installed apps from ``freeze`` and check to see if
``prefix`` exists in the list of packages installed.
@ -1109,7 +1156,11 @@ def list_(prefix=None,
if prefix is None or 'pip'.startswith(prefix):
packages['pip'] = version(bin_env)
for line in freeze(bin_env=bin_env, user=user, cwd=cwd, env_vars=env_vars):
for line in freeze(bin_env=bin_env,
user=user,
cwd=cwd,
env_vars=env_vars,
**kwargs):
if line.startswith('-f') or line.startswith('#'):
# ignore -f line as it contains --find-links directory
# ignore comment lines
@ -1119,7 +1170,15 @@ def list_(prefix=None,
continue
elif line.startswith('-e'):
line = line.split('-e ')[1]
version_, name = line.split('#egg=')
if '#egg=' in line:
version_, name = line.split('#egg=')
else:
if len(line.split('===')) >= 2:
name = line.split('===')[0]
version_ = line.split('===')[1]
elif len(line.split('==')) >= 2:
name = line.split('==')[0]
version_ = line.split('==')[1]
elif len(line.split('===')) >= 2:
name = line.split('===')[0]
version_ = line.split('===')[1]
@ -1154,14 +1213,27 @@ def version(bin_env=None):
salt '*' pip.version
'''
pip_bin = _get_pip_bin(bin_env)
contextkey = 'pip.version'
if bin_env is not None:
contextkey = '{0}.{1}'.format(contextkey, bin_env)
if contextkey in __context__:
return __context__[contextkey]
cmd = _get_pip_bin(bin_env)[:]
cmd.append('--version')
ret = __salt__['cmd.run_all'](cmd, python_shell=False)
if ret['retcode']:
raise CommandNotFoundError('Could not find a `pip` binary')
output = __salt__['cmd.run_stdout'](
'{0} --version'.format(pip_bin), python_shell=False)
try:
return re.match(r'^pip (\S+)', output).group(1)
pip_version = re.match(r'^pip (\S+)', ret['stdout']).group(1)
except AttributeError:
return None
pip_version = None
__context__[contextkey] = pip_version
return pip_version
def list_upgrades(bin_env=None,
@ -1176,15 +1248,15 @@ def list_upgrades(bin_env=None,
salt '*' pip.list_upgrades
'''
pip_bin = _get_pip_bin(bin_env)
cmd = _get_pip_bin(bin_env)
cmd.extend(['list', '--outdated'])
cmd = [pip_bin, 'list', '--outdated']
# If pip >= 9.0 use --format=json
pip_version = version(bin_env)
# Pip started supporting the ability to output json starting with 9.0.0
min_version = '9.0'
cur_version = version(pip_bin)
if salt.utils.versions.compare(ver1=cur_version, oper='>=',
ver2=min_version):
if salt.utils.versions.compare(ver1=pip_version,
oper='>=',
ver2=min_version):
cmd.append('--format=json')
cmd_kwargs = dict(cwd=cwd, runas=user)
@ -1192,54 +1264,78 @@ def list_upgrades(bin_env=None,
cmd_kwargs['env'] = {'VIRTUAL_ENV': bin_env}
result = __salt__['cmd.run_all'](cmd, **cmd_kwargs)
if result['retcode'] > 0:
logger.error(result['stderr'])
raise CommandExecutionError(result['stderr'])
if result['retcode']:
raise CommandExecutionError(result['stderr'], info=result)
packages = {}
try:
json_results = salt.utils.json.loads(result['stdout'])
for json_result in json_results:
packages[json_result['name']] = json_result['latest_version']
except ValueError:
# Pip started supporting the ability to output json starting with 9.0.0
# Older versions will have to parse stdout
if salt.utils.versions.compare(ver1=pip_version, oper='<', ver2='9.0.0'):
# Pip versions < 8.0.0 had a different output format
# Sample data:
# pip (Current: 7.1.2 Latest: 10.0.1 [wheel])
# psutil (Current: 5.2.2 Latest: 5.4.5 [wheel])
# pyasn1 (Current: 0.2.3 Latest: 0.4.2 [wheel])
# pycparser (Current: 2.17 Latest: 2.18 [sdist])
if salt.utils.versions.compare(ver1=pip_version, oper='<', ver2='8.0.0'):
logger.debug('pip module: Old output format')
pat = re.compile(r'(\S*)\s+\(.*Latest:\s+(.*)\)')
# New output format for version 8.0.0+
# Sample data:
# pip (8.0.0) - Latest: 10.0.1 [wheel]
# psutil (5.2.2) - Latest: 5.4.5 [wheel]
# pyasn1 (0.2.3) - Latest: 0.4.2 [wheel]
# pycparser (2.17) - Latest: 2.18 [sdist]
else:
logger.debug('pip module: New output format')
pat = re.compile(r'(\S*)\s+\(.*\)\s+-\s+Latest:\s+(.*)')
for line in result['stdout'].splitlines():
match = re.search(r'(\S*)\s+.*Latest:\s+(.*)', line)
match = pat.search(line)
if match:
name, version_ = match.groups()
else:
logger.error('Can\'t parse line \'%s\'', line)
logger.error('Can\'t parse line \'{0}\''.format(line))
continue
packages[name] = version_
else:
logger.debug('pip module: JSON output format')
try:
pkgs = salt.utils.json.loads(result['stdout'], strict=False)
except ValueError:
raise CommandExecutionError('Invalid JSON', info=result)
for pkg in pkgs:
packages[pkg['name']] = '{0} [{1}]'.format(pkg['latest_version'],
pkg['latest_filetype'])
return packages
def is_installed(pkgname=None,
bin_env=None,
user=None,
cwd=None):
bin_env=None,
user=None,
cwd=None):
'''
.. versionadded:: 2018.3.0
Filter list of installed apps from ``freeze`` and return True or False if
``pkgname`` exists in the list of packages installed.
.. note::
If the version of pip available is older than 8.0.3, the packages
wheel, setuptools, and distribute will not be reported by this function
even if they are installed. Unlike
:py:func:`pip.freeze <salt.modules.pip.freeze>`, this function always
reports the version of pip which is installed.
even if they are installed. Unlike :py:func:`pip.freeze
<salt.modules.pip.freeze>`, this function always reports the version of
pip which is installed.
CLI Example:
.. code-block:: bash
salt '*' pip.is_installed salt
.. versionadded:: 2018.3.0
The packages wheel, setuptools, and distribute are included if the
installed pip is new enough.
'''
for line in freeze(bin_env=bin_env, user=user, cwd=cwd):
if line.startswith('-f') or line.startswith('#'):
@ -1294,7 +1390,11 @@ def upgrade(bin_env=None,
'''
.. versionadded:: 2015.5.0
Upgrades outdated pip packages
Upgrades outdated pip packages.
.. note::
On Windows you can't update salt from pip using salt, so salt will be
skipped
Returns a dict containing the changes.
@ -1312,16 +1412,19 @@ def upgrade(bin_env=None,
'result': True,
'comment': '',
}
pip_bin = _get_pip_bin(bin_env)
cmd = _get_pip_bin(bin_env)
cmd.extend(['install', '-U'])
old = list_(bin_env=bin_env, user=user, cwd=cwd)
cmd = [pip_bin, 'install', '-U']
cmd_kwargs = dict(cwd=cwd, use_vt=use_vt)
if bin_env and os.path.isdir(bin_env):
cmd_kwargs['env'] = {'VIRTUAL_ENV': bin_env}
errors = False
for pkg in list_upgrades(bin_env=bin_env, user=user, cwd=cwd):
if pkg == 'salt':
if salt.utils.platform.is_windows():
continue
result = __salt__['cmd.run_all'](cmd + [pkg], **cmd_kwargs)
if result['retcode'] != 0:
errors = True
@ -1330,6 +1433,7 @@ def upgrade(bin_env=None,
if errors:
ret['result'] = False
_clear_context(bin_env)
new = list_(bin_env=bin_env, user=user, cwd=cwd)
ret['changes'] = salt.utils.data.compare_dicts(old, new)
@ -1383,9 +1487,8 @@ def list_all_versions(pkg,
salt '*' pip.list_all_versions <package name>
'''
pip_bin = _get_pip_bin(bin_env)
cmd = [pip_bin, 'install', '{0}==versions'.format(pkg)]
cmd = _get_pip_bin(bin_env)
cmd.extend(['install', '{0}==versions'.format(pkg)])
if index_url:
if not salt.utils.url.validate(index_url, VALID_PROTOS):

View File

@ -57,7 +57,8 @@ def create(path,
upgrade=None,
user=None,
use_vt=False,
saltenv='base'):
saltenv='base',
**kwargs):
'''
Create a virtualenv
@ -103,6 +104,11 @@ def create(path,
user : None
Set ownership for the virtualenv
.. note::
On Windows you must also pass a ``password`` parameter. Additionally,
the user must have permissions to the location where the virtual
environment is being created
runas : None
Set ownership for the virtualenv
@ -162,7 +168,7 @@ def create(path,
# Unable to import?? Let's parse the version from the console
version_cmd = [venv_bin, '--version']
ret = __salt__['cmd.run_all'](
version_cmd, runas=user, python_shell=False
version_cmd, runas=user, python_shell=False, **kwargs
)
if ret['retcode'] > 0 or not ret['stdout'].strip():
raise CommandExecutionError(
@ -252,7 +258,7 @@ def create(path,
cmd.append(path)
# Let's create the virtualenv
ret = __salt__['cmd.run_all'](cmd, runas=user, python_shell=False)
ret = __salt__['cmd.run_all'](cmd, runas=user, python_shell=False, **kwargs)
if ret['retcode'] != 0:
# Something went wrong. Let's bail out now!
return ret

View File

@ -719,23 +719,24 @@ def set_lcm_config(config_mode=None,
'ApplyAndAutoCorrect'):
error = 'config_mode must be one of ApplyOnly, ApplyAndMonitor, ' \
'or ApplyAndAutoCorrect. Passed {0}'.format(config_mode)
SaltInvocationError(error)
return error
raise SaltInvocationError(error)
cmd += ' ConfigurationMode = "{0}";'.format(config_mode)
if config_mode_freq:
if not isinstance(config_mode_freq, int):
SaltInvocationError('config_mode_freq must be an integer')
return 'config_mode_freq must be an integer. Passed {0}'.\
format(config_mode_freq)
error = 'config_mode_freq must be an integer. Passed {0}'.format(
config_mode_freq
)
raise SaltInvocationError(error)
cmd += ' ConfigurationModeFrequencyMins = {0};'.format(config_mode_freq)
if refresh_mode:
if refresh_mode not in ('Disabled', 'Push', 'Pull'):
SaltInvocationError('refresh_mode must be one of Disabled, Push, '
'or Pull')
raise SaltInvocationError(
'refresh_mode must be one of Disabled, Push, or Pull'
)
cmd += ' RefreshMode = "{0}";'.format(refresh_mode)
if refresh_freq:
if not isinstance(refresh_freq, int):
SaltInvocationError('refresh_freq must be an integer')
raise SaltInvocationError('refresh_freq must be an integer')
cmd += ' RefreshFrequencyMins = {0};'.format(refresh_freq)
if reboot_if_needed is not None:
if not isinstance(reboot_if_needed, bool):
@ -748,8 +749,10 @@ def set_lcm_config(config_mode=None,
if action_after_reboot:
if action_after_reboot not in ('ContinueConfiguration',
'StopConfiguration'):
SaltInvocationError('action_after_reboot must be one of '
'ContinueConfiguration or StopConfiguration')
raise SaltInvocationError(
'action_after_reboot must be one of '
'ContinueConfiguration or StopConfiguration'
)
cmd += ' ActionAfterReboot = "{0}"'.format(action_after_reboot)
if certificate_id is not None:
if certificate_id == '':
@ -761,7 +764,7 @@ def set_lcm_config(config_mode=None,
cmd += ' ConfigurationID = "{0}";'.format(configuration_id)
if allow_module_overwrite is not None:
if not isinstance(allow_module_overwrite, bool):
SaltInvocationError('allow_module_overwrite must be a boolean value')
raise SaltInvocationError('allow_module_overwrite must be a boolean value')
if allow_module_overwrite:
allow_module_overwrite = '$true'
else:
@ -771,13 +774,14 @@ def set_lcm_config(config_mode=None,
if debug_mode is None:
debug_mode = 'None'
if debug_mode not in ('None', 'ForceModuleImport', 'All'):
SaltInvocationError('debug_mode must be one of None, '
'ForceModuleImport, ResourceScriptBreakAll, or '
'All')
raise SaltInvocationError(
'debug_mode must be one of None, ForceModuleImport, '
'ResourceScriptBreakAll, or All'
)
cmd += ' DebugMode = "{0}";'.format(debug_mode)
if status_retention_days:
if not isinstance(status_retention_days, int):
SaltInvocationError('status_retention_days must be an integer')
raise SaltInvocationError('status_retention_days must be an integer')
cmd += ' StatusRetentionTimeInDays = {0};'.format(status_retention_days)
cmd += ' }}};'
cmd += r'SaltConfig -OutputPath "{0}\SaltConfig"'.format(temp_dir)

View File

@ -4364,7 +4364,7 @@ def _checkAllAdmxPolicies(policy_class,
if ENABLED_VALUE_XPATH(admx_policy) and this_policy_setting == 'Not Configured':
# some policies have a disabled list but not an enabled list
# added this to address those issues
if DISABLED_LIST_XPATH(admx_policy):
if DISABLED_LIST_XPATH(admx_policy) or DISABLED_VALUE_XPATH(admx_policy):
element_only_enabled_disabled = False
explicit_enable_disable_value_setting = True
if _checkValueItemParent(admx_policy,
@ -4374,14 +4374,14 @@ def _checkAllAdmxPolicies(policy_class,
ENABLED_VALUE_XPATH,
policy_filedata):
this_policy_setting = 'Enabled'
log.debug('%s is enabled', this_policyname)
log.debug('%s is enabled by detected ENABLED_VALUE_XPATH', this_policyname)
if this_policynamespace not in policy_vals:
policy_vals[this_policynamespace] = {}
policy_vals[this_policynamespace][this_policyname] = this_policy_setting
if DISABLED_VALUE_XPATH(admx_policy) and this_policy_setting == 'Not Configured':
# some policies have a disabled list but not an enabled list
# added this to address those issues
if ENABLED_LIST_XPATH(admx_policy):
if ENABLED_LIST_XPATH(admx_policy) or ENABLED_VALUE_XPATH(admx_policy):
element_only_enabled_disabled = False
explicit_enable_disable_value_setting = True
if _checkValueItemParent(admx_policy,
@ -4391,25 +4391,27 @@ def _checkAllAdmxPolicies(policy_class,
DISABLED_VALUE_XPATH,
policy_filedata):
this_policy_setting = 'Disabled'
log.debug('%s is disabled', this_policyname)
log.debug('%s is disabled by detected DISABLED_VALUE_XPATH', this_policyname)
if this_policynamespace not in policy_vals:
policy_vals[this_policynamespace] = {}
policy_vals[this_policynamespace][this_policyname] = this_policy_setting
if ENABLED_LIST_XPATH(admx_policy) and this_policy_setting == 'Not Configured':
element_only_enabled_disabled = False
explicit_enable_disable_value_setting = True
if DISABLED_LIST_XPATH(admx_policy) or DISABLED_VALUE_XPATH(admx_policy):
element_only_enabled_disabled = False
explicit_enable_disable_value_setting = True
if _checkListItem(admx_policy, this_policyname, this_key, ENABLED_LIST_XPATH, policy_filedata):
this_policy_setting = 'Enabled'
log.debug('%s is enabled', this_policyname)
log.debug('%s is enabled by detected ENABLED_LIST_XPATH', this_policyname)
if this_policynamespace not in policy_vals:
policy_vals[this_policynamespace] = {}
policy_vals[this_policynamespace][this_policyname] = this_policy_setting
if DISABLED_LIST_XPATH(admx_policy) and this_policy_setting == 'Not Configured':
element_only_enabled_disabled = False
explicit_enable_disable_value_setting = True
if ENABLED_LIST_XPATH(admx_policy) or ENABLED_VALUE_XPATH(admx_policy):
element_only_enabled_disabled = False
explicit_enable_disable_value_setting = True
if _checkListItem(admx_policy, this_policyname, this_key, DISABLED_LIST_XPATH, policy_filedata):
this_policy_setting = 'Disabled'
log.debug('%s is disabled', this_policyname)
log.debug('%s is disabled by detected DISABLED_LIST_XPATH', this_policyname)
if this_policynamespace not in policy_vals:
policy_vals[this_policynamespace] = {}
policy_vals[this_policynamespace][this_policyname] = this_policy_setting
@ -4424,7 +4426,7 @@ def _checkAllAdmxPolicies(policy_class,
'1')),
policy_filedata):
this_policy_setting = 'Enabled'
log.debug('%s is enabled', this_policyname)
log.debug('%s is enabled by no explicit enable/disable list or value', this_policyname)
if this_policynamespace not in policy_vals:
policy_vals[this_policynamespace] = {}
policy_vals[this_policynamespace][this_policyname] = this_policy_setting
@ -4435,7 +4437,7 @@ def _checkAllAdmxPolicies(policy_class,
check_deleted=True)),
policy_filedata):
this_policy_setting = 'Disabled'
log.debug('%s is disabled', this_policyname)
log.debug('%s is disabled by no explicit enable/disable list or value', this_policyname)
if this_policynamespace not in policy_vals:
policy_vals[this_policynamespace] = {}
policy_vals[this_policynamespace][this_policyname] = this_policy_setting

View File

@ -15,7 +15,7 @@ Support for Zabbix
Connection arguments from the minion config file can be overridden on the CLI by using arguments with
_connection_ prefix.
``_connection_`` prefix.
.. code-block:: bash
@ -23,26 +23,24 @@ Support for Zabbix
:codeauthor: Jiri Kotlin <jiri.kotlin@ultimum.io>
'''
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import, print_function, unicode_literals
# Import python libs
# Import Python libs
import logging
import socket
import os
# Import salt libs
try:
import salt.utils
from salt.ext import six
from salt.utils.versions import LooseVersion as _LooseVersion
# pylint: disable=import-error,no-name-in-module,unused-import
from salt.ext.six.moves.urllib.error import HTTPError, URLError
from salt.exceptions import SaltException
IMPORTS_OK = True
except ImportError:
IMPORTS_OK = False
# Import Salt libs
from salt.ext import six
from salt.exceptions import SaltException
import salt.utils.data
import salt.utils.files
import salt.utils.http
import salt.utils.json
from salt.utils.versions import LooseVersion as _LooseVersion
# pylint: disable=import-error,no-name-in-module,unused-import
from salt.ext.six.moves.urllib.error import HTTPError, URLError
# pylint: enable=import-error,no-name-in-module,unused-import
log = logging.getLogger(__name__)
@ -104,9 +102,7 @@ def __virtual__():
'''
Only load the module if all modules are imported correctly.
'''
if IMPORTS_OK:
return __virtualname__
return False, 'Importing modules failed.'
return __virtualname__
def _frontend_url():
@ -349,7 +345,7 @@ def compare_params(defined, existing, return_old_value=False):
defined))
# Comparison of values
if not salt.utils.is_iter(defined):
if not salt.utils.data.is_iter(defined):
if six.text_type(defined) != six.text_type(existing) and return_old_value:
return {'new': six.text_type(defined), 'old': six.text_type(existing)}
elif six.text_type(defined) != six.text_type(existing) and not return_old_value:
@ -2390,7 +2386,7 @@ def configuration_import(config_file, rules=None, file_format='xml', **connectio
else:
new_rules[rule] = rules[rule]
if 'salt://' in config_file:
tmpfile = salt.utils.mkstemp()
tmpfile = salt.utils.files.mkstemp()
cfile = __salt__['cp.get_file'](config_file, tmpfile)
if not cfile or os.path.getsize(cfile) == 0:
return {'name': config_file, 'result': False, 'message': 'Failed to fetch config file.'}
@ -2399,11 +2395,11 @@ def configuration_import(config_file, rules=None, file_format='xml', **connectio
if not os.path.isfile(cfile):
return {'name': config_file, 'result': False, 'message': 'Invalid file path.'}
with salt.utils.fopen(cfile, mode='r') as fp_:
with salt.utils.files.fopen(cfile, mode='r') as fp_:
xml = fp_.read()
if 'salt://' in config_file:
salt.utils.safe_rm(cfile)
salt.utils.files.safe_rm(cfile)
params = {'format': file_format,
'rules': new_rules,

View File

@ -261,7 +261,7 @@ different grain matches.
That said, sometimes a minion may match more than one class. For instance,
in the above example, Ubuntu minions will match both the **Debian** and
**Ubuntu** classes, since Ubuntu has an ``os_family`` grain of **Debian**
an an ``os`` grain of **Ubuntu**. As of the 2017.7.0 release, the order is
and an ``os`` grain of **Ubuntu**. As of the 2017.7.0 release, the order is
dictated by the order of declaration, with classes defined later overriding
earlier ones. Additionally, 2017.7.0 adds support for explicitly defining
the ordering using an optional attribute called ``priority``.

View File

@ -182,25 +182,28 @@ def _check_pkg_version_format(pkg):
return ret
def _check_if_installed(prefix, state_pkg_name, version_spec,
ignore_installed, force_reinstall,
upgrade, user, cwd, bin_env, env_vars,
index_url):
def _check_if_installed(prefix,
state_pkg_name,
version_spec,
ignore_installed,
force_reinstall,
upgrade,
user,
cwd,
bin_env,
env_vars,
index_url,
**kwargs):
# result: None means the command failed to run
# result: True means the package is installed
# result: False means the package is not installed
ret = {'result': False, 'comment': None}
# Check if the requested package is already installed.
try:
pip_list = __salt__['pip.list'](prefix, bin_env=bin_env,
user=user, cwd=cwd,
env_vars=env_vars)
prefix_realname = _find_key(prefix, pip_list)
except (CommandNotFoundError, CommandExecutionError) as err:
ret['result'] = None
ret['comment'] = 'Error installing \'{0}\': {1}'.format(state_pkg_name, err)
return ret
pip_list = __salt__['pip.list'](prefix, bin_env=bin_env,
user=user, cwd=cwd,
env_vars=env_vars, **kwargs)
prefix_realname = _find_key(prefix, pip_list)
# If the package was already installed, check
# the ignore_installed and force_reinstall flags
@ -313,7 +316,6 @@ def installed(name,
install_options=None,
global_options=None,
user=None,
no_chown=False,
cwd=None,
pre_releases=False,
cert=None,
@ -326,7 +328,8 @@ def installed(name,
trusted_host=None,
no_cache_dir=False,
cache_dir=None,
no_binary=None):
no_binary=None,
**kwargs):
'''
Make sure the package is installed
@ -448,10 +451,6 @@ def installed(name,
no_install
Download and unpack all packages, but don't actually install them
no_chown
When user is given, do not attempt to copy and chown
a requirements file
no_cache_dir:
Disable the cache.
@ -594,6 +593,12 @@ def installed(name,
.. _`virtualenv`: http://www.virtualenv.org/en/latest/
'''
if 'no_chown' in kwargs:
salt.utils.versions.warn_until(
'Flourine',
'The no_chown argument has been deprecated and is no longer used. '
'Its functionality was removed in Boron.')
kwargs.pop('no_chown')
if pip_bin and not bin_env:
bin_env = pip_bin
@ -619,11 +624,16 @@ def installed(name,
ret = {'name': ';'.join(pkgs), 'result': None,
'comment': '', 'changes': {}}
try:
cur_version = __salt__['pip.version'](bin_env)
except (CommandNotFoundError, CommandExecutionError) as err:
ret['result'] = None
ret['comment'] = 'Error installing \'{0}\': {1}'.format(name, err)
return ret
# Check that the pip binary supports the 'use_wheel' option
if use_wheel:
min_version = '1.4'
max_version = '9.0.3'
cur_version = __salt__['pip.version'](bin_env)
too_low = salt.utils.versions.compare(ver1=cur_version, oper='<', ver2=min_version)
too_high = salt.utils.versions.compare(ver1=cur_version, oper='>', ver2=max_version)
if too_low or too_high:
@ -637,7 +647,6 @@ def installed(name,
if no_use_wheel:
min_version = '1.4'
max_version = '9.0.3'
cur_version = __salt__['pip.version'](bin_env)
too_low = salt.utils.versions.compare(ver1=cur_version, oper='<', ver2=min_version)
too_high = salt.utils.versions.compare(ver1=cur_version, oper='>', ver2=max_version)
if too_low or too_high:
@ -650,7 +659,6 @@ def installed(name,
# Check that the pip binary supports the 'no_binary' option
if no_binary:
min_version = '7.0.0'
cur_version = __salt__['pip.version'](bin_env)
too_low = salt.utils.versions.compare(ver1=cur_version, oper='<', ver2=min_version)
if too_low:
ret['result'] = False
@ -724,7 +732,7 @@ def installed(name,
out = _check_if_installed(prefix, state_pkg_name, version_spec,
ignore_installed, force_reinstall,
upgrade, user, cwd, bin_env, env_vars,
index_url)
index_url, **kwargs)
# If _check_if_installed result is None, something went wrong with
# the command running. This way we keep stateful output.
if out['result'] is None:
@ -804,7 +812,6 @@ def installed(name,
install_options=install_options,
global_options=global_options,
user=user,
no_chown=no_chown,
cwd=cwd,
pre_releases=pre_releases,
cert=cert,
@ -816,7 +823,8 @@ def installed(name,
env_vars=env_vars,
use_vt=use_vt,
trusted_host=trusted_host,
no_cache_dir=no_cache_dir
no_cache_dir=no_cache_dir,
**kwargs
)
if pip_install_call and pip_install_call.get('retcode', 1) == 0:
@ -872,7 +880,8 @@ def installed(name,
if prefix:
pipsearch = __salt__['pip.list'](prefix, bin_env,
user=user, cwd=cwd,
env_vars=env_vars)
env_vars=env_vars,
**kwargs)
# If we didn't find the package in the system after
# installing it report it

View File

@ -42,7 +42,6 @@ def managed(name,
never_download=None,
prompt=None,
user=None,
no_chown=False,
cwd=None,
index_url=None,
extra_index_url=None,
@ -61,7 +60,8 @@ def managed(name,
pip_no_cache_dir=False,
pip_cache_dir=None,
process_dependency_links=False,
no_binary=None):
no_binary=None,
**kwargs):
'''
Create a virtualenv and optionally manage it with pip
@ -85,11 +85,6 @@ def managed(name,
user: None
The user under which to run virtualenv and pip.
no_chown: False
When user is given, do not attempt to copy and chown a requirements file
(needed if the requirements file refers to other files via relative
paths, as the copy-and-chown procedure does not account for such files)
cwd: None
Path to the working directory where `pip install` is executed.
@ -140,6 +135,13 @@ def managed(name,
- env_vars:
PATH_VAR: '/usr/local/bin/'
'''
if 'no_chown' in kwargs:
salt.utils.versions.warn_until(
'Flourine',
'The no_chown argument has been deprecated and is no longer used. '
'Its functionality was removed in Boron.')
kwargs.pop('no_chown')
ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
if 'virtualenv.create' not in __salt__:
@ -211,6 +213,7 @@ def managed(name,
prompt=prompt,
user=user,
use_vt=use_vt,
**kwargs
)
except CommandNotFoundError as err:
ret['result'] = False
@ -311,7 +314,6 @@ def managed(name,
extra_index_url=extra_index_url,
download=pip_download,
download_cache=pip_download_cache,
no_chown=no_chown,
pre_releases=pre_releases,
exists_action=pip_exists_action,
ignore_installed=pip_ignore_installed,
@ -321,7 +323,8 @@ def managed(name,
use_vt=use_vt,
env_vars=env_vars,
no_cache_dir=pip_no_cache_dir,
cache_dir=pip_cache_dir
cache_dir=pip_cache_dir,
**kwargs
)
ret['result'] &= pip_ret['retcode'] == 0
if pip_ret['retcode'] > 0:

View File

@ -475,6 +475,8 @@ class CkMinions(object):
minions = set(self._pki_minions())
log.debug('minions: %s', minions)
nodegroups = self.opts.get('nodegroups', {})
if self.opts.get('minion_data_cache', False):
ref = {'G': self._check_grain_minions,
'P': self._check_grain_pcre_minions,
@ -497,9 +499,11 @@ class CkMinions(object):
if isinstance(expr, six.string_types):
words = expr.split()
else:
words = expr
# we make a shallow copy in order to not affect the passed in arg
words = expr[:]
for word in words:
while words:
word = words.pop(0)
target_info = parse_target(word)
# Easy check first
@ -556,9 +560,12 @@ class CkMinions(object):
elif target_info and target_info['engine']:
if 'N' == target_info['engine']:
# Nodegroups should already be expanded/resolved to other engines
log.error('Detected nodegroup expansion failure of "%s"', word)
return {'minions': [], 'missing': []}
# if we encounter a node group, just evaluate it in-place
decomposed = nodegroup_comp(target_info['pattern'], nodegroups)
if decomposed:
words = decomposed + words
continue
engine = ref.get(target_info['engine'])
if not engine:
# If an unknown engine is called at any time, fail out

View File

@ -361,23 +361,46 @@ def check_whitelist_blacklist(value, whitelist=None, blacklist=None):
in the blacklist, then the whitelist is checked. If the value isn't
found in the whitelist, the function returns ``False``.
'''
if blacklist is not None:
if not isinstance(blacklist, list):
# Normalize the input so that we have a list
if blacklist:
if isinstance(blacklist, six.string_types):
blacklist = [blacklist]
for expr in blacklist:
if expr_match(value, expr):
return False
if not hasattr(blacklist, '__iter__'):
raise TypeError(
'Expecting iterable blacklist, but got {0} ({1})'.format(
type(blacklist).__name__, blacklist
)
)
else:
blacklist = []
if whitelist:
if not isinstance(whitelist, list):
if isinstance(whitelist, six.string_types):
whitelist = [whitelist]
for expr in whitelist:
if expr_match(value, expr):
return True
if not hasattr(whitelist, '__iter__'):
raise TypeError(
'Expecting iterable whitelist, but got {0} ({1})'.format(
type(whitelist).__name__, whitelist
)
)
else:
return True
whitelist = []
return False
_blacklist_match = any(expr_match(value, expr) for expr in blacklist)
_whitelist_match = any(expr_match(value, expr) for expr in whitelist)
if blacklist and not whitelist:
# Blacklist but no whitelist
return not _blacklist_match
elif whitelist and not blacklist:
# Whitelist but no blacklist
return _whitelist_match
elif blacklist and whitelist:
# Both whitelist and blacklist
return not _blacklist_match and _whitelist_match
else:
# No blacklist or whitelist passed
return True
def check_include_exclude(path_str, include_pat=None, exclude_pat=None):

View File

@ -279,7 +279,6 @@ def _command(source, command, flags=None, opts=None,
return ' '.join(cmd)
@real_memoize
def is_supported():
'''
Check the system for ZFS support
@ -302,7 +301,7 @@ def is_supported():
on_supported_platform = True
# Additional check for the zpool command
return (_zpool_cmd() and on_supported_platform) is True
return (salt.utils.path.which('zpool') and on_supported_platform) is True
@real_memoize

View File

@ -6,3 +6,5 @@
{#- wheels are disabled because the pip cache dir will not be owned by the above issue-1959 user. Need to check this ASAP #}
- no_binary: ':all:'
{%- endif %}
- env:
XDG_CACHE_HOME: /tmp

View File

@ -0,0 +1 @@
pillar_from_nodegroup: True

View File

@ -0,0 +1 @@
pillar_from_nodegroup_with_ghost: True

View File

@ -9,3 +9,7 @@ base:
'localhost':
- generic
- blackout
'N@mins not L@minion':
- ng1
'N@missing_minion':
- ng2

View File

@ -189,6 +189,29 @@ GPG_PILLAR_DECRYPTED = {
}
class BasePillarTest(ModuleCase):
'''
Tests for pillar decryption
'''
def test_pillar_top_compound_match(self, grains=None):
'''
Test that a compound match topfile that refers to a nodegroup via N@ works
as expected.
'''
if not grains:
grains = {}
grains['os'] = 'Fedora'
pillar_obj = pillar.Pillar(self.get_config('master', from_scratch=True), grains, 'minion', 'base')
ret = pillar_obj.compile_pillar()
self.assertEqual(ret.get('pillar_from_nodegroup_with_ghost'), True)
self.assertEqual(ret.get('pillar_from_nodegroup'), None)
sub_pillar_obj = pillar.Pillar(self.get_config('master', from_scratch=True), grains, 'sub_minion', 'base')
sub_ret = sub_pillar_obj.compile_pillar()
self.assertEqual(sub_ret.get('pillar_from_nodegroup_with_ghost'), None)
self.assertEqual(sub_ret.get('pillar_from_nodegroup'), True)
@skipIf(not salt.utils.path.which('gpg'), 'GPG is not installed')
class DecryptGPGPillarTest(ModuleCase):
'''

View File

@ -9,9 +9,9 @@
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import os
import pwd
import shutil
import re
import shutil
import sys
import tempfile
# Import Salt Testing libs
@ -23,6 +23,7 @@ from tests.support.helpers import skip_if_not_root
# Import salt libs
import salt.utils.files
import salt.utils.path
import salt.utils.platform
from salt.modules.virtualenv_mod import KNOWN_BINARY_NAMES
@ -74,23 +75,34 @@ class PipModuleTest(ModuleCase):
# Let's remove the pip binary
pip_bin = os.path.join(self.venv_dir, 'bin', 'pip')
py_dir = 'python{0}.{1}'.format(*sys.version_info[:2])
site_dir = os.path.join(self.venv_dir, 'lib', py_dir, 'site-packages')
if salt.utils.platform.is_windows():
pip_bin = os.path.join(self.venv_dir, 'Scripts', 'pip.exe')
site_dir = os.path.join(self.venv_dir, 'lib', 'site-packages')
if not os.path.isfile(pip_bin):
self.skipTest(
'Failed to find the pip binary to the test virtualenv'
)
os.remove(pip_bin)
# Also remove the pip dir from site-packages
# This is needed now that we're using python -m pip instead of the
# pip binary directly. python -m pip will still work even if the
# pip binary is missing
shutil.rmtree(os.path.join(site_dir, 'pip'))
# Let's run a pip depending functions
for func in ('pip.freeze', 'pip.list'):
ret = self.run_function(func, bin_env=self.venv_dir)
self.assertIn(
'Command required for \'{0}\' not found: '
'Could not find a `pip` binary in virtualenv'.format(func),
'Could not find a `pip` binary'.format(func),
ret
)
@skip_if_not_root
def test_requirements_as_list_of_chains__sans_no_chown__cwd_set__absolute_file_path(self):
def test_requirements_as_list_of_chains__cwd_set__absolute_file_path(self):
self.run_function('virtualenv.create', [self.venv_dir])
# Create a requirements file that depends on another one.
@ -109,11 +121,10 @@ class PipModuleTest(ModuleCase):
with salt.utils.files.fopen(req2b_filename, 'w') as f:
f.write('pep8\n')
this_user = pwd.getpwuid(os.getuid())[0]
requirements_list = [req1_filename, req2_filename]
ret = self.run_function(
'pip.install', requirements=requirements_list, user=this_user,
'pip.install', requirements=requirements_list,
bin_env=self.venv_dir, cwd=self.venv_dir
)
try:
@ -128,7 +139,7 @@ class PipModuleTest(ModuleCase):
raise
@skip_if_not_root
def test_requirements_as_list_of_chains__sans_no_chown__cwd_not_set__absolute_file_path(self):
def test_requirements_as_list_of_chains__cwd_not_set__absolute_file_path(self):
self.run_function('virtualenv.create', [self.venv_dir])
# Create a requirements file that depends on another one.
@ -147,12 +158,10 @@ class PipModuleTest(ModuleCase):
with salt.utils.files.fopen(req2b_filename, 'w') as f:
f.write('pep8\n')
this_user = pwd.getpwuid(os.getuid())[0]
requirements_list = [req1_filename, req2_filename]
ret = self.run_function(
'pip.install', requirements=requirements_list, user=this_user,
bin_env=self.venv_dir
'pip.install', requirements=requirements_list, bin_env=self.venv_dir
)
try:
self.assertEqual(ret['retcode'], 0)
@ -167,7 +176,7 @@ class PipModuleTest(ModuleCase):
raise
@skip_if_not_root
def test_requirements_as_list__sans_no_chown__absolute_file_path(self):
def test_requirements_as_list__absolute_file_path(self):
self.run_function('virtualenv.create', [self.venv_dir])
req1_filename = os.path.join(self.venv_dir, 'requirements.txt')
@ -178,12 +187,10 @@ class PipModuleTest(ModuleCase):
with salt.utils.files.fopen(req2_filename, 'w') as f:
f.write('pep8\n')
this_user = pwd.getpwuid(os.getuid())[0]
requirements_list = [req1_filename, req2_filename]
ret = self.run_function(
'pip.install', requirements=requirements_list, user=this_user,
bin_env=self.venv_dir
'pip.install', requirements=requirements_list, bin_env=self.venv_dir
)
found = self.pip_successful_install(ret['stdout'])
@ -198,7 +205,7 @@ class PipModuleTest(ModuleCase):
raise
@skip_if_not_root
def test_requirements_as_list__sans_no_chown__non_absolute_file_path(self):
def test_requirements_as_list__non_absolute_file_path(self):
self.run_function('virtualenv.create', [self.venv_dir])
# Create a requirements file that depends on another one.
@ -215,11 +222,10 @@ class PipModuleTest(ModuleCase):
with salt.utils.files.fopen(req2_filepath, 'w') as f:
f.write('pep8\n')
this_user = pwd.getpwuid(os.getuid())[0]
requirements_list = [req1_filename, req2_filename]
ret = self.run_function(
'pip.install', requirements=requirements_list, user=this_user,
'pip.install', requirements=requirements_list,
bin_env=self.venv_dir, cwd=req_cwd
)
try:
@ -234,7 +240,7 @@ class PipModuleTest(ModuleCase):
raise
@skip_if_not_root
def test_chained_requirements__sans_no_chown__absolute_file_path(self):
def test_chained_requirements__absolute_file_path(self):
self.run_function('virtualenv.create', [self.venv_dir])
# Create a requirements file that depends on another one.
@ -247,10 +253,8 @@ class PipModuleTest(ModuleCase):
with salt.utils.files.fopen(req2_filename, 'w') as f:
f.write('pep8')
this_user = pwd.getpwuid(os.getuid())[0]
ret = self.run_function(
'pip.install', requirements=req1_filename, user=this_user,
bin_env=self.venv_dir
'pip.install', requirements=req1_filename, bin_env=self.venv_dir
)
try:
self.assertEqual(ret['retcode'], 0)
@ -261,7 +265,7 @@ class PipModuleTest(ModuleCase):
raise
@skip_if_not_root
def test_chained_requirements__sans_no_chown__non_absolute_file_path(self):
def test_chained_requirements__non_absolute_file_path(self):
self.run_function('virtualenv.create', [self.venv_dir])
# Create a requirements file that depends on another one.
@ -278,10 +282,9 @@ class PipModuleTest(ModuleCase):
with salt.utils.files.fopen(req2_file, 'w') as f:
f.write('pep8')
this_user = pwd.getpwuid(os.getuid())[0]
ret = self.run_function(
'pip.install', requirements=req1_filename, user=this_user,
no_chown=False, cwd=req_basepath, bin_env=self.venv_dir
'pip.install', requirements=req1_filename, cwd=req_basepath,
bin_env=self.venv_dir
)
try:
self.assertEqual(ret['retcode'], 0)
@ -292,7 +295,7 @@ class PipModuleTest(ModuleCase):
raise
@skip_if_not_root
def test_issue_4805_nested_requirements_user_no_chown(self):
def test_issue_4805_nested_requirements(self):
self.run_function('virtualenv.create', [self.venv_dir])
# Create a requirements file that depends on another one.
@ -303,11 +306,8 @@ class PipModuleTest(ModuleCase):
with salt.utils.files.fopen(req2_filename, 'w') as f:
f.write('pep8')
this_user = pwd.getpwuid(os.getuid())[0]
ret = self.run_function(
'pip.install', requirements=req1_filename, user=this_user,
no_chown=True, bin_env=self.venv_dir
)
'pip.install', requirements=req1_filename, bin_env=self.venv_dir)
if self._check_download_error(ret['stdout']):
self.skipTest('Test skipped due to pip download error')
try:
@ -436,9 +436,9 @@ class PipModuleTest(ModuleCase):
def tearDown(self):
super(PipModuleTest, self).tearDown()
if os.path.isdir(self.venv_test_dir):
shutil.rmtree(self.venv_test_dir)
shutil.rmtree(self.venv_test_dir, ignore_errors=True)
if os.path.isdir(self.pip_temp):
shutil.rmtree(self.pip_temp)
shutil.rmtree(self.pip_temp, ignore_errors=True)
del self.venv_dir
del self.venv_test_dir
del self.pip_temp

View File

@ -88,6 +88,17 @@ class MatchTest(ShellCase, ShellCaseCommonTestsMixin):
data = self.run_salt("-C 'J%@knights%^(Lancelot|Galahad)$' test.ping")
self.assertTrue(minion_in_returns('minion', data))
self.assertTrue(minion_in_returns('sub_minion', data))
time.sleep(2)
data = self.run_salt("-C 'N@multiline_nodegroup' test.ping")
self.assertTrue(minion_in_returns('minion', data))
self.assertTrue(minion_in_returns('sub_minion', data))
time.sleep(2)
data = self.run_salt("-C 'N@multiline_nodegroup not sub_minion' test.ping")
self.assertTrue(minion_in_returns('minion', data))
self.assertFalse(minion_in_returns('sub_minion', data))
data = self.run_salt("-C 'N@multiline_nodegroup not @fakenodegroup not sub_minion' test.ping")
self.assertTrue(minion_in_returns('minion', data))
self.assertFalse(minion_in_returns('sub_minion', data))
def test_nodegroup(self):
'''

View File

@ -11,28 +11,38 @@
from __future__ import absolute_import, print_function, unicode_literals
import errno
import os
import pwd
import glob
import shutil
import sys
try:
import pwd
HAS_PWD = True
except ImportError:
HAS_PWD = False
# Import Salt Testing libs
from tests.support.mixins import SaltReturnAssertsMixin
from tests.support.unit import skipIf
from tests.support.runtests import RUNTIME_VARS
from tests.support.case import ModuleCase
from tests.support.helpers import (
destructiveTest,
requires_system_grains,
with_system_user,
skip_if_not_root
skip_if_not_root,
with_tempdir
)
from tests.support.mixins import SaltReturnAssertsMixin
from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import skipIf
# Import salt libs
import salt.utils.files
import salt.utils.path
import salt.utils.platform
import salt.utils.versions
import salt.utils.win_dacl
import salt.utils.win_functions
from salt.modules.virtualenv_mod import KNOWN_BINARY_NAMES
from salt.exceptions import CommandExecutionError
from tests.support.case import ModuleCase
# Import 3rd-party libs
from salt.ext import six
@ -49,7 +59,7 @@ class VirtualEnv(object):
def __exit__(self, exc_type, exc_value, traceback):
if os.path.isdir(self.venv_dir):
shutil.rmtree(self.venv_dir)
shutil.rmtree(self.venv_dir, ignore_errors=True)
@skipIf(salt.utils.path.which_bin(KNOWN_BINARY_NAMES) is None, 'virtualenv not installed')
@ -115,9 +125,10 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
else:
os.environ['SHELL'] = orig_shell
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
shutil.rmtree(venv_dir, ignore_errors=True)
@skipIf(six.PY3, 'Issue is specific to carbon module, which is PY2-only')
@skipIf(salt.utils.platform.is_windows(), "Carbon does not install in Windows")
@requires_system_grains
def test_pip_installed_weird_install(self, grains=None):
# First, check to see if this is running on CentOS 5 or MacOS.
@ -143,7 +154,7 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
)
finally:
if os.path.isdir(ographite):
shutil.rmtree(ographite)
shutil.rmtree(ographite, ignore_errors=True)
venv_dir = os.path.join(RUNTIME_VARS.TMP, 'pip-installed-weird-install')
try:
@ -152,7 +163,7 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
# context when running the call to state.sls that comes after.
self.run_function('saltutil.sync_modules')
# Since we don't have the virtualenv created, pip.installed will
# thrown and error.
# throw an error.
ret = self.run_function(
'state.sls', mods='pip-installed-weird-install'
)
@ -174,7 +185,7 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
raise Exception('Expected state did not run')
finally:
if os.path.isdir(ographite):
shutil.rmtree(ographite)
shutil.rmtree(ographite, ignore_errors=True)
def test_issue_2028_pip_installed_state(self):
ret = self.run_function('state.sls', mods='issue-2028-pip-installed')
@ -183,14 +194,18 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
RUNTIME_VARS.TMP, 'issue-2028-pip-installed'
)
pep8_bin = os.path.join(venv_dir, 'bin', 'pep8')
if salt.utils.platform.is_windows():
pep8_bin = os.path.join(venv_dir, 'Scripts', 'pep8.exe')
try:
self.assertSaltTrueReturn(ret)
self.assertTrue(
os.path.isfile(os.path.join(venv_dir, 'bin', 'pep8'))
os.path.isfile(pep8_bin)
)
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
shutil.rmtree(venv_dir, ignore_errors=True)
def test_issue_2087_missing_pip(self):
venv_dir = os.path.join(
@ -204,12 +219,23 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
# Let's remove the pip binary
pip_bin = os.path.join(venv_dir, 'bin', 'pip')
py_dir = 'python{0}.{1}'.format(*sys.version_info[:2])
site_dir = os.path.join(venv_dir, 'lib', py_dir, 'site-packages')
if salt.utils.platform.is_windows():
pip_bin = os.path.join(venv_dir, 'Scripts', 'pip.exe')
site_dir = os.path.join(venv_dir, 'lib', 'site-packages')
if not os.path.isfile(pip_bin):
self.skipTest(
'Failed to find the pip binary to the test virtualenv'
)
os.remove(pip_bin)
# Also remove the pip dir from site-packages
# This is needed now that we're using python -m pip instead of the
# pip binary directly. python -m pip will still work even if the
# pip binary is missing
shutil.rmtree(os.path.join(site_dir, 'pip'))
# Let's run the state which should fail because pip is missing
ret = self.run_function('state.sls', mods='issue-2087-missing-pip')
self.assertSaltFalseReturn(ret)
@ -219,7 +245,7 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
)
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
shutil.rmtree(venv_dir, ignore_errors=True)
def test_issue_5940_multiple_pip_mirrors(self):
'''
@ -244,148 +270,100 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
self.skipTest('the --mirrors arg has been deprecated and removed in pip==7.0.0')
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
shutil.rmtree(venv_dir, ignore_errors=True)
@destructiveTest
@skip_if_not_root
@with_system_user('issue-6912', on_existing='delete', delete=True)
def test_issue_6912_wrong_owner(self, username):
venv_dir = os.path.join(
RUNTIME_VARS.TMP, '6912-wrong-owner'
)
# ----- Using runas ------------------------------------------------->
venv_create = self.run_function(
'virtualenv.create', [venv_dir], user=username
)
if venv_create['retcode'] > 0:
self.skipTest(
'Failed to create testcase virtual environment: {0}'.format(
venv_create
)
)
@with_system_user('issue-6912', on_existing='delete', delete=True,
password='PassWord1!')
@with_tempdir()
def test_issue_6912_wrong_owner(self, temp_dir, username):
# Setup virtual environment directory to be used throughout the test
venv_dir = os.path.join(temp_dir, '6912-wrong-owner')
# Using the package name.
try:
ret = self.run_state(
'pip.installed', name='pep8', user=username, bin_env=venv_dir
)
self.assertSaltTrueReturn(ret)
uinfo = pwd.getpwnam(username)
for globmatch in (os.path.join(venv_dir, '**', 'pep8*'),
os.path.join(venv_dir, '*', '**', 'pep8*'),
os.path.join(venv_dir, '*', '*', '**', 'pep8*')):
for path in glob.glob(globmatch):
# The virtual environment needs to be in a location that is accessible
# by both the user running the test and the runas user
if salt.utils.platform.is_windows():
salt.utils.win_dacl.set_permissions(temp_dir, username, 'full_control')
else:
uid = self.run_function('file.user_to_uid', [username])
os.chown(temp_dir, uid, -1)
# Create the virtual environment
venv_create = self.run_function(
'virtualenv.create', [venv_dir], user=username,
password='PassWord1!')
if venv_create['retcode'] > 0:
self.skipTest('Failed to create testcase virtual environment: {0}'
''.format(venv_create))
# pip install passing the package name in `name`
ret = self.run_state(
'pip.installed', name='pep8', user=username, bin_env=venv_dir,
no_cache_dir=True, password='PassWord1!')
self.assertSaltTrueReturn(ret)
if HAS_PWD:
uid = pwd.getpwnam(username).pw_uid
for globmatch in (os.path.join(venv_dir, '**', 'pep8*'),
os.path.join(venv_dir, '*', '**', 'pep8*'),
os.path.join(venv_dir, '*', '*', '**', 'pep8*')):
for path in glob.glob(globmatch):
if HAS_PWD:
self.assertEqual(uid, os.stat(path).st_uid)
elif salt.utils.platform.is_windows():
self.assertEqual(
uinfo.pw_uid, os.stat(path).st_uid
)
salt.utils.win_dacl.get_owner(path), username)
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
@destructiveTest
@skip_if_not_root
@with_system_user('issue-6912', on_existing='delete', delete=True,
password='PassWord1!')
@with_tempdir()
def test_issue_6912_wrong_owner_requirements_file(self, temp_dir, username):
# Setup virtual environment directory to be used throughout the test
venv_dir = os.path.join(temp_dir, '6912-wrong-owner')
# Using a requirements file
# The virtual environment needs to be in a location that is accessible
# by both the user running the test and the runas user
if salt.utils.platform.is_windows():
salt.utils.win_dacl.set_permissions(temp_dir, username, 'full_control')
else:
uid = self.run_function('file.user_to_uid', [username])
os.chown(temp_dir, uid, -1)
# Create the virtual environment again as it should have been removed
venv_create = self.run_function(
'virtualenv.create', [venv_dir], user=username
)
'virtualenv.create', [venv_dir], user=username,
password='PassWord1!')
if venv_create['retcode'] > 0:
self.skipTest(
'Failed to create testcase virtual environment: {0}'.format(
ret
)
)
self.skipTest('failed to create testcase virtual environment: {0}'
''.format(venv_create))
# pip install using a requirements file
req_filename = os.path.join(
RUNTIME_VARS.TMP_STATE_TREE, 'issue-6912-requirements.txt'
)
with salt.utils.files.fopen(req_filename, 'wb') as reqf:
reqf.write(b'pep8\n')
try:
ret = self.run_state(
'pip.installed', name='', user=username, bin_env=venv_dir,
requirements='salt://issue-6912-requirements.txt'
)
self.assertSaltTrueReturn(ret)
uinfo = pwd.getpwnam(username)
for globmatch in (os.path.join(venv_dir, '**', 'pep8*'),
os.path.join(venv_dir, '*', '**', 'pep8*'),
os.path.join(venv_dir, '*', '*', '**', 'pep8*')):
for path in glob.glob(globmatch):
ret = self.run_state(
'pip.installed', name='', user=username, bin_env=venv_dir,
requirements='salt://issue-6912-requirements.txt',
no_cache_dir=True, password='PassWord1!')
self.assertSaltTrueReturn(ret)
if HAS_PWD:
uid = pwd.getpwnam(username).pw_uid
for globmatch in (os.path.join(venv_dir, '**', 'pep8*'),
os.path.join(venv_dir, '*', '**', 'pep8*'),
os.path.join(venv_dir, '*', '*', '**', 'pep8*')):
for path in glob.glob(globmatch):
if HAS_PWD:
self.assertEqual(uid, os.stat(path).st_uid)
elif salt.utils.platform.is_windows():
self.assertEqual(
uinfo.pw_uid, os.stat(path).st_uid
)
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
os.unlink(req_filename)
# <---- Using runas --------------------------------------------------
# ----- Using user -------------------------------------------------->
venv_create = self.run_function(
'virtualenv.create', [venv_dir], user=username
)
if venv_create['retcode'] > 0:
self.skipTest(
'Failed to create testcase virtual environment: {0}'.format(
ret
)
)
# Using the package name
try:
ret = self.run_state(
'pip.installed', name='pep8', user=username, bin_env=venv_dir
)
self.assertSaltTrueReturn(ret)
uinfo = pwd.getpwnam(username)
for globmatch in (os.path.join(venv_dir, '**', 'pep8*'),
os.path.join(venv_dir, '*', '**', 'pep8*'),
os.path.join(venv_dir, '*', '*', '**', 'pep8*')):
for path in glob.glob(globmatch):
self.assertEqual(
uinfo.pw_uid, os.stat(path).st_uid
)
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
# Using a requirements file
venv_create = self.run_function(
'virtualenv.create', [venv_dir], user=username
)
if venv_create['retcode'] > 0:
self.skipTest(
'Failed to create testcase virtual environment: {0}'.format(
ret
)
)
req_filename = os.path.join(
RUNTIME_VARS.TMP_STATE_TREE, 'issue-6912-requirements.txt'
)
with salt.utils.files.fopen(req_filename, 'wb') as reqf:
reqf.write(b'pep8\n')
try:
ret = self.run_state(
'pip.installed', name='', user=username, bin_env=venv_dir,
requirements='salt://issue-6912-requirements.txt'
)
self.assertSaltTrueReturn(ret)
uinfo = pwd.getpwnam(username)
for globmatch in (os.path.join(venv_dir, '**', 'pep8*'),
os.path.join(venv_dir, '*', '**', 'pep8*'),
os.path.join(venv_dir, '*', '*', '**', 'pep8*')):
for path in glob.glob(globmatch):
self.assertEqual(
uinfo.pw_uid, os.stat(path).st_uid
)
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
os.unlink(req_filename)
# <---- Using user ---------------------------------------------------
salt.utils.win_dacl.get_owner(path), username)
def test_issue_6833_pip_upgrade_pip(self):
# Create the testing virtualenv
@ -393,6 +371,7 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
RUNTIME_VARS.TMP, '6833-pip-upgrade-pip'
)
ret = self.run_function('virtualenv.create', [venv_dir])
try:
try:
self.assertEqual(ret['retcode'], 0)
@ -435,18 +414,15 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
)
try:
self.assertSaltTrueReturn(ret)
self.assertInSaltReturn(
'Installed',
ret,
['changes', 'pip==8.0.1']
)
self.assertSaltStateChangesEqual(
ret, {'pip==8.0.1': 'Installed'})
except AssertionError:
import pprint
pprint.pprint(ret)
raise
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
shutil.rmtree(venv_dir, ignore_errors=True)
def test_pip_installed_specific_env(self):
# Create the testing virtualenv
@ -498,16 +474,14 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
)
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
shutil.rmtree(venv_dir, ignore_errors=True)
if os.path.isfile(requirements_file):
os.unlink(requirements_file)
def test_22359_pip_installed_unless_does_not_trigger_warnings(self):
# This test case should be moved to a format_call unit test specific to
# the state internal keywords
venv_dir = venv_dir = os.path.join(
RUNTIME_VARS.TMP, 'pip-installed-unless'
)
venv_dir = os.path.join(RUNTIME_VARS.TMP, 'pip-installed-unless')
venv_create = self.run_function('virtualenv.create', [venv_dir])
if venv_create['retcode'] > 0:
self.skipTest(
@ -516,17 +490,21 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
)
)
false_cmd = '/bin/false'
if salt.utils.platform.is_windows():
false_cmd = 'exit 1 >nul'
try:
ret = self.run_state(
'pip.installed', name='pep8', bin_env=venv_dir, unless='/bin/false'
'pip.installed', name='pep8', bin_env=venv_dir, unless=false_cmd
)
self.assertSaltTrueReturn(ret)
self.assertNotIn('warnings', next(six.itervalues(ret)))
finally:
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)
shutil.rmtree(venv_dir, ignore_errors=True)
@skipIf(sys.version_info[:2] >= (3, 6), 'Old version of virtualenv too old for python3.6')
@skipIf(salt.utils.platform.is_windows(), "Carbon does not install in Windows")
def test_46127_pip_env_vars(self):
'''
Test that checks if env_vars passed to pip.installed are also passed
@ -550,7 +528,7 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
)
finally:
if os.path.isdir(ographite):
shutil.rmtree(ographite)
shutil.rmtree(ographite, ignore_errors=True)
venv_dir = os.path.join(RUNTIME_VARS.TMP, 'issue-46127-pip-env-vars')
try:
@ -559,7 +537,7 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
# context when running the call to state.sls that comes after.
self.run_function('saltutil.sync_modules')
# Since we don't have the virtualenv created, pip.installed will
# thrown and error.
# throw an error.
ret = self.run_function(
'state.sls', mods='issue-46127-pip-env-vars'
)
@ -598,6 +576,6 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
raise Exception('Expected state did not run')
finally:
if os.path.isdir(ographite):
shutil.rmtree(ographite)
shutil.rmtree(ographite, ignore_errors=True)
if os.path.isdir(venv_dir):
shutil.rmtree(venv_dir)

View File

@ -57,6 +57,7 @@ from tests.support.paths import FILES, TMP
# Import Salt libs
import salt.utils.files
import salt.utils.platform
log = logging.getLogger(__name__)
@ -613,10 +614,10 @@ def requires_network(only_local_network=False):
return decorator
def with_system_user(username, on_existing='delete', delete=True):
def with_system_user(username, on_existing='delete', delete=True, password=None):
'''
Create and optionally destroy a system user to be used within a test
case. The system user is crated using the ``user`` salt module.
case. The system user is created using the ``user`` salt module.
The decorated testcase function must accept 'username' as an argument.
@ -646,7 +647,10 @@ def with_system_user(username, on_existing='delete', delete=True):
# Let's add the user to the system.
log.debug('Creating system user {0!r}'.format(username))
create_user = cls.run_function('user.add', [username])
kwargs = {'timeout': 60}
if salt.utils.platform.is_windows():
kwargs.update({'password': password})
create_user = cls.run_function('user.add', [username], **kwargs)
if not create_user:
log.debug('Failed to create system user')
# The user was not created
@ -702,7 +706,7 @@ def with_system_user(username, on_existing='delete', delete=True):
finally:
if delete:
delete_user = cls.run_function(
'user.delete', [username, True, True]
'user.delete', [username, True, True], timeout=60
)
if not delete_user:
if failure is None:
@ -1117,7 +1121,6 @@ def requires_salt_modules(*names):
def skip_if_binaries_missing(*binaries, **kwargs):
import salt.utils
import salt.utils.path
if len(binaries) == 1:
if isinstance(binaries[0], (list, tuple, set, frozenset)):

View File

@ -3,6 +3,7 @@
# Import python libs
from __future__ import absolute_import
import os
import sys
# Import Salt Testing libs
from tests.support.mixins import LoaderModuleMockMixin
@ -10,7 +11,6 @@ from tests.support.unit import skipIf, TestCase
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch
# Import salt libs
from salt.ext import six
import salt.utils.platform
import salt.modules.pip as pip
from salt.exceptions import CommandExecutionError
@ -25,9 +25,8 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(requirements='requirements.txt')
expected_cmd = ['pip', 'install', '--requirement',
'requirements.txt']
mock.assert_called_once_with(
expected_cmd = [sys.executable, '-m', 'pip', 'install', '--requirement', 'requirements.txt']
mock.assert_called_with(
expected_cmd,
saltenv='base',
runas=None,
@ -50,7 +49,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting'
]
expected = ['pip', 'install']
expected = [sys.executable, '-m', 'pip', 'install']
for item in editables:
expected.extend(['--editable', item])
@ -58,7 +57,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(editable=editables)
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -70,7 +69,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(editable=','.join(editables))
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -85,7 +84,8 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting'
]
expected = ['pip', 'install'] + pkgs
expected = [sys.executable, '-m', 'pip', 'install']
expected.extend(pkgs)
for item in editables:
expected.extend(['--editable', item])
@ -93,7 +93,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkgs=pkgs, editable=editables)
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -105,7 +105,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkgs=','.join(pkgs), editable=','.join(editables))
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -117,8 +117,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkgs=pkgs[0], editable=editables[0])
mock.assert_called_once_with(
['pip', 'install', pkgs[0], '--editable', editables[0]],
expected = [sys.executable, '-m', 'pip', 'install', pkgs[0], '--editable', editables[0]]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -136,7 +137,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
'http://pypi.crate.io'
]
expected = ['pip', 'install', '--use-mirrors']
expected = [sys.executable, '-m', 'pip', 'install', '--use-mirrors']
for item in mirrors:
expected.extend(['--mirrors', item])
expected.append('pep8')
@ -145,7 +146,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkgs=['pep8'], mirrors=mirrors)
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -157,7 +158,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkgs=['pep8'], mirrors=','.join(mirrors))
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -165,12 +166,14 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
python_shell=False,
)
expected = [sys.executable, '-m', 'pip', 'install', '--use-mirrors', '--mirrors', mirrors[0], 'pep8']
# As single string (just use the first element from mirrors)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkgs=['pep8'], mirrors=mirrors[0])
mock.assert_called_once_with(
['pip', 'install', '--use-mirrors', '--mirrors', mirrors[0], 'pep8'],
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -185,7 +188,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
]
pkg = 'pep8'
expected = ['pip', 'install']
expected = [sys.executable, '-m', 'pip', 'install']
for item in find_links:
expected.extend(['--find-links', item])
expected.append(pkg)
@ -194,7 +197,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, find_links=find_links)
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -206,7 +209,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, find_links=','.join(find_links))
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -214,12 +217,26 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
python_shell=False,
)
# Valid protos work?
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, find_links=find_links)
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
python_shell=False,
)
expected = [sys.executable, '-m', 'pip', 'install', '--find-links', find_links[0], pkg]
# As single string (just use the first element from find_links)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, find_links=find_links[0])
mock.assert_called_once_with(
['pip', 'install', '--find-links', find_links[0], pkg],
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -236,18 +253,6 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
find_links='sftp://pypi.crate.io'
)
# Valid protos work?
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, find_links=find_links)
mock.assert_called_once_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
python_shell=False,
)
def test_install_no_index_with_index_url_or_extra_index_url_raises(self):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
@ -276,8 +281,8 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(requirements='salt://requirements.txt')
expected = ['pip', 'install', '--requirement', 'my_cached_reqs']
mock.assert_called_once_with(
expected = [sys.executable, '-m', 'pip', 'install', '--requirement', 'my_cached_reqs']
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -287,28 +292,29 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
def test_install_venv(self):
with patch('os.path') as mock_path:
mock_path.is_file.return_value = True
mock_path.isdir.return_value = True
pkg = 'mock'
def join(*args):
return os.sep.join(args)
return os.path.normpath(os.sep.join(args))
mock_path.is_file.return_value = True
mock_path.isdir.return_value = True
mock_path.join = join
if salt.utils.platform.is_windows():
venv_path = 'C:\\test_env'
bin_path = os.path.join(venv_path, 'python.exe')
else:
venv_path = '/test_env'
bin_path = os.path.join(venv_path, 'python')
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
if salt.utils.platform.is_windows():
venv_path = 'c:\\test_env'
bin_path = os.path.join(venv_path, 'Scripts', 'pip.exe')
if six.PY2:
bin_path = bin_path.encode('string-escape')
else:
venv_path = '/test_env'
bin_path = os.path.join(venv_path, 'bin', 'pip')
pip.install(pkg, bin_env=venv_path)
mock.assert_called_once_with(
[bin_path, 'install', pkg],
pip_bin = MagicMock(return_value=[bin_path, '-m', 'pip'])
with patch.dict(pip.__salt__, {'cmd.run_all': mock}), \
patch.object(pip, '_get_pip_bin', pip_bin):
pip.install('mock', bin_env=venv_path)
mock.assert_called_with(
[bin_path, '-m', 'pip', 'install', 'mock'],
env={'VIRTUAL_ENV': venv_path},
saltenv='base',
runas=None,
@ -323,8 +329,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, log=log_path)
mock.assert_called_once_with(
['pip', 'install', '--log', log_path, pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--log', log_path, pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -349,12 +356,12 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
def test_install_timeout_argument_in_resulting_command(self):
# Passing an int
pkg = 'pep8'
expected_prefix = ['pip', 'install', '--timeout']
expected = [sys.executable, '-m', 'pip', 'install', '--timeout']
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, timeout=10)
mock.assert_called_once_with(
expected_prefix + [10, pkg],
mock.assert_called_with(
expected + [10, pkg],
saltenv='base',
runas=None,
use_vt=False,
@ -365,8 +372,8 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, timeout='10')
mock.assert_called_once_with(
expected_prefix + ['10', pkg],
mock.assert_called_with(
expected + ['10', pkg],
saltenv='base',
runas=None,
use_vt=False,
@ -389,8 +396,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, index_url=index_url)
mock.assert_called_once_with(
['pip', 'install', '--index-url', index_url, pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--index-url', index_url, pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -403,8 +411,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, extra_index_url=extra_index_url)
mock.assert_called_once_with(
['pip', 'install', '--extra-index-url', extra_index_url, pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--extra-index-url', extra_index_url, pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -416,8 +425,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, no_index=True)
mock.assert_called_once_with(
['pip', 'install', '--no-index', pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--no-index', pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -430,8 +440,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, build=build)
mock.assert_called_once_with(
['pip', 'install', '--build', build, pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--build', build, pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -444,8 +455,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, target=target)
mock.assert_called_once_with(
['pip', 'install', '--target', target, pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--target', target, pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -458,8 +470,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, download=download)
mock.assert_called_once_with(
['pip', 'install', '--download', download, pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--download', download, pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -471,8 +484,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, no_download=True)
mock.assert_called_once_with(
['pip', 'install', '--no-download', pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--no-download', pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -494,8 +508,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
MagicMock(return_value=pip_version)):
# test `download_cache` kwarg
pip.install(pkg, download_cache='/tmp/foo')
expected = [sys.executable, '-m', 'pip', 'install', cmd_arg, download_cache, pkg]
mock.assert_called_with(
['pip', 'install', cmd_arg, download_cache, pkg],
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -505,7 +520,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
# test `cache_dir` kwarg
pip.install(pkg, cache_dir='/tmp/foo')
mock.assert_called_with(
['pip', 'install', cmd_arg, download_cache, pkg],
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -518,8 +533,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, source=source)
mock.assert_called_once_with(
['pip', 'install', '--source', source, pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--source', source, pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -531,9 +547,10 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
for action in ('s', 'i', 'w', 'b'):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install('pep8', exists_action=action)
mock.assert_called_once_with(
['pip', 'install', '--exists-action', action, pkg],
pip.install(pkg, exists_action=action)
expected = [sys.executable, '-m', 'pip', 'install', '--exists-action', action, pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -557,7 +574,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
]
pkg = 'pep8'
expected = ['pip', 'install']
expected = [sys.executable, '-m', 'pip', 'install']
for item in install_options:
expected.extend(['--install-option', item])
expected.append(pkg)
@ -566,7 +583,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, install_options=install_options)
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -578,7 +595,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, install_options=','.join(install_options))
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -590,9 +607,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, install_options=install_options[0])
mock.assert_called_once_with(
['pip', 'install', '--install-option',
install_options[0], pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--install-option', install_options[0], pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -606,7 +623,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
]
pkg = 'pep8'
expected = ['pip', 'install']
expected = [sys.executable, '-m', 'pip', 'install']
for item in global_options:
expected.extend(['--global-option', item])
expected.append(pkg)
@ -615,7 +632,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, global_options=global_options)
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -627,7 +644,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, global_options=','.join(global_options))
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -639,8 +656,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, global_options=global_options[0])
mock.assert_called_once_with(
['pip', 'install', '--global-option', global_options[0], pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--global-option', global_options[0], pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -652,8 +670,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, upgrade=True)
mock.assert_called_once_with(
['pip', 'install', '--upgrade', pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--upgrade', pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -665,8 +684,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, force_reinstall=True)
mock.assert_called_once_with(
['pip', 'install', '--force-reinstall', pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--force-reinstall', pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -678,8 +698,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, ignore_installed=True)
mock.assert_called_once_with(
['pip', 'install', '--ignore-installed', pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--ignore-installed', pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -691,8 +712,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, no_deps=True)
mock.assert_called_once_with(
['pip', 'install', '--no-deps', pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--no-deps', pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -704,8 +726,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, no_install=True)
mock.assert_called_once_with(
['pip', 'install', '--no-install', pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--no-install', pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -718,8 +741,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(pkg, proxy=proxy)
mock.assert_called_once_with(
['pip', 'install', '--proxy', proxy, pkg],
expected = [sys.executable, '-m', 'pip', 'install', '--proxy', proxy, pkg]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -736,7 +760,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
'salt://requirements-1.txt', 'salt://requirements-2.txt'
]
expected = ['pip', 'install']
expected = [sys.executable, '-m', 'pip', 'install']
for item in cached_reqs:
expected.extend(['--requirement', item])
@ -744,7 +768,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(requirements=requirements)
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -757,7 +781,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(requirements=','.join(requirements))
mock.assert_called_once_with(
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
@ -770,8 +794,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.install(requirements=requirements[0])
mock.assert_called_once_with(
['pip', 'install', '--requirement', cached_reqs[0]],
expected = [sys.executable, '-m', 'pip', 'install', '--requirement', cached_reqs[0]]
mock.assert_called_with(
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -788,7 +813,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
'salt://requirements-1.txt', 'salt://requirements-2.txt'
]
expected = ['pip', 'uninstall', '-y']
expected = [sys.executable, '-m', 'pip', 'uninstall', '-y']
for item in cached_reqs:
expected.extend(['--requirement', item])
@ -796,7 +821,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.uninstall(requirements=requirements)
mock.assert_called_once_with(
mock.assert_called_with(
expected,
cwd=None,
saltenv='base',
@ -810,7 +835,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.uninstall(requirements=','.join(requirements))
mock.assert_called_once_with(
mock.assert_called_with(
expected,
cwd=None,
saltenv='base',
@ -824,8 +849,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.uninstall(requirements=requirements[0])
mock.assert_called_once_with(
['pip', 'uninstall', '-y', '--requirement', cached_reqs[0]],
expected = [sys.executable, '-m', 'pip', 'uninstall', '-y', '--requirement', cached_reqs[0]]
mock.assert_called_with(
expected,
cwd=None,
saltenv='base',
runas=None,
@ -839,8 +865,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.uninstall(pkg, proxy=proxy)
mock.assert_called_once_with(
['pip', 'uninstall', '-y', '--proxy', proxy, pkg],
expected = [sys.executable, '-m', 'pip', 'uninstall', '-y', '--proxy', proxy, pkg]
mock.assert_called_with(
expected,
saltenv='base',
cwd=None,
runas=None,
@ -849,22 +876,24 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
)
def test_uninstall_log_argument_in_resulting_command(self):
with patch('os.path') as mock_path:
pkg = 'pep8'
log_path = '/tmp/pip-install.log'
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.uninstall(pkg, log=log_path)
mock.assert_called_once_with(
['pip', 'uninstall', '-y', '--log', log_path, pkg],
saltenv='base',
cwd=None,
runas=None,
use_vt=False,
python_shell=False,
)
pkg = 'pep8'
log_path = '/tmp/pip-install.log'
# Let's fake a non-writable log file
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.uninstall(pkg, log=log_path)
expected = [sys.executable, '-m', 'pip', 'uninstall', '-y', '--log', log_path, pkg]
mock.assert_called_with(
expected,
saltenv='base',
cwd=None,
runas=None,
use_vt=False,
python_shell=False,
)
# Let's fake a non-writable log file
with patch('os.path') as mock_path:
mock_path.exists.side_effect = IOError('Fooo!')
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
@ -877,13 +906,13 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
def test_uninstall_timeout_argument_in_resulting_command(self):
pkg = 'pep8'
expected_prefix = ['pip', 'uninstall', '-y', '--timeout']
expected = [sys.executable, '-m', 'pip', 'uninstall', '-y', '--timeout']
# Passing an int
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.uninstall(pkg, timeout=10)
mock.assert_called_once_with(
expected_prefix + [10, pkg],
mock.assert_called_with(
expected + [10, pkg],
cwd=None,
saltenv='base',
runas=None,
@ -895,8 +924,8 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
pip.uninstall(pkg, timeout='10')
mock.assert_called_once_with(
expected_prefix + ['10', pkg],
mock.assert_called_with(
expected + ['10', pkg],
cwd=None,
saltenv='base',
runas=None,
@ -915,6 +944,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
)
def test_freeze_command(self):
expected = [sys.executable, '-m', 'pip', 'freeze']
eggs = [
'M2Crypto==0.21.1',
'-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev',
@ -932,8 +962,8 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
with patch('salt.modules.pip.version',
MagicMock(return_value='6.1.1')):
ret = pip.freeze()
mock.assert_called_once_with(
['pip', 'freeze'],
mock.assert_called_with(
expected,
cwd=None,
runas=None,
use_vt=False,
@ -952,8 +982,8 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
with patch('salt.modules.pip.version',
MagicMock(return_value='6.1.1')):
ret = pip.freeze(env_vars={"foo": "bar"})
mock.assert_called_once_with(
['pip', 'freeze'],
mock.assert_called_with(
expected,
cwd=None,
runas=None,
use_vt=False,
@ -992,8 +1022,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
with patch('salt.modules.pip.version',
MagicMock(return_value='9.0.1')):
ret = pip.freeze()
mock.assert_called_once_with(
['pip', 'freeze', '--all'],
expected = [sys.executable, '-m', 'pip', 'freeze', '--all']
mock.assert_called_with(
expected,
cwd=None,
runas=None,
use_vt=False,
@ -1025,8 +1056,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
with patch('salt.modules.pip.version',
MagicMock(return_value=mock_version)):
ret = pip.list_()
expected = [sys.executable, '-m', 'pip', 'freeze']
mock.assert_called_with(
['pip', 'freeze'],
expected,
cwd=None,
runas=None,
python_shell=False,
@ -1072,8 +1104,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
with patch('salt.modules.pip.version',
MagicMock(return_value=mock_version)):
ret = pip.list_()
expected = [sys.executable, '-m', 'pip', 'freeze', '--all']
mock.assert_called_with(
['pip', 'freeze', '--all'],
expected,
cwd=None,
runas=None,
python_shell=False,
@ -1119,8 +1152,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
with patch('salt.modules.pip.version',
MagicMock(return_value='6.1.1')):
ret = pip.list_(prefix='bb')
expected = [sys.executable, '-m', 'pip', 'freeze']
mock.assert_called_with(
['pip', 'freeze'],
expected,
cwd=None,
runas=None,
python_shell=False,
@ -1135,9 +1169,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
def test_list_upgrades_legacy(self):
eggs = [
'apache-libcloud (1.1.0) - Latest: 2.2.1 [wheel]',
'appdirs (1.4.1) - Latest: 1.4.3 [wheel]',
'awscli (1.11.63) - Latest: 1.12.1 [sdist]'
'apache-libcloud (Current: 1.1.0 Latest: 2.2.1 [wheel])',
'appdirs (Current: 1.4.1 Latest: 1.4.3 [wheel])',
'awscli (Current: 1.11.63 Latest: 1.12.1 [sdist])'
]
mock = MagicMock(
return_value={
@ -1150,7 +1184,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
MagicMock(return_value='6.1.1')):
ret = pip.list_upgrades()
mock.assert_called_with(
['pip', 'list', '--outdated'],
[sys.executable, '-m', 'pip', 'list', '--outdated'],
cwd=None,
runas=None,
)
@ -1178,15 +1212,15 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
MagicMock(return_value='9.1.1')):
ret = pip.list_upgrades()
mock.assert_called_with(
['pip', 'list', '--outdated', '--format=json'],
[sys.executable, '-m', 'pip', 'list', '--outdated', '--format=json'],
cwd=None,
runas=None,
)
self.assertEqual(
ret, {
'apache-libcloud': '2.2.1',
'appdirs': '1.4.3',
'awscli': '1.12.1'
'apache-libcloud': '2.2.1 [wheel]',
'appdirs': '1.4.3 [wheel]',
'awscli': '1.12.1 [sdist]'
}
)
@ -1209,7 +1243,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
MagicMock(return_value='6.1.1')):
ret = pip.is_installed(pkgname='bbfreeze')
mock.assert_called_with(
['pip', 'freeze'],
[sys.executable, '-m', 'pip', 'freeze'],
cwd=None,
runas=None,
python_shell=False,
@ -1236,7 +1270,7 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
MagicMock(return_value='6.1.1')):
ret = pip.is_installed(pkgname='notexist')
mock.assert_called_with(
['pip', 'freeze'],
[sys.executable, '-m', 'pip', 'freeze'],
cwd=None,
runas=None,
python_shell=False,
@ -1256,8 +1290,9 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
with patch('salt.modules.pip.version',
MagicMock(return_value='1.3')):
pip.install(pkg, pre_releases=True)
expected = [sys.executable, '-m', 'pip', 'install', pkg]
mock.assert_called_with(
['pip', 'install', pkg],
expected,
saltenv='base',
runas=None,
use_vt=False,
@ -1269,10 +1304,11 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
with patch.dict(pip.__salt__, {'cmd.run_stdout': mock_run,
'cmd.run_all': mock_run_all}):
with patch('salt.modules.pip._get_pip_bin',
MagicMock(return_value='pip')):
MagicMock(return_value=['pip'])):
pip.install(pkg, pre_releases=True)
expected = ['pip', 'install', '--pre', pkg]
mock_run_all.assert_called_with(
['pip', 'install', '--pre', pkg],
expected,
saltenv='base',
runas=None,
use_vt=False,

View File

@ -17,6 +17,7 @@ from tests.support.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch
# Import salt libs
import salt.states.pip_state as pip_state
import salt.utils.versions
# Import 3rd-party libs
try:
@ -43,211 +44,163 @@ class PipStateTest(TestCase, SaltReturnAssertsMixin, LoaderModuleMockMixin):
def test_install_requirements_parsing(self):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.3'})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed('pep8=1.3.2')
self.assertSaltFalseReturn({'test': ret})
self.assertInSaltComment(
'Invalid version specification in package pep8=1.3.2. '
'\'=\' is not supported, use \'==\' instead.',
{'test': ret}
)
pip_version = pip.__version__
mock_pip_version = MagicMock(return_value=pip_version)
with patch.dict(pip_state.__salt__, {'pip.version': mock_pip_version}):
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
if salt.utils.versions.compare(ver1=pip_version,
oper='<',
ver2='10.0'):
ret = pip_state.installed('pep8=1.3.2')
self.assertSaltFalseReturn({'test': ret})
self.assertInSaltComment(
'Invalid version specification in package pep8=1.3.2. '
'\'=\' is not supported, use \'==\' instead.',
{'test': ret})
else:
self.assertRaises(
pip._internal.exceptions.InstallationError,
pip_state.installed, 'pep=1.3.2')
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.3'})
pip_install = MagicMock(return_value={'retcode': 0})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed('pep8>=1.3.2')
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment(
'Python package pep8>=1.3.2 was already installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.3'})
pip_install = MagicMock(return_value={'retcode': 0})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed('pep8>=1.3.2')
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment(
'Python package pep8>=1.3.2 was already installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.3'})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed('pep8<1.3.2')
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package pep8<1.3.2 is set to be installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.3'})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed('pep8<1.3.2')
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package pep8<1.3.2 is set to be installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.2'})
pip_install = MagicMock(return_value={'retcode': 0})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed('pep8>1.3.1,<1.3.3')
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment(
'Python package pep8>1.3.1,<1.3.3 was already installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.2'})
pip_install = MagicMock(return_value={'retcode': 0})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed('pep8>1.3.1,<1.3.3')
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment(
'Python package pep8>1.3.1,<1.3.3 was already installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
pip_install = MagicMock(return_value={'retcode': 0})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed('pep8>1.3.1,<1.3.3')
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package pep8>1.3.1,<1.3.3 is set to be installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
pip_install = MagicMock(return_value={'retcode': 0})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed('pep8>1.3.1,<1.3.3')
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package pep8>1.3.1,<1.3.3 is set to be installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed(
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting>=0.5.1'
)
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package git+https://github.com/saltstack/'
'salt-testing.git#egg=SaltTesting>=0.5.1 is set to be '
'installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed(
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting>=0.5.1'
)
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package git+https://github.com/saltstack/'
'salt-testing.git#egg=SaltTesting>=0.5.1 is set to be '
'installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed(
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting'
)
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package git+https://github.com/saltstack/'
'salt-testing.git#egg=SaltTesting is set to be '
'installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed(
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting'
)
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package git+https://github.com/saltstack/'
'salt-testing.git#egg=SaltTesting is set to be '
'installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
ret = pip_state.installed(
'https://pypi.python.org/packages/source/S/SaltTesting/'
'SaltTesting-0.5.0.tar.gz'
'#md5=e6760af92b7165f8be53b5763e40bc24'
)
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package https://pypi.python.org/packages/source/'
'S/SaltTesting/SaltTesting-0.5.0.tar.gz'
'#md5=e6760af92b7165f8be53b5763e40bc24 is set to be '
'installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'SaltTesting': '0.5.0'})
pip_install = MagicMock(return_value={
'retcode': 0,
'stderr': '',
'stdout': 'Downloading/unpacking https://pypi.python.org/packages'
'/source/S/SaltTesting/SaltTesting-0.5.0.tar.gz\n '
'Downloading SaltTesting-0.5.0.tar.gz\n Running '
'setup.py egg_info for package from '
'https://pypi.python.org/packages/source/S/SaltTesting/'
'SaltTesting-0.5.0.tar.gz\n \nCleaning up...'
})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
ret = pip_state.installed(
'https://pypi.python.org/packages/source/S/SaltTesting/'
'SaltTesting-0.5.0.tar.gz'
'#md5=e6760af92b7165f8be53b5763e40bc24'
)
self.assertSaltNoneReturn({'test': ret})
self.assertInSaltComment(
'Python package https://pypi.python.org/packages/source/'
'S/SaltTesting/SaltTesting-0.5.0.tar.gz'
'#md5=e6760af92b7165f8be53b5763e40bc24 is set to be '
'installed',
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment('All packages were successfully installed',
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'SaltTesting': '0.5.0'})
pip_install = MagicMock(return_value={
'retcode': 0,
'stderr': '',
'stdout': 'Downloading/unpacking https://pypi.python.org/packages'
'/source/S/SaltTesting/SaltTesting-0.5.0.tar.gz\n '
'Downloading SaltTesting-0.5.0.tar.gz\n Running '
'setup.py egg_info for package from '
'https://pypi.python.org/packages/source/S/SaltTesting/'
'SaltTesting-0.5.0.tar.gz\n \nCleaning up...'
})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
ret = pip_state.installed(
'https://pypi.python.org/packages/source/S/SaltTesting/'
'SaltTesting-0.5.0.tar.gz'
'#md5=e6760af92b7165f8be53b5763e40bc24'
)
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment('All packages were successfully installed',
{'test': ret}
)
self.assertInSaltReturn(
'Installed',
{'test': ret},
('changes', 'https://pypi.python.org/packages/source/S/'
'SaltTesting/SaltTesting-0.5.0.tar.gz'
'#md5=e6760af92b7165f8be53b5763e40bc24==???')
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'SaltTesting': '0.5.0'})
pip_install = MagicMock(return_value={
'retcode': 0,
'stderr': '',
'stdout': 'Cloned!'
})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': False}):
ret = pip_state.installed(
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting'
)
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment(
'packages are already installed',
{'test': ret}
self.assertInSaltReturn(
'Installed',
{'test': ret},
('changes', 'https://pypi.python.org/packages/source/S/'
'SaltTesting/SaltTesting-0.5.0.tar.gz'
'#md5=e6760af92b7165f8be53b5763e40bc24==???')
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
pip_install = MagicMock(return_value={'retcode': 0})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': False}):
ret = pip_state.installed(
'arbitrary ID that should be ignored due to requirements specified',
requirements='/tmp/non-existing-requirements.txt'
)
self.assertSaltTrueReturn({'test': ret})
# Test VCS installations using git+git://
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'SaltTesting': '0.5.0'})
pip_install = MagicMock(return_value={
'retcode': 0,
'stderr': '',
'stdout': 'Cloned!'
})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': False}):
ret = pip_state.installed(
'git+git://github.com/saltstack/salt-testing.git#egg=SaltTesting'
)
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment(
'packages are already installed',
{'test': ret}
)
# Test VCS installations with version info like >= 0.1
with patch.object(pip, '__version__', MagicMock(side_effect=AttributeError(
'Faked missing __version__ attribute'))):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'SaltTesting': '0.5.0'})
pip_install = MagicMock(return_value={
@ -260,7 +213,7 @@ class PipStateTest(TestCase, SaltReturnAssertsMixin, LoaderModuleMockMixin):
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': False}):
ret = pip_state.installed(
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting>=0.5.0'
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting'
)
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment(
@ -268,6 +221,63 @@ class PipStateTest(TestCase, SaltReturnAssertsMixin, LoaderModuleMockMixin):
{'test': ret}
)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.1'})
pip_install = MagicMock(return_value={'retcode': 0})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': False}):
ret = pip_state.installed(
'arbitrary ID that should be ignored due to requirements specified',
requirements='/tmp/non-existing-requirements.txt'
)
self.assertSaltTrueReturn({'test': ret})
# Test VCS installations using git+git://
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'SaltTesting': '0.5.0'})
pip_install = MagicMock(return_value={
'retcode': 0,
'stderr': '',
'stdout': 'Cloned!'
})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': False}):
ret = pip_state.installed(
'git+git://github.com/saltstack/salt-testing.git#egg=SaltTesting'
)
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment(
'packages are already installed',
{'test': ret}
)
# Test VCS installations with version info like >= 0.1
with patch.object(pip, '__version__', MagicMock(side_effect=AttributeError(
'Faked missing __version__ attribute'))):
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'SaltTesting': '0.5.0'})
pip_install = MagicMock(return_value={
'retcode': 0,
'stderr': '',
'stdout': 'Cloned!'
})
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
with patch.dict(pip_state.__opts__, {'test': False}):
ret = pip_state.installed(
'git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting>=0.5.0'
)
self.assertSaltTrueReturn({'test': ret})
self.assertInSaltComment(
'packages are already installed',
{'test': ret}
)
def test_install_in_editable_mode(self):
'''
Check that `name` parameter containing bad characters is not parsed by
@ -281,9 +291,11 @@ class PipStateTest(TestCase, SaltReturnAssertsMixin, LoaderModuleMockMixin):
'stderr': '',
'stdout': 'Cloned!'
})
pip_version = MagicMock(return_value='10.0.1')
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list,
'pip.install': pip_install}):
'pip.install': pip_install,
'pip.version': pip_version}):
ret = pip_state.installed('state@name',
cwd='/path/to/project',
editable=['.'])

View File

@ -208,3 +208,238 @@ class StringutilsTestCase(TestCase):
self.assertTrue(salt.utils.stringutils.expr_match(val, r'foo/\w+/baz'))
# Regex non-match
self.assertFalse(salt.utils.stringutils.expr_match(val, r'foo/\w/baz'))
def test_check_whitelist_blacklist(self):
'''
Ensure that whitelist matching works on both PY2 and PY3
'''
whitelist = ['one/two/three', r'web[0-9]']
blacklist = ['four/five/six', r'web[5-9]']
# Tests with string whitelist/blacklist
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web_one',
whitelist=whitelist[1],
blacklist=None,
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web_one',
whitelist=whitelist[1],
blacklist=[],
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web1',
whitelist=whitelist[1],
blacklist=None,
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web1',
whitelist=whitelist[1],
blacklist=[],
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web5',
whitelist=None,
blacklist=blacklist[1],
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web5',
whitelist=[],
blacklist=blacklist[1],
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web_five',
whitelist=None,
blacklist=blacklist[1],
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web_five',
whitelist=[],
blacklist=blacklist[1],
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web5',
whitelist=whitelist[1],
blacklist=blacklist[1],
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web4',
whitelist=whitelist[1],
blacklist=blacklist[1],
)
)
# Tests with list whitelist/blacklist
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web_one',
whitelist=whitelist,
blacklist=None,
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web_one',
whitelist=whitelist,
blacklist=[],
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web1',
whitelist=whitelist,
blacklist=None,
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web1',
whitelist=whitelist,
blacklist=[],
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web5',
whitelist=None,
blacklist=blacklist,
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web5',
whitelist=[],
blacklist=blacklist,
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web_five',
whitelist=None,
blacklist=blacklist,
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web_five',
whitelist=[],
blacklist=blacklist,
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web5',
whitelist=whitelist,
blacklist=blacklist,
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web4',
whitelist=whitelist,
blacklist=blacklist,
)
)
# Tests with set whitelist/blacklist
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web_one',
whitelist=set(whitelist),
blacklist=None,
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web_one',
whitelist=set(whitelist),
blacklist=set(),
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web1',
whitelist=set(whitelist),
blacklist=None,
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web1',
whitelist=set(whitelist),
blacklist=set(),
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web5',
whitelist=None,
blacklist=set(blacklist),
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web5',
whitelist=set(),
blacklist=set(blacklist),
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web_five',
whitelist=None,
blacklist=set(blacklist),
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web_five',
whitelist=set(),
blacklist=set(blacklist),
)
)
self.assertFalse(
salt.utils.stringutils.check_whitelist_blacklist(
'web5',
whitelist=set(whitelist),
blacklist=set(blacklist),
)
)
self.assertTrue(
salt.utils.stringutils.check_whitelist_blacklist(
'web4',
whitelist=set(whitelist),
blacklist=set(blacklist),
)
)
# Test with invalid type for whitelist/blacklist
self.assertRaises(
TypeError,
salt.utils.stringutils.check_whitelist_blacklist,
'foo', whitelist=123
)
self.assertRaises(
TypeError,
salt.utils.stringutils.check_whitelist_blacklist,
'foo', blacklist=123
)

View File

@ -891,6 +891,17 @@ class ZfsUtilsTestCase(TestCase):
This class contains a set of functions that test salt.utils.zfs utils
'''
## NOTE: test parameter parsing
def test_is_supported(self):
'''
Test zfs.is_supported method
'''
for value in [False, True]:
with patch('salt.utils.path.which',
MagicMock(return_value=value)):
with patch('salt.utils.platform.is_linux',
MagicMock(return_value=value)):
self.assertEqual(value, zfs.is_supported())
def test_property_data_zpool(self):
'''
Test parsing of zpool get output

View File

@ -19,6 +19,7 @@ integration.modules.test_mine
integration.modules.test_network
integration.modules.test_ntp
integration.modules.test_pillar
integration.modules.test_pip
integration.modules.test_pkg
integration.modules.test_publish
integration.modules.test_service
@ -36,6 +37,7 @@ integration.runners.test_jobs
integration.runners.test_salt
integration.sdb.test_env
integration.states.test_host
integration.states.test_pip
integration.states.test_reg
integration.states.test_renderers
integration.utils.testprogram