mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2018.3' into solarisips_fixes
This commit is contained in:
commit
e8e91e3b27
52 changed files with 6346 additions and 263 deletions
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
=====================================
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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" />
|
||||
|
|
32
pkg/osx/pkg-resources/welcome_py2.rtf
Normal file
32
pkg/osx/pkg-resources/welcome_py2.rtf
Normal 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.}
|
|
@ -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
|
||||
|
|
|
@ -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'] = (
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.',
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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 = {}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
def test(grains):
|
||||
return {'custom_grain_test': 'itworked' if 'os' in grains else 'itdidntwork'}
|
|
@ -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:
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;'),
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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'}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue