Merge branch '2018.3' into solarisips_fixes

This commit is contained in:
Daniel Wozniak 2019-02-12 21:22:15 -07:00 committed by GitHub
commit e8e91e3b27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 6346 additions and 263 deletions

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-API" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-API" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-api \- salt-api Command
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CALL" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-CALL" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-call \- salt-call Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CLOUD" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-CLOUD" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-cloud \- Salt Cloud Command
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CP" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-CP" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-cp \- salt-cp Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-KEY" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-KEY" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-key \- salt-key Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-MASTER" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-MASTER" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-master \- salt-master Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-MINION" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-MINION" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-minion \- salt-minion Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-PROXY" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-PROXY" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-proxy \- salt-proxy Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-RUN" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-RUN" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-run \- salt-run Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-SSH" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-SSH" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-ssh \- salt-ssh Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-SYNDIC" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-SYNDIC" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-syndic \- salt-syndic Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-UNITY" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT-UNITY" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt-unity \- salt-unity Command
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt \- salt
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT" "7" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SALT" "7" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
salt \- Salt Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SPM" "1" "Sep 21, 2018" "2018.3.3" "Salt"
.TH "SPM" "1" "Sep 21, 2018" "2018.3.4" "Salt"
.SH NAME
spm \- Salt Package Manager Command
.

View file

@ -2599,6 +2599,8 @@ can have multiple root directories. The subdirectories in the multiple file
roots cannot match, otherwise the downloaded files will not be able to be
reliably ensured. A base environment is required to house the top file.
As of 2018.3.5 and 2019.2.1, it is possible to have `__env__` as a catch-all environment.
Example:
.. code-block:: yaml
@ -2612,6 +2614,8 @@ Example:
prod:
- /srv/salt/prod/services
- /srv/salt/prod/states
__env__:
- /srv/salt/default
.. note::
For masterless Salt, this parameter must be specified in the minion config

View file

@ -803,6 +803,23 @@ A value of 10 minutes is a reasonable default.
grains_refresh_every: 0
.. conf_minion:: metadata_server_grains
``metadata_server_grains``
--------------------------
.. versionadded:: 2017.7.0
Default: ``False``
Set this option to enable gathering of cloud metadata from
``http://169.254.169.254/latest`` for use in grains (see :py:mod:`here
<salt.grains.metadata>` for more information).
.. code-block:: yaml
metadata_server_grains: True
.. conf_minion:: fibre_channel_grains
``fibre_channel_grains``

File diff suppressed because it is too large Load diff

View file

@ -734,6 +734,19 @@ Then the ``roots`` backend (the default backend of files in ``/srv/salt``) will
be searched first for the requested file; then, if it is not found on the
master, each configured git remote will be searched.
.. note::
This can be used together with `file_roots` accepting `__env__` as a catch-all
environment, since 2018.3.5 and 2019.2.1:
.. code-block:: yaml
file_roots:
base:
- /srv/salt
__env__:
- /srv/salt
Branches, Environments, and Top Files
=====================================

View file

@ -177,7 +177,7 @@ $MAKE install
############################################################################
echo -n -e "\033]0;Build_Env: libsodium: download\007"
PKGURL="https://download.libsodium.org/libsodium/releases/libsodium-1.0.15.tar.gz"
PKGURL="https://download.libsodium.org/libsodium/releases/old/libsodium-1.0.15.tar.gz"
PKGDIR="libsodium-1.0.15"
download $PKGURL

View file

@ -158,13 +158,20 @@ echo -n -e "\033]0;Build_Pkg: Add Version to .xml\007"
if [ "$PYVER" == "2" ]; then
TITLE="Salt $VERSION"
DESC="Salt $VERSION with Python 2"
SEDSTR="s/@PY2@/_py2/g"
else
TITLE="Salt $VERSION (Python 3)"
DESC="Salt $VERSION with Python 3"
SEDSTR="s/@PY2@//g"
fi
cd $PKGRESOURCES
cp distribution.xml.dist distribution.xml
# Select the appropriate welcome text
# This is only necessary until Sodium, then this can be removed
sed -E -i '' "$SEDSTR" distribution.xml
SEDSTR="s/@TITLE@/$TITLE/g"
sed -E -i '' "$SEDSTR" distribution.xml

View file

@ -16,7 +16,7 @@
mime-type="image/png"
scaling="proportional" />
<!-- Define documents displayed at various steps -->
<welcome file="welcome.rtf"
<welcome file="welcome@PY2@.rtf"
mime-type="text/rtf" />
<license file="license.rtf"
mime-type="text/rtf" />

View file

@ -0,0 +1,32 @@
{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\froman\fcharset0 Times-Roman;\f2\fnil\fcharset0 PTMono-Regular;
}
{\colortbl;\red255\green255\blue255;\red0\green0\blue233;}
\vieww28300\viewh14680\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
\f0\fs24 \cf0 WARNING: Python 2 Support will be discontinued in Sodium. Salt will only ship Python 3 installers starting with the Sodium release.\
\
\pard\pardeftab720\sl280\sa240\partightenfactor0
{\field{\*\fldinst{HYPERLINK "http://saltstack.com/"}}{\fldrslt
\f1 \cf2 \expnd0\expndtw0\kerning0
\ul \ulc2 SaltStack}}
\f1 \expnd0\expndtw0\kerning0
is extremely fast and scalable systems and configuration management software for predictive orchestration, cloud and data center automation, server provisioning, application deployment and more. \
Documentation for Salt is available at {\field{\*\fldinst{HYPERLINK "http://docs.saltstack.com/"}}{\fldrslt \cf2 \ul \ulc2 http://docs.saltstack.com}} \
This package will install Salt on your Mac. Salt installs into
\f2\fs22 /opt/salt
\f1\fs24 .\
Sample configuration files (
\f2\fs22 master.dist
\f1\fs24 and
\f2\fs22 minion.dist
\f1\fs24 ) will be installed to
\f2\fs22 /etc/salt
\f1\fs24 . Create copies of them without the '
\f2\fs22 .dist
\f1\fs24 ' in the filename and edit as you see fit.\
This Salt package uses a custom-built Python. To install additional Python modules for Salt, use the associated 'pip' binary. For example, if you need LDAP support in Salt you will need the 'python-ldap' module. Install it with
\f2\fs22 /opt/salt/bin/pip install python-ldap
\f1\fs24 \
Note that some Python modules need a compiler available. Installing Apple's Xcode Command Line Tools should provide the necessary utilities. Alternatively, {\field{\*\fldinst{HYPERLINK "http://macports.org/"}}{\fldrslt \cf2 \ul \ulc2 MacPorts}}, {\field{\*\fldinst{HYPERLINK "http://finkproject.org/"}}{\fldrslt \cf2 \ul \ulc2 Fink}}, or {\field{\*\fldinst{HYPERLINK "http://brew.sh/"}}{\fldrslt \cf2 \ul \ulc2 Homebrew}} may provide what you need.}

View file

@ -70,6 +70,22 @@ ${StrStrAdv}
!define MUI_ICON "salt.ico"
!define MUI_UNICON "salt.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP "panel.bmp"
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "panel.bmp"
# This entire if block can be removed for the Sodium release... including the !define MUI_WELCOMEPAGE_TEXT
# NSIS will just use the default like it does for Python 3, which should be the same test
!if "${PYTHON_VERSION}" == "2"
!define MUI_WELCOMEPAGE_TEXT "\
WARNING: Python 2 Support will be discontinued in Sodium. Salt will only ship Python 3 \
installers starting with the Sodium release.$\r$\n\
$\r$\n\
Setup will guide you through the installation of ${PRODUCT_NAME} ${PRODUCT_VERSION}.$\r$\n\
$\r$\n\
It is recommended that you close all other applications before starting Setup. This will make it possible to \
update relevant system files without having to reboot your computer.$\r$\n\
$\r$\n\
Click Next to continue."
!endif
# Welcome page
!insertmacro MUI_PAGE_WELCOME

View file

@ -1938,15 +1938,10 @@ PROVIDER_CONFIG_DEFAULTS = {
# <---- Salt Cloud Configuration Defaults ------------------------------------
def _validate_file_roots(file_roots):
def _normalize_roots(file_roots):
'''
If the file_roots option has a key that is None then we will error out,
just replace it with an empty list
Normalize file or pillar roots.
'''
if not isinstance(file_roots, dict):
log.warning('The file_roots parameter is not properly formatted,'
' using defaults')
return {'base': _expand_glob_path([salt.syspaths.BASE_FILE_ROOTS_DIR])}
for saltenv, dirs in six.iteritems(file_roots):
normalized_saltenv = six.text_type(saltenv)
if normalized_saltenv != saltenv:
@ -1958,6 +1953,30 @@ def _validate_file_roots(file_roots):
return file_roots
def _validate_pillar_roots(pillar_roots):
'''
If the pillar_roots option has a key that is None then we will error out,
just replace it with an empty list
'''
if not isinstance(pillar_roots, dict):
log.warning('The pillar_roots parameter is not properly formatted,'
' using defaults')
return {'base': _expand_glob_path([salt.syspaths.BASE_PILLAR_ROOTS_DIR])}
return _normalize_roots(pillar_roots)
def _validate_file_roots(file_roots):
'''
If the file_roots option has a key that is None then we will error out,
just replace it with an empty list
'''
if not isinstance(file_roots, dict):
log.warning('The file_roots parameter is not properly formatted,'
' using defaults')
return {'base': _expand_glob_path([salt.syspaths.BASE_FILE_ROOTS_DIR])}
return _normalize_roots(file_roots)
def _expand_glob_path(file_roots):
'''
Applies shell globbing to a set of directories and returns
@ -3767,7 +3786,7 @@ def apply_minion_config(overrides=None,
# nothing else!
opts['open_mode'] = opts['open_mode'] is True
opts['file_roots'] = _validate_file_roots(opts['file_roots'])
opts['pillar_roots'] = _validate_file_roots(opts['pillar_roots'])
opts['pillar_roots'] = _validate_pillar_roots(opts['pillar_roots'])
# Make sure ext_mods gets set if it is an untrue value
# (here to catch older bad configs)
opts['extension_modules'] = (

View file

@ -51,7 +51,11 @@ def find_file(path, saltenv='base', **kwargs):
if os.path.isabs(path):
return fnd
if saltenv not in __opts__['file_roots']:
return fnd
if '__env__' in __opts__['file_roots']:
log.debug("salt environment '%s' maps to __env__ file_roots directory", saltenv)
saltenv = '__env__'
else:
return fnd
def _add_file_stat(fnd):
'''
@ -220,6 +224,9 @@ def file_hash(load, fnd):
if 'path' not in load or 'saltenv' not in load:
return ''
path = fnd['path']
saltenv = load['saltenv']
if saltenv not in __opts__['file_roots'] and '__env__' in __opts__['file_roots']:
saltenv = '__env__'
ret = {}
# if the file doesn't exist, we can't get a hash
@ -234,7 +241,7 @@ def file_hash(load, fnd):
cache_path = os.path.join(__opts__['cachedir'],
'roots',
'hash',
load['saltenv'],
saltenv,
'{0}.hash.{1}'.format(fnd['rel'],
__opts__['hash_type']))
# if we have a cache, serve that if the mtime hasn't changed
@ -293,8 +300,13 @@ def _file_lists(load, form):
# "env" is not supported; Use "saltenv".
load.pop('env')
if load['saltenv'] not in __opts__['file_roots']:
return []
saltenv = load['saltenv']
if saltenv not in __opts__['file_roots']:
if '__env__' in __opts__['file_roots']:
log.debug("salt environment '%s' maps to __env__ file_roots directory", saltenv)
saltenv = '__env__'
else:
return []
list_cachedir = os.path.join(__opts__['cachedir'], 'file_lists', 'roots')
if not os.path.isdir(list_cachedir):
@ -303,8 +315,8 @@ def _file_lists(load, form):
except os.error:
log.critical('Unable to make cachedir %s', list_cachedir)
return []
list_cache = os.path.join(list_cachedir, '{0}.p'.format(salt.utils.files.safe_filename_leaf(load['saltenv'])))
w_lock = os.path.join(list_cachedir, '.{0}.w'.format(salt.utils.files.safe_filename_leaf(load['saltenv'])))
list_cache = os.path.join(list_cachedir, '{0}.p'.format(salt.utils.files.safe_filename_leaf(saltenv)))
w_lock = os.path.join(list_cachedir, '.{0}.w'.format(salt.utils.files.safe_filename_leaf(saltenv)))
cache_match, refresh_cache, save_cache = \
salt.fileserver.check_file_list_cache(
__opts__, form, list_cache, w_lock
@ -390,7 +402,7 @@ def _file_lists(load, form):
# (i.e. the "path" variable)
ret['links'][rel_path] = link_dest
for path in __opts__['file_roots'][load['saltenv']]:
for path in __opts__['file_roots'][saltenv]:
for root, dirs, files in salt.utils.path.os_walk(
path,
followlinks=__opts__['fileserver_followsymlinks']):
@ -445,7 +457,7 @@ def symlink_list(load):
load.pop('env')
ret = {}
if load['saltenv'] not in __opts__['file_roots']:
if load['saltenv'] not in __opts__['file_roots'] and '__env__' not in __opts__['file_roots']:
return ret
if 'prefix' in load:

View file

@ -22,6 +22,7 @@ import locale
import uuid
from errno import EACCES, EPERM
import datetime
import warnings
__proxyenabled__ = ['*']
__FQDN__ = None
@ -34,7 +35,12 @@ _supported_dists += ('arch', 'mageia', 'meego', 'vmware', 'bluewhite64',
# linux_distribution deprecated in py3.7
try:
from platform import linux_distribution
from platform import linux_distribution as _deprecated_linux_distribution
def linux_distribution(**kwargs):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
return _deprecated_linux_distribution(**kwargs)
except ImportError:
from distro import linux_distribution
@ -1389,7 +1395,9 @@ _OS_FAMILY_MAP = {
'KDE neon': 'Debian',
'Void': 'Void',
'IDMS': 'Debian',
'AIX': 'AIX'
'Funtoo': 'Gentoo',
'AIX': 'AIX',
'TurnKey': 'Debian',
}
# Matches any possible format:

View file

@ -280,7 +280,7 @@ def _run(cmd,
'''
if 'pillar' in kwargs and not pillar_override:
pillar_override = kwargs['pillar']
if _is_valid_shell(shell) is False:
if output_loglevel != 'quiet' and _is_valid_shell(shell) is False:
log.warning(
'Attempt to run a shell command with what may be an invalid shell! '
'Check to ensure that the shell <%s> is valid for this user.',

View file

@ -1266,6 +1266,7 @@ def user_exists(user,
'''
run_verify = False
server_version = version(**connection_args)
compare_version = '10.2.0' if 'MariaDB' in server_version else '8.0.11'
dbc = _connect(**connection_args)
# Did we fail to connect with the user we are checking
# Its password might have previously change with the same command/state
@ -1297,7 +1298,7 @@ def user_exists(user,
else:
qry += ' AND ' + password_column + ' = \'\''
elif password:
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
run_verify = True
else:
_password = password
@ -1404,6 +1405,7 @@ def user_create(user,
salt '*' mysql.user_create 'username' 'hostname' allow_passwordless=True
'''
server_version = version(**connection_args)
compare_version = '10.2.0' if 'MariaDB' in server_version else '8.0.11'
if user_exists(user, host, **connection_args):
log.info('User \'%s\'@\'%s\' already exists', user, host)
return False
@ -1424,7 +1426,7 @@ def user_create(user,
qry += ' IDENTIFIED BY %(password)s'
args['password'] = six.text_type(password)
elif password_hash is not None:
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
qry += ' IDENTIFIED BY %(password)s'
else:
qry += ' IDENTIFIED BY PASSWORD %(password)s'
@ -1508,9 +1510,10 @@ def user_chpass(user,
salt '*' mysql.user_chpass frank localhost allow_passwordless=True
'''
server_version = version(**connection_args)
compare_version = '10.2.0' if 'MariaDB' in server_version else '8.0.11'
args = {}
if password is not None:
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
password_sql = '%(password)s'
else:
password_sql = 'PASSWORD(%(password)s)'
@ -1533,28 +1536,23 @@ def user_chpass(user,
password_column = __password_column(**connection_args)
cur = dbc.cursor()
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
qry = ("ALTER USER '" + user + "'@'" + host + "'"
" IDENTIFIED BY '" + password + "';")
args = {}
args['user'] = user
args['host'] = host
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
qry = "ALTER USER %(user)s@%(host)s IDENTIFIED BY %(password)s;"
else:
qry = ('UPDATE mysql.user SET ' + password_column + '='
+ password_sql +
qry = ('UPDATE mysql.user SET ' + password_column + '=' + password_sql +
' WHERE User=%(user)s AND Host = %(host)s;')
args['user'] = user
args['host'] = host
if salt.utils.data.is_true(allow_passwordless) and \
salt.utils.data.is_true(unix_socket):
if host == 'localhost':
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
qry = ("ALTER USER '" + user + "'@'" + host + "'"
" IDENTIFIED BY '" + password + "';")
args = {}
args['unix_socket'] = 'auth_socket'
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
qry = "ALTER USER %(user)s@%(host)s IDENTIFIED WITH %(unix_socket)s AS %(user)s;"
else:
qry = ('UPDATE mysql.user SET ' + password_column + '='
+ password_sql + ', plugin=%(unix_socket)s' +
' WHERE User=%(user)s AND Host = %(host)s;')
args['unix_socket'] = 'unix_socket'
else:
log.error('Auth via unix_socket can be set only for host=localhost')
try:
@ -1565,7 +1563,7 @@ def user_chpass(user,
log.error(err)
return False
if salt.utils.versions.version_cmp(server_version, '8.0.11') >= 0:
if salt.utils.versions.version_cmp(server_version, compare_version) >= 0:
_execute(cur, 'FLUSH PRIVILEGES;')
log.info(
'Password for user \'%s\'@\'%s\' has been %s',
@ -1869,7 +1867,8 @@ def grant_exists(grant,
server_version = version(**connection_args)
if 'ALL' in grant:
if salt.utils.versions.version_cmp(server_version, '8.0') >= 0:
if salt.utils.versions.version_cmp(server_version, '8.0') >= 0 and \
'MariaDB' not in server_version:
grant = ','.join([i for i in __all_privileges__])
else:
grant = 'ALL PRIVILEGES'

View file

@ -1620,7 +1620,7 @@ def set_authentication_profile(profile=None, deploy=False):
'''
if not profile:
CommandExecutionError("Profile name option must not be none.")
raise CommandExecutionError("Profile name option must not be none.")
ret = {}
@ -1657,7 +1657,7 @@ def set_hostname(hostname=None, deploy=False):
'''
if not hostname:
CommandExecutionError("Hostname option must not be none.")
raise CommandExecutionError("Hostname option must not be none.")
ret = {}
@ -1697,7 +1697,7 @@ def set_management_icmp(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1737,7 +1737,7 @@ def set_management_http(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1777,7 +1777,7 @@ def set_management_https(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1817,7 +1817,7 @@ def set_management_ocsp(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1857,7 +1857,7 @@ def set_management_snmp(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1897,7 +1897,7 @@ def set_management_ssh(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -1937,7 +1937,7 @@ def set_management_telnet(enabled=True, deploy=False):
elif enabled is False:
value = "yes"
else:
CommandExecutionError("Invalid option provided for service enabled option.")
raise CommandExecutionError("Invalid option provided for service enabled option.")
ret = {}
@ -2130,7 +2130,7 @@ def set_permitted_ip(address=None, deploy=False):
'''
if not address:
CommandExecutionError("Address option must not be empty.")
raise CommandExecutionError("Address option must not be empty.")
ret = {}
@ -2166,7 +2166,7 @@ def set_timezone(tz=None, deploy=False):
'''
if not tz:
CommandExecutionError("Timezone name option must not be none.")
raise CommandExecutionError("Timezone name option must not be none.")
ret = {}

View file

@ -19,7 +19,6 @@ import re
import subprocess
# Import salt libs
from salt.ext import six
import salt.utils.decorators.path
import salt.utils.data
import salt.utils.files
@ -44,9 +43,8 @@ if six.PY3:
def __virtual__():
# TODO: This could work on windows with some love
if salt.utils.platform.is_windows():
return (False, 'The module cannot be loaded on windows.')
if not salt.utils.path.which('ssh'):
return False, 'The module requires the ssh binary.'
return True
@ -753,9 +751,10 @@ def set_auth_key(
if not os.path.isdir(os.path.dirname(fconfig)):
dpath = os.path.dirname(fconfig)
os.makedirs(dpath)
if os.geteuid() == 0:
os.chown(dpath, uinfo['uid'], uinfo['gid'])
os.chmod(dpath, 448)
if not salt.utils.platform.is_windows():
if os.geteuid() == 0:
os.chown(dpath, uinfo['uid'], uinfo['gid'])
os.chmod(dpath, 448)
# If SELINUX is available run a restorecon on the file
rcon = salt.utils.path.which('restorecon')
if rcon:
@ -784,9 +783,10 @@ def set_auth_key(
raise CommandExecutionError(msg.format(exc))
if new_file:
if os.geteuid() == 0:
os.chown(fconfig, uinfo['uid'], uinfo['gid'])
os.chmod(fconfig, 384)
if not salt.utils.platform.is_windows():
if os.geteuid() == 0:
os.chown(fconfig, uinfo['uid'], uinfo['gid'])
os.chmod(fconfig, 384)
# If SELINUX is available run a restorecon on the file
rcon = salt.utils.path.which('restorecon')
if rcon:
@ -1104,10 +1104,11 @@ def rm_known_host(user=None, hostname=None, config=None, port=None):
ssh_hostname = _hostname_and_port_to_ssh_hostname(hostname, port)
cmd = ['ssh-keygen', '-R', ssh_hostname, '-f', full]
cmd_result = __salt__['cmd.run'](cmd, python_shell=False)
# ssh-keygen creates a new file, thus a chown is required.
if os.geteuid() == 0 and user:
uinfo = __salt__['user.info'](user)
os.chown(full, uinfo['uid'], uinfo['gid'])
if not salt.utils.platform.is_windows():
# ssh-keygen creates a new file, thus a chown is required.
if os.geteuid() == 0 and user:
uinfo = __salt__['user.info'](user)
os.chown(full, uinfo['uid'], uinfo['gid'])
return {'status': 'removed', 'comment': cmd_result}
@ -1317,12 +1318,13 @@ def set_known_host(user=None,
"Couldn't append to known hosts file: '{0}'".format(exception)
)
if os.geteuid() == 0 and user:
os.chown(full, uinfo['uid'], uinfo['gid'])
if origmode:
os.chmod(full, origmode)
else:
os.chmod(full, 0o600)
if not salt.utils.platform.is_windows():
if os.geteuid() == 0 and user:
os.chown(full, uinfo['uid'], uinfo['gid'])
if origmode:
os.chmod(full, origmode)
else:
os.chmod(full, 0o600)
if key and hash_known_hosts:
cmd_result = __salt__['ssh.hash_known_hosts'](user=user, config=full)
@ -1446,10 +1448,11 @@ def hash_known_hosts(user=None, config=None):
cmd = ['ssh-keygen', '-H', '-f', full]
cmd_result = __salt__['cmd.run'](cmd, python_shell=False)
os.chmod(full, origmode)
# ssh-keygen creates a new file, thus a chown is required.
if os.geteuid() == 0 and user:
uinfo = __salt__['user.info'](user)
os.chown(full, uinfo['uid'], uinfo['gid'])
if not salt.utils.platform.is_windows():
# ssh-keygen creates a new file, thus a chown is required.
if os.geteuid() == 0 and user:
uinfo = __salt__['user.info'](user)
os.chown(full, uinfo['uid'], uinfo['gid'])
return {'status': 'updated', 'comment': cmd_result}

View file

@ -739,7 +739,7 @@ def set_lcm_config(config_mode=None,
cmd += ' RefreshFrequencyMins = {0};'.format(refresh_freq)
if reboot_if_needed is not None:
if not isinstance(reboot_if_needed, bool):
SaltInvocationError('reboot_if_needed must be a boolean value')
raise SaltInvocationError('reboot_if_needed must be a boolean value')
if reboot_if_needed:
reboot_if_needed = '$true'
else:

View file

@ -5083,8 +5083,8 @@ def _findOptionValueAdvAudit(option):
field_names = _get_audit_defaults('fieldnames')
# If the file doesn't exist anywhere, create it with default
# fieldnames
__salt__['file.touch'](f_audit)
__salt__['file.append'](f_audit, ','.join(field_names))
__salt__['file.mkdir'](os.path.dirname(f_audit))
__salt__['file.write'](f_audit, ','.join(field_names))
audit_settings = {}
with salt.utils.files.fopen(f_audit, mode='r') as csv_file:
@ -5187,6 +5187,7 @@ def _set_audit_file_data(option, value):
# Copy the temporary csv file over the existing audit.csv in both
# locations if a value was written
__salt__['file.copy'](f_temp.name, f_audit, remove_existing=True)
__salt__['file.mkdir'](os.path.dirname(f_audit_gpo))
__salt__['file.copy'](f_temp.name, f_audit_gpo, remove_existing=True)
finally:
f_temp.close()

View file

@ -205,17 +205,22 @@ def get_zone():
Returns:
str: Timezone in unix format
Raises:
CommandExecutionError: If timezone could not be gathered
CLI Example:
.. code-block:: bash
salt '*' timezone.get_zone
'''
win_zone = __utils__['reg.read_value'](
hive='HKLM',
key='SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation',
vname='TimeZoneKeyName')['vdata']
return mapper.get_unix(win_zone.lower(), 'Unknown')
cmd = ['tzutil', '/g']
res = __salt__['cmd.run_all'](cmd, python_shell=False)
if res['retcode'] or not res['stdout']:
raise CommandExecutionError('tzutil encountered an error getting '
'timezone',
info=res)
return mapper.get_unix(res['stdout'].lower(), 'Unknown')
def get_offset():

View file

@ -2,26 +2,36 @@
'''
Retrieve EC2 instance data for minions for ec2_tags and ec2_tags_list
The minion id must be the AWS instance-id or value in 'tag_match_key'.
For example set 'tag_match_key' to 'Name', to have the minion-id matched against the
tag 'Name'. The tag contents must be unique. The value of tag_match_value can
be 'uqdn' or 'asis'. if 'uqdn' strips any domain before comparison.
The minion id must be the AWS instance-id or value in ``tag_match_key``. For
example set ``tag_match_key`` to ``Name`` to have the minion-id matched against
the tag 'Name'. The tag contents must be unique. The value of
``tag_match_value`` can be 'uqdn' or 'asis'. if 'uqdn', then the domain will be
stripped before comparison.
The option use_grain can be set to True. This allows the use of an
instance-id grain instead of the minion-id. Since this is a potential
security risk, the configuration can be further expanded to include
a list of minions that are trusted to only allow the alternate id
of the instances to specific hosts. There is no glob matching at
this time.
Additionally, the ``use_grain`` option can be set to ``True``. This allows the
use of an instance-id grain instead of the minion-id. Since this is a potential
security risk, the configuration can be further expanded to include a list of
minions that are trusted to only allow the alternate id of the instances to
specific hosts. There is no glob matching at this time.
The optional 'tag_list_key' indicates which keys should be added to
'ec2_tags_list' and be split by tag_list_sep (default `;`). If a tag key is
included in 'tag_list_key' it is removed from ec2_tags. If a tag does not
exist it is still included as an empty list.
.. note::
If you are using ``use_grain: True`` in the configuration for this external
pillar module, the minion must have :conf_minion:`metadata_server_grains`
enabled in the minion config file (see also :py:mod:`here
<salt.grains.metadata>`).
It is important to also note that enabling the ``use_grain`` option allows
the minion to manipulate the pillar data returned, as described above.
The optional ``tag_list_key`` indicates which keys should be added to
``ec2_tags_list`` and be split by ``tag_list_sep`` (by default ``;``). If a tag
key is included in ``tag_list_key`` it is removed from ec2_tags. If a tag does
not exist it is still included as an empty list.
Note: restart the salt-master for changes to take effect.
..note::
As with any master configuration change, restart the salt-master daemon for
changes to take effect.
.. code-block:: yaml
@ -38,11 +48,10 @@ exist it is still included as an empty list.
- trusted-minion-2
- trusted-minion-3
This is a very simple pillar that simply retrieves the instance data
from AWS. Currently the only portion implemented are EC2 tags, which
returns a list of key/value pairs for all of the EC2 tags assigned to
the instance.
This is a very simple pillar configuration that simply retrieves the instance
data from AWS. Currently the only portion implemented are EC2 tags, which
returns a list of key/value pairs for all of the EC2 tags assigned to the
instance.
'''
# Import python libs

View file

@ -3767,12 +3767,14 @@ class BaseHighState(object):
statefiles = []
for saltenv, states in six.iteritems(matches):
for sls_match in states:
try:
if saltenv in self.avail:
statefiles = fnmatch.filter(self.avail[saltenv], sls_match)
except KeyError:
all_errors.extend(
['No matching salt environment for environment '
'\'{0}\' found'.format(saltenv)]
elif '__env__' in self.avail:
statefiles = fnmatch.filter(self.avail['__env__'], sls_match)
else:
all_errors.append(
'No matching salt environment for environment '
'\'{0}\' found'.format(saltenv)
)
# if we did not found any sls in the fileserver listing, this
# may be because the sls was generated or added later, we can

View file

@ -46,6 +46,7 @@ try:
except ImportError:
HAS_DNSPYTHON = False
HAS_DIG = salt.utils.path.which('dig') is not None
DIG_OPTIONS = '+search +fail +noall +answer +nocl +nottl'
HAS_DRILL = salt.utils.path.which('drill') is not None
HAS_HOST = salt.utils.path.which('host') is not None
HAS_NSLOOKUP = salt.utils.path.which('nslookup') is not None
@ -230,7 +231,7 @@ def _lookup_dig(name, rdtype, timeout=None, servers=None, secure=None):
:param servers: [] of servers to use
:return: [] of records or False if error
'''
cmd = 'dig +search +fail +noall +answer +noclass +nottl -t {0} '.format(rdtype)
cmd = 'dig {0} -t {1} '.format(DIG_OPTIONS, rdtype)
if servers:
cmd += ''.join(['@{0} '.format(srv) for srv in servers])
if timeout is not None:

View file

@ -11,8 +11,8 @@
from __future__ import absolute_import, unicode_literals, print_function
# Import salt libs
from salt.ext import six
import salt.utils.files
import salt.utils.stringutils
from salt.exceptions import SaltException
@ -85,14 +85,11 @@ class BufferedReader(object):
multiplier = 1
self.__buffered = self.__buffered[self.__chunk_size:]
if six.PY3:
# Data is a byte object in Python 3
# Decode it in order to append to self.__buffered str later
data = self.__file.read(self.__chunk_size * multiplier).decode(
__salt_system_encoding__
)
else:
data = self.__file.read(self.__chunk_size * multiplier)
data = self.__file.read(self.__chunk_size * multiplier)
# Data is a byte object in Python 3
# Decode it in order to append to self.__buffered str later
# Use the salt util in case it's already a string (Windows)
data = salt.utils.stringutils.to_str(data)
if not data:
self.__file.close()

View file

@ -3006,7 +3006,11 @@ class GitPillar(GitBase):
elif repo.env:
env = repo.env
else:
env = 'base' if repo.branch == repo.base else repo.get_checkout_target()
if repo.branch == repo.base:
env = 'base'
else:
tgt = repo.get_checkout_target()
env = 'base' if tgt == repo.base else tgt
if repo._mountpoint:
if self.link_mountpoint(repo):
self.pillar_dirs[repo.linkdir] = env

View file

@ -8,10 +8,16 @@ from __future__ import absolute_import, print_function, unicode_literals
import re
import sys
import platform
import warnings
# linux_distribution deprecated in py3.7
try:
from platform import linux_distribution
from platform import linux_distribution as _deprecated_linux_distribution
def linux_distribution(**kwargs):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
return _deprecated_linux_distribution(**kwargs)
except ImportError:
from distro import linux_distribution

View file

@ -183,7 +183,7 @@ class TestDaemon(object):
'''
Set up the master and minion daemons, and run related cases
'''
MINIONS_CONNECT_TIMEOUT = MINIONS_SYNC_TIMEOUT = 120
MINIONS_CONNECT_TIMEOUT = MINIONS_SYNC_TIMEOUT = 300
def __init__(self, parser):
self.parser = parser
@ -219,6 +219,8 @@ class TestDaemon(object):
if getattr(self.parser.options, 'ssh', False):
self.prep_ssh()
self.wait_for_minions(time.time(), self.MINIONS_CONNECT_TIMEOUT)
if self.parser.options.sysinfo:
try:
print_header(
@ -1185,84 +1187,6 @@ class TestDaemon(object):
k for (k, v) in six.iteritems(running) if v and v[0]['jid'] == jid
]
def wait_for_minion_connections(self, targets, timeout):
salt.utils.process.appendproctitle('WaitForMinionConnections')
sys.stdout.write(
' {LIGHT_BLUE}*{ENDC} Waiting at most {0} for minions({1}) to '
'connect back\n'.format(
(timeout > 60 and
timedelta(seconds=timeout) or
'{0} secs'.format(timeout)),
', '.join(targets),
**self.colors
)
)
sys.stdout.flush()
expected_connections = set(targets)
now = datetime.now()
expire = now + timedelta(seconds=timeout)
while now <= expire:
sys.stdout.write(
'\r{0}\r'.format(
' ' * getattr(self.parser.options, 'output_columns', PNUM)
)
)
sys.stdout.write(
' * {LIGHT_YELLOW}[Quit in {0}]{ENDC} Waiting for {1}'.format(
'{0}'.format(expire - now).rsplit('.', 1)[0],
', '.join(expected_connections),
**self.colors
)
)
sys.stdout.flush()
try:
responses = self.client.cmd(
list(expected_connections), 'test.ping', tgt_type='list',
)
# we'll get this exception if the master process hasn't finished starting yet
except SaltClientError:
time.sleep(0.1)
now = datetime.now()
continue
for target in responses:
if target not in expected_connections:
# Someone(minion) else "listening"?
continue
expected_connections.remove(target)
sys.stdout.write(
'\r{0}\r'.format(
' ' * getattr(self.parser.options, 'output_columns',
PNUM)
)
)
sys.stdout.write(
' {LIGHT_GREEN}*{ENDC} {0} connected.\n'.format(
target, **self.colors
)
)
sys.stdout.flush()
if not expected_connections:
return
time.sleep(1)
now = datetime.now()
else: # pylint: disable=W0120
print(
'\n {LIGHT_RED}*{ENDC} WARNING: Minions failed to connect '
'back. Tests requiring them WILL fail'.format(**self.colors)
)
try:
print_header(
'=', sep='=', inline=True,
width=getattr(self.parser.options, 'output_columns', PNUM)
)
except TypeError:
print_header('=', sep='=', inline=True)
raise SystemExit()
def sync_minion_modules_(self, modules_kind, targets, timeout=None):
if not timeout:
timeout = 120
@ -1339,3 +1263,20 @@ class TestDaemon(object):
def sync_minion_grains(self, targets, timeout=None):
salt.utils.process.appendproctitle('SyncMinionGrains')
self.sync_minion_modules_('grains', targets, timeout=timeout)
def wait_for_minions(self, start, timeout, sleep=5):
'''
Ensure all minions and masters (including sub-masters) are connected.
'''
while True:
try:
ret = self.client.run_job('*', 'test.ping')
except salt.exceptions.SaltClientError:
ret = None
if ret and 'minions' not in ret:
continue
if ret and sorted(ret['minions']) == ['minion', 'sub_minion']:
break
if time.time() - start >= timeout:
raise RuntimeError("Ping Minions Failed")
time.sleep(sleep)

View file

@ -1,5 +0,0 @@
# -*- coding: utf-8 -*-
def test(grains):
return {'custom_grain_test': 'itworked' if 'os' in grains else 'itdidntwork'}

View file

@ -15,6 +15,7 @@ from tests.support.helpers import skip_if_binaries_missing
# Import salt libs
import salt.utils.files
import salt.utils.platform
# Import 3rd-party libs
from tornado.httpclient import HTTPClient
@ -70,7 +71,10 @@ class SSHModuleTest(ModuleCase):
shutil.copyfile(
os.path.join(FILES, 'ssh', 'authorized_keys'),
AUTHORIZED_KEYS)
ret = self.run_function('ssh.auth_keys', ['root', AUTHORIZED_KEYS])
user = 'root'
if salt.utils.platform.is_windows():
user = 'Administrator'
ret = self.run_function('ssh.auth_keys', [user, AUTHORIZED_KEYS])
self.assertEqual(len(list(ret.items())), 1) # exactly one key is found
key_data = list(ret.items())[0][1]
try:

View file

@ -22,8 +22,12 @@ class WinDNSTest(ModuleCase):
'''
Test add and removing a dns server
'''
# Get a list of interfaces on the system
interfaces = self.run_function('network.interfaces_names')
skipIf(interfaces.count == 0, 'This test requires a network interface')
interface = interfaces[0]
dns = '8.8.8.8'
interface = 'Ethernet'
# add dns server
self.assertTrue(self.run_function('win_dns_client.add_dns', [dns, interface], index=42))

View file

@ -276,9 +276,9 @@ class ShellTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
if 'env' not in popen_kwargs:
popen_kwargs['env'] = os.environ.copy()
if sys.version_info[0] < 3:
popen_kwargs['env'][b'PYTHONPATH'] = os.getcwd().encode()
popen_kwargs['env'][b'PYTHONPATH'] = CODE_DIR.encode()
else:
popen_kwargs['env']['PYTHONPATH'] = os.getcwd()
popen_kwargs['env']['PYTHONPATH'] = CODE_DIR
else:
cmd = 'PYTHONPATH='
python_path = os.environ.get('PYTHONPATH', None)

View file

@ -1 +1,32 @@
# -*- coding: utf-8 -*-
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
# Import Salt Testing Libs
from tests.support.unit import TestCase, skipIf
import tests.support.mock as mock
import salt.config
import salt.syspaths
class ConfigTest(TestCase):
def test_validate_bad_pillar_roots(self):
expected = salt.config._expand_glob_path(
[salt.syspaths.BASE_PILLAR_ROOTS_DIR]
)
with mock.patch('salt.config._normalize_roots') as mk:
ret = salt.config._validate_pillar_roots(None)
assert not mk.called
assert ret == {'base': expected}
def test_validate_bad_file_roots(self):
expected = salt.config._expand_glob_path(
[salt.syspaths.BASE_FILE_ROOTS_DIR]
)
with mock.patch('salt.config._normalize_roots') as mk:
ret = salt.config._validate_file_roots(None)
assert not mk.called
assert ret == {'base': expected}

View file

@ -179,3 +179,20 @@ class RootsTest(TestCase, AdaptedConfigurationTestCaseMixin, LoaderModuleMockMix
finally:
if self.test_symlink_list_file_roots:
self.opts['file_roots'] = orig_file_roots
def test_dynamic_file_roots(self):
dyn_root_dir = tempfile.mkdtemp(dir=TMP)
top_sls = os.path.join(dyn_root_dir, 'top.sls')
with salt.utils.files.fopen(top_sls, 'w') as fp_:
fp_.write("{{saltenv}}:\n '*':\n - dynamo\n")
dynamo_sls = os.path.join(dyn_root_dir, 'dynamo.sls')
with salt.utils.files.fopen(dynamo_sls, 'w') as fp_:
fp_.write("foo:\n test.nop\n")
opts = {'file_roots': copy.copy(self.opts['file_roots'])}
opts['file_roots']['__env__'] = [dyn_root_dir]
with patch.dict(roots.__opts__, opts):
ret1 = roots.find_file('dynamo.sls', 'dyn')
ret2 = roots.file_list({'saltenv': 'dyn'})
self.assertEqual('dynamo.sls', ret1['rel'])
self.assertIn('top.sls', ret2)
self.assertIn('dynamo.sls', ret2)

View file

@ -99,6 +99,21 @@ class MySQLTestCase(TestCase, LoaderModuleMockMixin):
password='BLUECOW'
)
with patch.object(mysql, 'version', return_value='10.1.38-MariaDB'):
self._test_call(mysql.user_exists,
{'sql': ('SELECT User,Host FROM mysql.user WHERE '
'User = %(user)s AND Host = %(host)s AND '
'Password = PASSWORD(%(password)s)'),
'sql_args': {'host': 'localhost',
'password': 'BLUECOW',
'user': 'mytestuser'
}
},
user='mytestuser',
host='localhost',
password='BLUECOW'
)
with patch.object(mysql, 'version', return_value='8.0.11'):
self._test_call(mysql.user_exists,
{'sql': ('SELECT User,Host FROM mysql.user WHERE '
@ -125,6 +140,19 @@ class MySQLTestCase(TestCase, LoaderModuleMockMixin):
password='BLUECOW'
)
with patch.object(mysql, 'version', return_value='10.2.21-MariaDB'):
self._test_call(mysql.user_exists,
{'sql': ('SELECT User,Host FROM mysql.user WHERE '
'User = %(user)s AND Host = %(host)s'),
'sql_args': {'host': 'localhost',
'user': 'mytestuser'
}
},
user='mytestuser',
host='localhost',
password='BLUECOW'
)
# test_user_create_when_user_exists(self):
# ensure we don't try to create a user when one already exists
# mock the version of MySQL
@ -187,7 +215,11 @@ class MySQLTestCase(TestCase, LoaderModuleMockMixin):
mysql.user_chpass('testuser', password='BLUECOW')
calls = (
call().cursor().execute(
"ALTER USER 'testuser'@'localhost' IDENTIFIED BY 'BLUECOW';"
"ALTER USER %(user)s@%(host)s IDENTIFIED BY %(password)s;",
{'password': 'BLUECOW',
'user': 'testuser',
'host': 'localhost',
}
),
call().cursor().execute('FLUSH PRIVILEGES;'),
)

View file

@ -3,18 +3,15 @@
:codeauthor: Jayesh Kariya <jayeshk@saltstack.com>
'''
# Import Python Libs
from __future__ import absolute_import, unicode_literals, print_function
# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.unit import TestCase, skipIf
from tests.support.mock import (
MagicMock,
patch
)
from __future__ import absolute_import, print_function, unicode_literals
# Import Salt Libs
import salt.modules.win_timezone as win_timezone
from salt.exceptions import CommandExecutionError
# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase, skipIf
@skipIf(not win_timezone.HAS_PYTZ, 'This test requires pytz')
@ -25,20 +22,36 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {win_timezone: {}}
# 'get_zone' function tests: 1
# 'get_zone' function tests: 3
def test_get_zone(self):
'''
Test if it get current timezone (i.e. Asia/Calcutta)
'''
mock_read = MagicMock(side_effect=[{'vdata': 'India Standard Time'},
{'vdata': 'Indian Standard Time'}])
mock_read_ok = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
with patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read_ok}):
self.assertEqual(win_timezone.get_zone(), 'Asia/Calcutta')
mock_read_error = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'Indian Standard Time'})
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read_error}):
self.assertEqual(win_timezone.get_zone(), 'Unknown')
mock_read_fatal = MagicMock(return_value={'pid': 78,
'retcode': 1,
'stderr': '',
'stdout': ''})
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read_fatal}):
self.assertRaises(CommandExecutionError, win_timezone.get_zone)
# 'get_offset' function tests: 1
def test_get_offset(self):
@ -49,10 +62,12 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
# New Delhi\nIndia Standard Time')
# mock_cmd = MagicMock(side_effect=['India Standard Time', time])
# with patch.dict(win_timezone.__salt__, {'cmd.run': mock_cmd}):
mock_read = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
mock_read = MagicMock(return_value={'vdata': 'India Standard Time'})
with patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read}):
self.assertEqual(win_timezone.get_offset(), '+0530')
# 'get_zonecode' function tests: 1
@ -61,9 +76,12 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
'''
Test if it get current timezone (i.e. PST, MDT, etc)
'''
mock_read = MagicMock(return_value={'vdata': 'India Standard Time'})
mock_read = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
with patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read}):
self.assertEqual(win_timezone.get_zonecode(), 'IST')
# 'set_zone' function tests: 1
@ -72,14 +90,17 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
'''
Test if it unlinks, then symlinks /etc/localtime to the set timezone.
'''
mock_cmd = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': ''})
mock_read = MagicMock(return_value={'vdata': 'India Standard Time'})
mock_write = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': ''})
mock_read = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_cmd}), \
patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_write}), \
patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read}):
self.assertTrue(win_timezone.set_zone('Asia/Calcutta'))
@ -91,9 +112,12 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
the one set in /etc/localtime. Returns True if they match,
and False if not. Mostly useful for running state checks.
'''
mock_read = MagicMock(return_value={'vdata': 'India Standard Time'})
mock_read = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
with patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read}):
self.assertTrue(win_timezone.zone_compare('Asia/Calcutta'))
# 'get_hwclock' function tests: 1

View file

@ -775,10 +775,15 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
with patch.object(os.path, 'exists', mock_t):
with patch.dict(filestate.__opts__, {'test': True}):
ret.update({'comment': comt})
self.assertDictEqual(filestate.managed
(name, user=user,
group=group,
mode=400), ret)
if salt.utils.is_windows():
self.assertDictEqual(filestate.managed
(name, user=user,
group=group), ret)
else:
self.assertDictEqual(filestate.managed
(name, user=user,
group=group,
mode=400), ret)
# 'directory' function tests: 1

View file

@ -25,8 +25,10 @@ if sys.version_info >= (3,):
else:
BUILTINS_OPEN = '__builtin__.open'
zyppnotify = imp.load_source('zyppnotify', os.path.sep.join(os.path.dirname(__file__).split(
os.path.sep)[:-2] + ['scripts', 'suse', 'zypper', 'plugins', 'commit', 'zyppnotify']))
ZYPPNOTIFY_FILE = os.path.sep.join(
os.path.dirname(__file__).split(os.path.sep)[:-2] +
['scripts', 'suse', 'zypper', 'plugins', 'commit', 'zyppnotify']
)
@skipIf(NO_MOCK, NO_MOCK_REASON)
@ -40,6 +42,7 @@ class ZyppPluginsTestCase(TestCase):
Returns:
'''
zyppnotify = imp.load_source('zyppnotify', ZYPPNOTIFY_FILE)
drift = zyppnotify.DriftDetector()
drift._get_mtime = MagicMock(return_value=123)
drift._get_checksum = MagicMock(return_value='deadbeef')

View file

@ -15,6 +15,7 @@ import salt.utils.dns
from salt.utils.dns import _to_port, _tree, _weighted_order, _data2rec, _data2rec_group
from salt.utils.dns import _lookup_gai, _lookup_dig, _lookup_drill, _lookup_host, _lookup_nslookup
from salt.utils.dns import lookup
import salt.modules.cmdmod
# Testing
from tests.support.unit import skipIf, TestCase
@ -318,6 +319,12 @@ class DNSlookupsCase(TestCase):
lookup(rec, rec_t, method='nslookup', servers='8.8.8.8'), test_res,
)
@skipIf(not salt.utils.dns.HAS_DIG, 'dig is not available')
def test_dig_options(self):
cmd = 'dig {0} -v'.format(salt.utils.dns.DIG_OPTIONS)
cmd = salt.modules.cmdmod.retcode(cmd, python_shell=False, output_loglevel='quiet')
self.assertEqual(cmd, 0)
def test_dig(self):
wrong_type = {'retcode': 0, 'stderr': ';; Warning, ignoring invalid type ABC'}