Merge pull request #49282 from rallytime/merge-2018.3

[2018.3] Merge forward from 2017.7 to 2018.3
This commit is contained in:
Nicole Thomas 2018-08-24 12:45:49 -04:00 committed by GitHub
commit 914bb09667
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 369 additions and 242 deletions

View file

@ -125,7 +125,7 @@
# The master can take a while to start up when lspci and/or dmidecode is used
# to populate the grains for the master. Enable if you want to see GPU hardware
# data for your master.
# enable_gpu_grains: False
# enable_gpu_grains: True
# The master maintains a job cache. While this is a great addition, it can be
# a burden on the master for larger deployments (over 5000 minions).
@ -574,12 +574,6 @@
#
#master_tops: {}
# The external_nodes option allows Salt to gather data that would normally be
# placed in a top file. The external_nodes option is the executable that will
# return the ENC data. Remember that Salt will look for external nodes AND top
# files and combine the results if both are enabled!
#external_nodes: None
# The renderer to use on the minions to render the state data
#renderer: yaml_jinja

View file

@ -127,7 +127,7 @@ syndic_user: salt
# The master can take a while to start up when lspci and/or dmidecode is used
# to populate the grains for the master. Enable if you want to see GPU hardware
# data for your master.
# enable_gpu_grains: False
# enable_gpu_grains: True
# The master maintains a job cache. While this is a great addition, it can be
# a burden on the master for larger deployments (over 5000 minions).
@ -536,12 +536,6 @@ syndic_user: salt
#
#master_tops: {}
# The external_nodes option allows Salt to gather data that would normally be
# placed in a top file. The external_nodes option is the executable that will
# return the ENC data. Remember that Salt will look for external nodes AND top
# files and combine the results if both are enabled!
#external_nodes: None
# The renderer to use on the minions to render the state data
#renderer: yaml_jinja

View file

@ -5256,7 +5256,7 @@ sock_dir: /var/run/salt/master
.UNINDENT
.SS \fBenable_gpu_grains\fP
.sp
Default: \fBTrue\fP
Default: \fBFalse\fP
.sp
Enable GPU hardware data for your master. Be aware that the master can
take a while to start up when lspci and/or dmidecode is used to populate the
@ -6993,25 +6993,6 @@ master_tops:
.fi
.UNINDENT
.UNINDENT
.SS \fBexternal_nodes\fP
.sp
Default: None
.sp
The external_nodes option allows Salt to gather data that would normally be
placed in a top file from and external node controller. The external_nodes
option is the executable that will return the ENC data. Remember that Salt
will look for external nodes AND top files and combine the results if both
are enabled and available!
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
external_nodes: cobbler\-ext\-nodes
.ft P
.fi
.UNINDENT
.UNINDENT
.SS \fBrenderer\fP
.sp
Default: \fByaml_jinja\fP
@ -15229,7 +15210,7 @@ and \fBmine_functions\fP\&.
# The master can take a while to start up when lspci and/or dmidecode is used
# to populate the grains for the master. Enable if you want to see GPU hardware
# data for your master.
# enable_gpu_grains: False
# enable_gpu_grains: True
# The master maintains a job cache. While this is a great addition, it can be
# a burden on the master for larger deployments (over 5000 minions).
@ -15678,12 +15659,6 @@ and \fBmine_functions\fP\&.
#
#master_tops: {}
# The external_nodes option allows Salt to gather data that would normally be
# placed in a top file. The external_nodes option is the executable that will
# return the ENC data. Remember that Salt will look for external nodes AND top
# files and combine the results if both are enabled!
#external_nodes: None
# The renderer to use on the minions to render the state data
#renderer: yaml_jinja

View file

@ -472,7 +472,7 @@ communication.
``enable_gpu_grains``
---------------------
Default: ``True``
Default: ``False``
Enable GPU hardware data for your master. Be aware that the master can
take a while to start up when lspci and/or dmidecode is used to populate the
@ -2059,23 +2059,6 @@ following configuration:
master_tops:
ext_nodes: <Shell command which returns yaml>
.. conf_master:: external_nodes
``external_nodes``
------------------
Default: None
The external_nodes option allows Salt to gather data that would normally be
placed in a top file from and external node controller. The external_nodes
option is the executable that will return the ENC data. Remember that Salt
will look for external nodes AND top files and combine the results if both
are enabled and available!
.. code-block:: yaml
external_nodes: cobbler-ext-nodes
.. conf_master:: renderer
``renderer``

View file

@ -18,7 +18,7 @@
#======================================================================================================================
set -o nounset # Treat unset variables as an error
__ScriptVersion="2018.08.13"
__ScriptVersion="2018.08.15"
__ScriptName="bootstrap-salt.sh"
__ScriptFullName="$0"
@ -3140,7 +3140,7 @@ install_debian_8_git_deps() {
__PACKAGES="libzmq3 libzmq3-dev lsb-release python-apt python-crypto python-jinja2"
__PACKAGES="${__PACKAGES} python-m2crypto python-msgpack python-requests python-systemd"
__PACKAGES="${__PACKAGES} python-yaml python-zmq"
__PACKAGES="${__PACKAGES} python-yaml python-zmq python-concurrent.futures"
if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then
# Install python-libcloud if asked to
@ -3211,7 +3211,7 @@ install_debian_9_git_deps() {
PY_PKG_VER=""
# These packages are PY2-ONLY
__PACKAGES="${__PACKAGES} python-backports-abc python-m2crypto"
__PACKAGES="${__PACKAGES} python-backports-abc python-m2crypto python-concurrent.futures"
fi
__PACKAGES="${__PACKAGES} python${PY_PKG_VER}-apt python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2"
@ -3429,7 +3429,7 @@ install_fedora_deps() {
fi
fi
__PACKAGES="${__PACKAGES} dnf-utils libyaml python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2"
__PACKAGES="${__PACKAGES} procps-ng dnf-utils libyaml python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2"
__PACKAGES="${__PACKAGES} python${PY_PKG_VER}-msgpack python${PY_PKG_VER}-requests python${PY_PKG_VER}-zmq"
# shellcheck disable=SC2086
@ -3800,7 +3800,7 @@ install_centos_git_deps() {
fi
fi
__PACKAGES="python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2"
__PACKAGES="${__PACKAGES} python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2"
__PACKAGES="${__PACKAGES} python${PY_PKG_VER}-msgpack python${PY_PKG_VER}-requests"
__PACKAGES="${__PACKAGES} python${PY_PKG_VER}-tornado python${PY_PKG_VER}-zmq"
@ -3815,7 +3815,7 @@ install_centos_git_deps() {
if [ "${_PY_EXE}" != "" ] && [ "$_PIP_ALLOWED" -eq "$BS_TRUE" ]; then
# If "-x" is defined, install dependencies with pip based on the Python version given.
_PIP_PACKAGES="m2crypto jinja2 msgpack-python pycrypto PyYAML tornado<5.0 zmq"
_PIP_PACKAGES="m2crypto jinja2 msgpack-python pycrypto PyYAML tornado<5.0 zmq futures>=2.0"
# install swig and openssl on cent6
if [ "$DISTRO_MAJOR_VERSION" -eq 6 ]; then
@ -4608,6 +4608,7 @@ _eof
# which is already installed
__PACKAGES="m2crypto ${pkg_append}-crypto ${pkg_append}-jinja2 ${pkg_append}-PyYAML"
__PACKAGES="${__PACKAGES} ${pkg_append}-msgpack ${pkg_append}-requests ${pkg_append}-zmq"
__PACKAGES="${__PACKAGES} ${pkg_append}-futures"
# shellcheck disable=SC2086
__yum_install_noinput ${__PACKAGES} || return 1
@ -4627,6 +4628,9 @@ install_amazon_linux_ami_git_deps() {
PIP_EXE='pip'
if __check_command_exists python2.7; then
if ! __check_command_exists pip2.7; then
if ! __check_command_exists easy_install-2.7; then
__yum_install_noinput python27-setuptools
fi
/usr/bin/easy_install-2.7 pip || return 1
fi
PIP_EXE='/usr/local/bin/pip2.7'
@ -4646,7 +4650,7 @@ install_amazon_linux_ami_git_deps() {
if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then
__check_pip_allowed "You need to allow pip based installations (-P) in order to install apache-libcloud"
__PACKAGES="${__PACKAGES} python-pip"
__PACKAGES="${__PACKAGES} python27-pip"
__PIP_PACKAGES="${__PIP_PACKAGES} apache-libcloud>=$_LIBCLOUD_MIN_VERSION"
fi
@ -4795,7 +4799,7 @@ install_arch_linux_stable() {
pacman -S --noconfirm --needed bash || return 1
pacman -Su --noconfirm || return 1
# We can now resume regular salt update
pacman -Syu --noconfirm salt || return 1
pacman -Syu --noconfirm salt python2-futures || return 1
return 0
}
@ -5649,7 +5653,7 @@ install_opensuse_git_deps() {
__git_clone_and_checkout || return 1
__PACKAGES="libzmq5 python-Jinja2 python-m2crypto python-msgpack-python python-pycrypto python-pyzmq python-xml"
__PACKAGES="libzmq5 python-Jinja2 python-m2crypto python-msgpack-python python-pycrypto python-pyzmq python-xml python-futures"
if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then
# We're on the develop branch, install whichever tornado is on the requirements file

View file

@ -1212,9 +1212,17 @@ class SAuth(AsyncAuth):
creds = self.sign_in(channel=channel)
if creds == 'retry':
if self.opts.get('caller'):
print('Minion failed to authenticate with the master, '
'has the minion key been accepted?')
sys.exit(2)
# We have a list of masters, so we should break
# and try the next one in the list.
if self.opts.get('local_masters', None):
error = SaltClientError('Minion failed to authenticate'
' with the master, has the '
'minion key been accepted?')
break
else:
print('Minion failed to authenticate with the master, '
'has the minion key been accepted?')
sys.exit(2)
if acceptance_wait_time:
log.info('Waiting %s seconds before retry.', acceptance_wait_time)
time.sleep(acceptance_wait_time)

View file

@ -530,7 +530,7 @@ def name(device, partition, name):
'Invalid characters passed to partition.name'
)
cmd = 'parted -m -s {0} name {1} {2}'.format(device, partition, name)
cmd = '''parted -m -s {0} name {1} "'{2}'"'''.format(device, partition, name)
out = __salt__['cmd.run'](cmd).splitlines()
return out

View file

@ -88,8 +88,6 @@ SERVICE_ERROR_CONTROL = {0: 'Ignore',
'severe': 2,
'critical': 3}
RETRY_ATTEMPTS = 90
def __virtual__():
'''
@ -104,6 +102,51 @@ def __virtual__():
return __virtualname__
def _status_wait(service_name, end_time, service_states):
'''
Helper function that will wait for the status of the service to match the
provided status before an end time expires. Used for service stop and start
.. versionadded:: 2017.7.9, 2018.3.4
Args:
service_name (str):
The name of the service
end_time (float):
A future time. e.g. time.time() + 10
service_states (list):
Services statuses to wait for as returned by info()
Returns:
dict: A dictionary containing information about the service.
:codeauthor: Damon Atkins <https://github.com/damon-atkins>
'''
info_results = info(service_name)
while info_results['Status'] in service_states and time.time() < end_time:
# From Microsoft: Do not wait longer than the wait hint. A good interval
# is one-tenth of the wait hint but not less than 1 second and not more
# than 10 seconds.
# https://docs.microsoft.com/en-us/windows/desktop/services/starting-a-service
# https://docs.microsoft.com/en-us/windows/desktop/services/stopping-a-service
# Wait hint is in ms
wait_time = info_results['Status_WaitHint']
# Convert to seconds or 0
wait_time = wait_time / 1000 if wait_time else 0
if wait_time < 1:
wait_time = 1
elif wait_time > 10:
wait_time = 10
time.sleep(wait_time)
info_results = info(service_name)
return info_results
def get_enabled():
'''
Return a list of enabled services. Enabled is defined as a service that is
@ -378,7 +421,7 @@ def info(name):
return ret
def start(name):
def start(name, timeout=90):
'''
Start the specified service.
@ -389,8 +432,14 @@ def start(name):
Args:
name (str): The name of the service to start
timeout (int):
The time in seconds to wait for the service to start before
returning. Default is 90 seconds
.. versionadded:: 2017.7.9, 2018.3.4
Returns:
bool: True if successful, False otherwise
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -411,24 +460,28 @@ def start(name):
raise CommandExecutionError(
'Failed To Start {0}: {1}'.format(name, exc[2]))
attempts = 0
while info(name)['Status'] in ['Start Pending', 'Stopped'] \
and attempts <= RETRY_ATTEMPTS:
time.sleep(1)
attempts += 1
srv_status = _status_wait(service_name=name,
end_time=time.time() + int(timeout),
service_states=['Start Pending', 'Stopped'])
return status(name)
return srv_status['Status'] == 'Running'
def stop(name):
def stop(name, timeout=90):
'''
Stop the specified service
Args:
name (str): The name of the service to stop
timeout (int):
The time in seconds to wait for the service to stop before
returning. Default is 90 seconds
.. versionadded:: 2017.7.9, 2018.3.4
Returns:
bool: True if successful, False otherwise
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -436,15 +489,6 @@ def stop(name):
salt '*' service.stop <service name>
'''
# net stop issues a stop command and waits briefly (~30s), but will give
# up if the service takes too long to stop with a misleading
# "service could not be stopped" message and RC 0.
cmd = ['net', 'stop', '/y', name]
res = __salt__['cmd.run'](cmd, python_shell=False)
if 'service was stopped' in res:
return True
try:
win32serviceutil.StopService(name)
except pywintypes.error as exc:
@ -452,28 +496,37 @@ def stop(name):
raise CommandExecutionError(
'Failed To Stop {0}: {1}'.format(name, exc[2]))
attempts = 0
while info(name)['Status'] in ['Running', 'Stop Pending'] \
and attempts <= RETRY_ATTEMPTS:
time.sleep(1)
attempts += 1
srv_status = _status_wait(service_name=name,
end_time=time.time() + int(timeout),
service_states=['Running', 'Stop Pending'])
return not status(name)
return srv_status['Status'] == 'Stopped'
def restart(name):
def restart(name, timeout=90):
'''
Restart the named service. This issues a stop command followed by a start.
Args:
name: The name of the service to restart.
.. note::
If the name passed is ``salt-minion`` a scheduled task is created and
executed to restart the salt-minion service.
.. note::
If the name passed is ``salt-minion`` a scheduled task is
created and executed to restart the salt-minion service.
timeout (int):
The time in seconds to wait for the service to stop and start before
returning. Default is 90 seconds
.. note::
The timeout is cumulative meaning it is applied to the stop and
then to the start command. A timeout of 90 could take up to 180
seconds if the service is long in stopping and starting
.. versionadded:: 2017.7.9, 2018.3.4
Returns:
bool: ``True`` if successful, ``False`` otherwise
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -485,7 +538,8 @@ def restart(name):
create_win_salt_restart_task()
return execute_salt_restart_task()
return stop(name) and start(name)
return stop(name=name, timeout=timeout) and \
start(name=name, timeout=timeout)
def create_win_salt_restart_task():
@ -531,7 +585,7 @@ def execute_salt_restart_task():
return __salt__['task.run'](name='restart-salt-minion')
def status(name, sig=None):
def status(name, *args, **kwargs):
'''
Return the status for a service.
If the name contains globbing, a dict mapping service name to True/False
@ -542,7 +596,6 @@ def status(name, sig=None):
Args:
name (str): The name of the service to check
sig (str): Not supported on Windows
Returns:
bool: True if running, False otherwise
@ -610,20 +663,26 @@ def modify(name,
.. versionadded:: 2016.11.0
Args:
name (str): The name of the service. Can be found using the
name (str):
The name of the service. Can be found using the
``service.get_service_name`` function
bin_path (str): The path to the service executable. Backslashes must be
escaped, eg: C:\\path\\to\\binary.exe
bin_path (str):
The path to the service executable. Backslashes must be escaped, eg:
``C:\\path\\to\\binary.exe``
exe_args (str): Any arguments required by the service executable
exe_args (str):
Any arguments required by the service executable
display_name (str): The name to display in the service manager
display_name (str):
The name to display in the service manager
description (str): The description to display for the service
description (str):
The description to display for the service
service_type (str): Specifies the service type. Default is ``own``.
Valid options are as follows:
service_type (str):
Specifies the service type. Default is ``own``. Valid options are as
follows:
- kernel: Driver service
- filesystem: File system driver service
@ -632,8 +691,8 @@ def modify(name,
- own (default): Service runs in its own process
- share: Service shares a process with one or more other services
start_type (str): Specifies the service start type. Valid options are as
follows:
start_type (str):
Specifies the service start type. Valid options are as follows:
- boot: Device driver that is loaded by the boot loader
- system: Device driver that is started during kernel initialization
@ -641,13 +700,14 @@ def modify(name,
- manual: Service must be started manually
- disabled: Service cannot be started
start_delayed (bool): Set the service to Auto(Delayed Start). Only valid
if the start_type is set to ``Auto``. If service_type is not passed,
but the service is already set to ``Auto``, then the flag will be
set.
start_delayed (bool):
Set the service to Auto(Delayed Start). Only valid if the start_type
is set to ``Auto``. If service_type is not passed, but the service
is already set to ``Auto``, then the flag will be set.
error_control (str): The severity of the error, and action taken, if
this service fails to start. Valid options are as follows:
error_control (str):
The severity of the error, and action taken, if this service fails
to start. Valid options are as follows:
- normal: Error is logged and a message box is displayed
- severe: Error is logged and computer attempts a restart with the
@ -657,29 +717,33 @@ def modify(name,
- ignore: Error is logged and startup continues, no notification is
given to the user
load_order_group: The name of the load order group to which this service
belongs
load_order_group (str):
The name of the load order group to which this service belongs
dependencies (list): A list of services or load ordering groups that
must start before this service
dependencies (list):
A list of services or load ordering groups that must start before
this service
account_name (str): The name of the account under which the service
should run. For ``own`` type services this should be in the
``domain\\username`` format. The following are examples of valid
built-in service accounts:
account_name (str):
The name of the account under which the service should run. For
``own`` type services this should be in the ``domain\\username``
format. The following are examples of valid built-in service
accounts:
- NT Authority\\LocalService
- NT Authority\\NetworkService
- NT Authority\\LocalSystem
- .\LocalSystem
account_password (str): The password for the account name specified in
``account_name``. For the above built-in accounts, this can be None.
Otherwise a password must be specified.
account_password (str):
The password for the account name specified in ``account_name``. For
the above built-in accounts, this can be None. Otherwise a password
must be specified.
run_interactive (bool): If this setting is True, the service will be
allowed to interact with the user. Not recommended for services that
run with elevated privileges.
run_interactive (bool):
If this setting is True, the service will be allowed to interact
with the user. Not recommended for services that run with elevated
privileges.
Returns:
dict: a dictionary of changes made
@ -936,20 +1000,26 @@ def create(name,
Args:
name (str): Specifies the service name. This is not the display_name
name (str):
Specifies the service name. This is not the display_name
bin_path (str): Specifies the path to the service binary file.
Backslashes must be escaped, eg: C:\\path\\to\\binary.exe
bin_path (str):
Specifies the path to the service binary file. Backslashes must be
escaped, eg: ``C:\\path\\to\\binary.exe``
exe_args (str): Any additional arguments required by the service binary.
exe_args (str):
Any additional arguments required by the service binary.
display_name (str): the name to be displayed in the service manager. If
not passed, the ``name`` will be used
display_name (str):
The name to be displayed in the service manager. If not passed, the
``name`` will be used
description (str): A description of the service
description (str):
A description of the service
service_type (str): Specifies the service type. Default is ``own``.
Valid options are as follows:
service_type (str):
Specifies the service type. Default is ``own``. Valid options are as
follows:
- kernel: Driver service
- filesystem: File system driver service
@ -958,8 +1028,8 @@ def create(name,
- own (default): Service runs in its own process
- share: Service shares a process with one or more other services
start_type (str): Specifies the service start type. Valid options are as
follows:
start_type (str):
Specifies the service start type. Valid options are as follows:
- boot: Device driver that is loaded by the boot loader
- system: Device driver that is started during kernel initialization
@ -967,13 +1037,15 @@ def create(name,
- manual (default): Service must be started manually
- disabled: Service cannot be started
start_delayed (bool): Set the service to Auto(Delayed Start). Only valid
if the start_type is set to ``Auto``. If service_type is not passed,
but the service is already set to ``Auto``, then the flag will be
set. Default is ``False``
start_delayed (bool):
Set the service to Auto(Delayed Start). Only valid if the start_type
is set to ``Auto``. If service_type is not passed, but the service
is already set to ``Auto``, then the flag will be set. Default is
``False``
error_control (str): The severity of the error, and action taken, if
this service fails to start. Valid options are as follows:
error_control (str):
The severity of the error, and action taken, if this service fails
to start. Valid options are as follows:
- normal (normal): Error is logged and a message box is displayed
- severe: Error is logged and computer attempts a restart with the
@ -983,29 +1055,33 @@ def create(name,
- ignore: Error is logged and startup continues, no notification is
given to the user
load_order_group: The name of the load order group to which this service
belongs
load_order_group (str):
The name of the load order group to which this service belongs
dependencies (list): A list of services or load ordering groups that
must start before this service
dependencies (list):
A list of services or load ordering groups that must start before
this service
account_name (str): The name of the account under which the service
should run. For ``own`` type services this should be in the
``domain\\username`` format. The following are examples of valid
built-in service accounts:
account_name (str):
The name of the account under which the service should run. For
``own`` type services this should be in the ``domain\\username``
format. The following are examples of valid built-in service
accounts:
- NT Authority\\LocalService
- NT Authority\\NetworkService
- NT Authority\\LocalSystem
- .\\LocalSystem
account_password (str): The password for the account name specified in
``account_name``. For the above built-in accounts, this can be None.
Otherwise a password must be specified.
account_password (str):
The password for the account name specified in ``account_name``. For
the above built-in accounts, this can be None. Otherwise a password
must be specified.
run_interactive (bool): If this setting is True, the service will be
allowed to interact with the user. Not recommended for services that
run with elevated privileges.
run_interactive (bool):
If this setting is True, the service will be allowed to interact
with the user. Not recommended for services that run with elevated
privileges.
Returns:
dict: A dictionary containing information about the new service
@ -1096,15 +1172,23 @@ def create(name,
return info(name)
def delete(name):
def delete(name, timeout=90):
'''
Delete the named service
Args:
name (str): The name of the service to delete
timeout (int):
The time in seconds to wait for the service to be deleted before
returning. This is necessary because a service must be stopped
before it can be deleted. Default is 90 seconds
.. versionadded:: 2017.7.9, 2018.3.4
Returns:
bool: True if successful, False otherwise
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -1120,16 +1204,20 @@ def delete(name):
handle_scm, name, win32service.SERVICE_ALL_ACCESS)
except pywintypes.error as exc:
raise CommandExecutionError(
'Failed To Open {0}: {1}'.format(name, exc[2]))
'Failed to open {0}. {1}'.format(name, exc.strerror))
win32service.DeleteService(handle_svc)
try:
win32service.DeleteService(handle_svc)
except pywintypes.error as exc:
raise CommandExecutionError(
'Failed to delete {0}. {1}'.format(name, exc.strerror))
finally:
log.debug('Cleaning up')
win32service.CloseServiceHandle(handle_scm)
win32service.CloseServiceHandle(handle_svc)
win32service.CloseServiceHandle(handle_scm)
win32service.CloseServiceHandle(handle_svc)
attempts = 0
while name in get_all() and attempts <= RETRY_ATTEMPTS:
end_time = time.time() + int(timeout)
while name in get_all() and time.time() < end_time:
time.sleep(1)
attempts += 1
return name not in get_all()

View file

@ -111,12 +111,14 @@ class NestDisplay(object):
)
# Number includes all python numbers types
# (float, int, long, complex, ...)
# use repr() to get the full precision also for older python versions
# as until about python32 it was limited to 12 digits only by default
elif isinstance(ret, Number):
out.append(
self.ustring(
indent,
self.LIGHT_YELLOW,
ret,
repr(ret),
prefix=prefix
)
)

View file

@ -2656,8 +2656,15 @@ def managed(name,
ret['changes'] = {}
log.debug(traceback.format_exc())
salt.utils.files.remove(tmp_filename)
if not keep_source and sfn:
salt.utils.files.remove(sfn)
if not keep_source:
if not sfn \
and source \
and _urlparse(source).scheme == 'salt':
# The file would not have been cached until manage_file was
# run, so check again here for a cached copy.
sfn = __salt__['cp.is_cached'](source, __env__)
if sfn:
salt.utils.files.remove(sfn)
return _error(ret, 'Unable to check_cmd file: {0}'.format(exc))
# file being updated to verify using check_cmd
@ -2729,8 +2736,15 @@ def managed(name,
finally:
if tmp_filename:
salt.utils.files.remove(tmp_filename)
if not keep_source and sfn:
salt.utils.files.remove(sfn)
if not keep_source:
if not sfn \
and source \
and _urlparse(source).scheme == 'salt':
# The file would not have been cached until manage_file was
# run, so check again here for a cached copy.
sfn = __salt__['cp.is_cached'](source, __env__)
if sfn:
salt.utils.files.remove(sfn)
_RECURSE_TYPES = ['user', 'group', 'mode', 'ignore_files', 'ignore_dirs']

View file

@ -199,6 +199,21 @@ def mounted(name,
update_mount_cache = False
if not name:
ret['result'] = False
ret['comment'] = 'Must provide name to mount.mounted'
return ret
if not device:
ret['result'] = False
ret['comment'] = 'Must provide device to mount.mounted'
return ret
if not fstype:
ret['result'] = False
ret['comment'] = 'Must provide fstype to mount.mounted'
return ret
if device_name_regex is None:
device_name_regex = []
@ -588,11 +603,11 @@ def mounted(name,
if __opts__['test']:
if __grains__['os'] in ['MacOS', 'Darwin']:
out = __salt__['mount.set_automaster'](name,
device,
fstype,
opts,
config,
test=True)
device,
fstype,
opts,
config,
test=True)
elif __grains__['os'] in ['AIX']:
out = __salt__['mount.set_filesystems'](name,
device,
@ -646,10 +661,10 @@ def mounted(name,
else:
if __grains__['os'] in ['MacOS', 'Darwin']:
out = __salt__['mount.set_automaster'](name,
device,
fstype,
opts,
config)
device,
fstype,
opts,
config)
elif __grains__['os'] in ['AIX']:
out = __salt__['mount.set_filesystems'](name,
device,
@ -830,6 +845,11 @@ def unmounted(name,
update_mount_cache = False
if not name:
ret['result'] = False
ret['comment'] = 'Must provide name to mount.unmounted'
return ret
# Get the active data
active = __salt__['mount.active'](extended=True)
if name not in active:

View file

@ -437,16 +437,15 @@ def running(name,
ret['comment'] = 'Service {0} is set to start'.format(name)
return ret
if salt.utils.platform.is_windows():
if enable is True:
ret.update(_enable(name, False, result=False, **kwargs))
# Conditionally add systemd-specific args to call to service.start
start_kwargs, warnings = \
_get_systemd_only(__salt__['service.start'], locals())
if warnings:
ret.setdefault('warnings', []).extend(warnings)
if salt.utils.platform.is_windows() and kwargs.get('timeout', False):
start_kwargs.update({'timeout': kwargs.get('timeout')})
try:
func_ret = __salt__['service.start'](name, **start_kwargs)
except CommandExecutionError as exc:
@ -590,6 +589,9 @@ def dead(name,
if warnings:
ret.setdefault('warnings', []).extend(warnings)
if salt.utils.platform.is_windows() and kwargs.get('timeout', False):
stop_kwargs.update({'timeout': kwargs.get('timeout')})
func_ret = __salt__['service.stop'](name, **stop_kwargs)
if not func_ret:
ret['result'] = False

View file

@ -5,16 +5,13 @@ Utilities to enable exception reraising across the master commands
'''
from __future__ import absolute_import, unicode_literals, print_function
# Import python libs
try:
import exceptions
except ImportError:
pass
# Import salt libs
import salt.exceptions
import salt.utils.event
# Import 3rd-party libs
from salt.ext.six.moves import builtins as exceptions
def raise_error(name=None, args=None, message=''):
'''

View file

@ -706,7 +706,7 @@ class CkMinions(object):
'S': 'ipcidr',
'E': 'pcre',
'N': 'node',
None: 'glob'}
None: 'compound'}
target_info = parse_target(auth_entry)
if not target_info:

View file

@ -1126,7 +1126,10 @@ class TestDaemon(object):
for dirname in (TMP, RUNTIME_VARS.TMP_STATE_TREE,
RUNTIME_VARS.TMP_PILLAR_TREE, RUNTIME_VARS.TMP_PRODENV_STATE_TREE):
if os.path.isdir(dirname):
shutil.rmtree(six.text_type(dirname), onerror=remove_readonly)
try:
shutil.rmtree(six.text_type(dirname), onerror=remove_readonly)
except Exception:
log.exception('Failed to remove directory: %s', dirname)
def wait_for_jid(self, targets, jid, timeout=120):
time.sleep(1) # Allow some time for minions to accept jobs

View file

@ -7,4 +7,4 @@ azure-test:
ssh_username: ''
ssh_password: ''
media_link: ''
script_args: '-P -Z'
script_args: '-P'

View file

@ -2,4 +2,4 @@ digitalocean-test:
provider: digitalocean-config
image: 14.04.5 x64
size: 2GB
script_args: '-P -Z'
script_args: '-P'

View file

@ -3,7 +3,7 @@ ec2-test:
image: ami-98aa1cf0
size: m1.large
sh_username: ec2-user
script_args: '-P -Z'
script_args: '-P'
ec2-win2012r2-test:
provider: ec2-config
size: m1.large

View file

@ -2,4 +2,4 @@ gogrid-test:
provider: gogrid-config
size: 512MB
image: Ubuntu 14.04 LTS Server (64-bit) w/ None
script_args: '-P -Z'
script_args: '-P'

View file

@ -3,4 +3,4 @@ joyent-test:
size: k4-highcpu-kvm-250M
image: ubuntu-16.04
location: us-east-1
script_args: '-P -Z'
script_args: '-P'

View file

@ -2,4 +2,4 @@ linode-test:
provider: linode-config
size: Linode 2GB
image: Ubuntu 14.04 LTS
script_args: '-P -Z'
script_args: '-P'

View file

@ -2,4 +2,4 @@ rackspace-test:
provider: openstack-config
size: 2 GB Performance
image: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)
script_args: '-P -Z'
script_args: '-P'

View file

@ -363,7 +363,7 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
with salt.utils.files.fopen(grain_path, 'r') as fp_:
file_contents = fp_.readlines()
if salt.utils.platform.is_windows():
if IS_WINDOWS:
match = '^minion\r\n'
else:
match = '^minion\n'
@ -592,8 +592,8 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
name = os.path.join(TMP, 'local_source_with_source_hash')
local_path = os.path.join(BASE_FILES, 'grail', 'scene33')
actual_hash = '567fd840bf1548edc35c48eb66cdd78bfdfcccff'
if salt.utils.platform.is_windows():
# CRLF vs LF causes a differnt hash on windows
if IS_WINDOWS:
# CRLF vs LF causes a different hash on windows
actual_hash = 'f658a0ec121d9c17088795afcc6ff3c43cb9842a'
# Reverse the actual hash
bad_hash = actual_hash[::-1]
@ -677,7 +677,7 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
'-{0}_|-managed'.format(name)
local_path = os.path.join(BASE_FILES, 'hello_world.txt')
actual_hash = 'c98c24b677eff44860afea6f493bbaec5bb1c4cbb209c6fc2bbb47f66ff2ad31'
if salt.utils.platform.is_windows():
if IS_WINDOWS:
# CRLF vs LF causes a differnt hash on windows
actual_hash = '92b772380a3f8e27a93e57e6deeca6c01da07f5aadce78bb2fbb20de10a66925'
uppercase_hash = actual_hash.upper()
@ -743,6 +743,29 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
diff_lines = ret['changes']['diff'].split(os.linesep)
assert '+räksmörgås' in diff_lines, diff_lines
@with_tempfile()
def test_managed_keep_source_false_salt(self, name):
'''
This test ensures that we properly clean the cached file if keep_source
is set to False, for source files using a salt:// URL
'''
source = 'salt://grail/scene33'
saltenv = 'base'
# Run the state
ret = self.run_state(
'file.managed',
name=name,
source=source,
saltenv=saltenv,
keep_source=False)
ret = ret[next(iter(ret))]
assert ret['result'] is True
# Now make sure that the file is not cached
result = self.run_function('cp.is_cached', [source, saltenv])
assert result == '', 'File is still cached at {0}'.format(result)
def test_directory(self):
'''
file.directory
@ -861,14 +884,10 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
self.assertFalse(os.path.exists(straydir))
self.assertTrue(os.path.isdir(name))
@skipIf(salt.utils.platform.is_windows(), 'Skip on windows')
@with_tempdir()
def test_directory_clean_exclude(self, base_dir):
'''
file.directory with clean=True and exclude_pat set
Skipped on windows because clean and exclude_pat not supported by
salt.sates.file._check_directory_win
'''
name = os.path.join(base_dir, 'directory_clean_dir')
if not os.path.isdir(name):
@ -904,11 +923,14 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
self.assertFalse(os.path.exists(strayfile2))
self.assertTrue(os.path.exists(keepfile))
@skipIf(salt.utils.is_windows(), 'Skip on windows')
@skipIf(IS_WINDOWS, 'Skip on windows')
@with_tempdir()
def test_test_directory_clean_exclude(self, base_dir):
'''
file.directory with test=True, clean=True and exclude_pat set
Skipped on windows because clean and exclude_pat not supported by
salt.sates.file._check_directory_win
'''
name = os.path.join(base_dir, 'directory_clean_dir')
os.mkdir(name)
@ -1231,7 +1253,7 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
self.assertTrue(os.path.isfile(os.path.join(name, '32', 'scene')))
self.assertTrue(os.path.isfile(os.path.join(name, 'scene34')))
@skipIf(salt.utils.platform.is_windows(), 'Skip on windows')
@skipIf(IS_WINDOWS, 'Skip on windows')
@with_tempdir()
def test_recurse_issue_34945(self, base_dir):
'''
@ -1273,7 +1295,7 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
name=name,
source='salt://соль')
self.assertSaltTrueReturn(ret)
if six.PY2 and salt.utils.platform.is_windows():
if six.PY2 and IS_WINDOWS:
# Providing unicode to os.listdir so that we avoid having listdir
# try to decode the filenames using the systemencoding on windows
# python 2.
@ -2496,18 +2518,18 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin):
marker_start = '# start'
marker_end = '# end'
content = os.linesep.join([
content = six.text_type(os.linesep.join([
'Line 1 of block',
'Line 2 of block',
''
])
without_block = os.linesep.join([
]))
without_block = six.text_type(os.linesep.join([
'Hello world!',
'',
'# comment here',
''
])
with_non_matching_block = os.linesep.join([
]))
with_non_matching_block = six.text_type(os.linesep.join([
'Hello world!',
'',
'# start',
@ -2515,16 +2537,16 @@ class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin):
'# end',
'# comment here',
''
])
with_non_matching_block_and_marker_end_not_after_newline = os.linesep.join([
]))
with_non_matching_block_and_marker_end_not_after_newline = six.text_type(os.linesep.join([
'Hello world!',
'',
'# start',
'No match here# end',
'# comment here',
''
])
with_matching_block = os.linesep.join([
]))
with_matching_block = six.text_type(os.linesep.join([
'Hello world!',
'',
'# start',
@ -2533,8 +2555,8 @@ class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin):
'# end',
'# comment here',
''
])
with_matching_block_and_extra_newline = os.linesep.join([
]))
with_matching_block_and_extra_newline = six.text_type(os.linesep.join([
'Hello world!',
'',
'# start',
@ -2544,8 +2566,8 @@ class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin):
'# end',
'# comment here',
''
])
with_matching_block_and_marker_end_not_after_newline = os.linesep.join([
]))
with_matching_block_and_marker_end_not_after_newline = six.text_type(os.linesep.join([
'Hello world!',
'',
'# start',
@ -2553,7 +2575,7 @@ class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin):
'Line 2 of block# end',
'# comment here',
''
])
]))
content_explicit_posix_newlines = ('Line 1 of block\n'
'Line 2 of block\n')
content_explicit_windows_newlines = ('Line 1 of block\r\n'
@ -3711,8 +3733,8 @@ class RemoteFileTest(ModuleCase, SaltReturnAssertsMixin):
cls.webserver = Webserver()
cls.webserver.start()
cls.source = cls.webserver.url('grail/scene33')
if salt.utils.platform.is_windows():
# CRLF vs LF causes a differnt hash on windows
if IS_WINDOWS:
# CRLF vs LF causes a different hash on windows
cls.source_hash = '21438b3d5fd2c0028bcab92f7824dc69'
else:
cls.source_hash = 'd2feb3beb323c79fc7a0f44f1408b4a3'
@ -3732,6 +3754,11 @@ class RemoteFileTest(ModuleCase, SaltReturnAssertsMixin):
if exc.errno != errno.ENOENT:
raise exc
def run_state(self, *args, **kwargs):
ret = super(RemoteFileTest, self).run_state(*args, **kwargs)
log.debug('ret = %s', ret)
return ret
def test_file_managed_http_source_no_hash(self):
'''
Test a remote file with no hash
@ -3740,7 +3767,6 @@ class RemoteFileTest(ModuleCase, SaltReturnAssertsMixin):
name=self.name,
source=self.source,
skip_verify=False)
log.debug('ret = %s', ret)
# This should fail because no hash was provided
self.assertSaltFalseReturn(ret)
@ -3753,7 +3779,6 @@ class RemoteFileTest(ModuleCase, SaltReturnAssertsMixin):
source=self.source,
source_hash=self.source_hash,
skip_verify=False)
log.debug('ret = %s', ret)
self.assertSaltTrueReturn(ret)
def test_file_managed_http_source_skip_verify(self):
@ -3764,9 +3789,27 @@ class RemoteFileTest(ModuleCase, SaltReturnAssertsMixin):
name=self.name,
source=self.source,
skip_verify=True)
log.debug('ret = %s', ret)
self.assertSaltTrueReturn(ret)
def test_file_managed_keep_source_false_http(self):
'''
This test ensures that we properly clean the cached file if keep_source
is set to False, for source files using an http:// URL
'''
# Run the state
ret = self.run_state('file.managed',
name=self.name,
source=self.source,
source_hash=self.source_hash,
keep_source=False)
ret = ret[next(iter(ret))]
assert ret['result'] is True
# Now make sure that the file is not cached
result = self.run_function('cp.is_cached', [self.source])
assert result == '', 'File is still cached at {0}'.format(result)
WIN_TEST_FILE = 'c:/testfile'

View file

@ -48,7 +48,7 @@ class CkMinionsTestCase(TestCase):
TestCase for salt.utils.minions.CkMinions class
'''
def setUp(self):
self.ckminions = salt.utils.minions.CkMinions({})
self.ckminions = salt.utils.minions.CkMinions({'minion_data_cache': True})
def test_spec_check(self):
# Test spec-only rule