mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2016.11' into 2016.11
This commit is contained in:
commit
1d0bd5bb32
34 changed files with 1482 additions and 830 deletions
|
@ -5,7 +5,7 @@
|
|||
<% driverfile = ENV['SALT_KITCHEN_DRIVER'] || '.kitchen/driver.yml' %>
|
||||
|
||||
<% if File.exists?(driverfile) %>
|
||||
<%= File.read(driverfile) %>
|
||||
<%= ERB.new(File.read(driverfile)).result %>
|
||||
<% else %>
|
||||
driver:
|
||||
name: docker
|
||||
|
@ -31,7 +31,7 @@ provisioner:
|
|||
log_level: info
|
||||
require_chef: false
|
||||
remote_states:
|
||||
name: git://github.com/gtmanfred/salt-jenkins.git
|
||||
name: git://github.com/saltstack/salt-jenkins.git
|
||||
branch: 2016.11
|
||||
repo: git
|
||||
testingdir: /testing
|
||||
|
@ -51,7 +51,7 @@ provisioner:
|
|||
- git.salt
|
||||
- kitchen
|
||||
<% if File.exists?(platformsfile) %>
|
||||
<%= File.read(platformsfile) %>
|
||||
<%= ERB.new(File.read(platformsfile)).result %>
|
||||
<% else %>
|
||||
platforms:
|
||||
- name: fedora
|
||||
|
|
|
@ -19,14 +19,18 @@ Salt SSH allows for salt routines to be executed using only SSH for transport
|
|||
Options
|
||||
=======
|
||||
|
||||
.. program:: salt-ssh
|
||||
|
||||
.. include:: _includes/common-options.rst
|
||||
|
||||
.. option:: --hard-crash
|
||||
|
||||
Raise any original exception rather than exiting gracefully. Default: False.
|
||||
|
||||
.. option:: -r, --raw, --raw-shell
|
||||
|
||||
Execute a raw shell command.
|
||||
|
||||
.. option:: --priv
|
||||
|
||||
Specify the SSH private key file to be used for authentication.
|
||||
|
||||
.. option:: --roster
|
||||
|
||||
Define which roster system to use, this defines if a database backend,
|
||||
|
@ -53,38 +57,117 @@ Options
|
|||
the more running process the faster communication should be, default
|
||||
is 25.
|
||||
|
||||
.. option:: --extra-filerefs=EXTRA_FILEREFS
|
||||
|
||||
Pass in extra files to include in the state tarball.
|
||||
|
||||
.. option:: --min-extra-modules=MIN_EXTRA_MODS
|
||||
|
||||
One or comma-separated list of extra Python modulesto be included
|
||||
into Minimal Salt.
|
||||
|
||||
.. option:: --thin-extra-modules=THIN_EXTRA_MODS
|
||||
|
||||
One or comma-separated list of extra Python modulesto be included
|
||||
into Thin Salt.
|
||||
|
||||
.. option:: -v, --verbose
|
||||
|
||||
Turn on command verbosity, display jid.
|
||||
|
||||
.. option:: -s, --static
|
||||
|
||||
Return the data from minions as a group after they all return.
|
||||
|
||||
.. option:: -w, --wipe
|
||||
|
||||
Remove the deployment of the salt files when done executing.
|
||||
|
||||
.. option:: -W, --rand-thin-dir
|
||||
|
||||
Select a random temp dir to deploy on the remote system. The dir
|
||||
will be cleaned after the execution.
|
||||
|
||||
.. option:: -t, --regen-thin, --thin
|
||||
|
||||
Trigger a thin tarball regeneration. This is needed if custom
|
||||
grains/modules/states have been added or updated.
|
||||
|
||||
.. option:: --python2-bin=PYTHON2_BIN
|
||||
|
||||
Path to a python2 binary which has salt installed.
|
||||
|
||||
.. option:: --python3-bin=PYTHON3_BIN
|
||||
|
||||
Path to a python3 binary which has salt installed.
|
||||
|
||||
.. option:: --jid=JID
|
||||
|
||||
Pass a JID to be used instead of generating one.
|
||||
|
||||
Authentication Options
|
||||
----------------------
|
||||
|
||||
.. option:: --priv=SSH_PRIV
|
||||
|
||||
Specify the SSH private key file to be used for authentication.
|
||||
|
||||
.. option:: -i, --ignore-host-keys
|
||||
|
||||
Disables StrictHostKeyChecking to relax acceptance of new and unknown
|
||||
host keys.
|
||||
By default ssh host keys are honored and connections will ask for
|
||||
approval. Use this option to disable StrictHostKeyChecking.
|
||||
|
||||
.. option:: --no-host-keys
|
||||
|
||||
Fully ignores ssh host keys which by default are honored and connections
|
||||
would ask for approval. Useful if the host key of a remote server has
|
||||
would ask for approval. Useful if the host key of a remote server has
|
||||
changed and would still error with --ignore-host-keys.
|
||||
|
||||
.. option:: --user=SSH_USER
|
||||
|
||||
Set the default user to attempt to use when authenticating.
|
||||
|
||||
.. option:: --passwd
|
||||
|
||||
Set the default password to attempt to use when authenticating.
|
||||
|
||||
.. option:: --askpass
|
||||
|
||||
Interactively ask for the SSH password with no echo - avoids password
|
||||
in process args and stored in history.
|
||||
|
||||
.. option:: --key-deploy
|
||||
|
||||
Set this flag to attempt to deploy the authorized ssh key with all
|
||||
minions. This combined with --passwd can make initial deployment of keys
|
||||
very fast and easy.
|
||||
|
||||
.. program:: salt
|
||||
.. option:: --identities-only
|
||||
|
||||
.. include:: _includes/common-options.rst
|
||||
Use the only authentication identity files configured in the ssh_config
|
||||
files. See IdentitiesOnly flag in man ssh_config.
|
||||
|
||||
.. include:: _includes/target-selection-ssh.rst
|
||||
.. option:: --sudo
|
||||
|
||||
Run command via sudo.
|
||||
|
||||
Scan Roster Options
|
||||
-------------------
|
||||
|
||||
.. option:: --scan-ports=SSH_SCAN_PORTS
|
||||
|
||||
Comma-separated list of ports to scan in the scan roster.
|
||||
|
||||
.. option:: --scan-timeout=SSH_SCAN_TIMEOUT
|
||||
|
||||
Scanning socket timeout for the scan roster.
|
||||
|
||||
.. include:: _includes/logging-options.rst
|
||||
.. |logfile| replace:: /var/log/salt/ssh
|
||||
.. |loglevel| replace:: ``warning``
|
||||
|
||||
.. include:: _includes/target-selection-ssh.rst
|
||||
|
||||
.. include:: _includes/output-options.rst
|
||||
|
||||
|
||||
|
|
|
@ -225,15 +225,16 @@ enclosing brackets ``[`` and ``]``:
|
|||
|
||||
Default: ``{}``
|
||||
|
||||
This can be used to control logging levels more specifically. The example sets
|
||||
the main salt library at the 'warning' level, but sets ``salt.modules`` to log
|
||||
at the ``debug`` level:
|
||||
This can be used to control logging levels more specifically, based on log call name. The example sets
|
||||
the main salt library at the 'warning' level, sets ``salt.modules`` to log
|
||||
at the ``debug`` level, and sets a custom module to the ``all`` level:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
log_granular_levels:
|
||||
'salt': 'warning'
|
||||
'salt.modules': 'debug'
|
||||
'salt.loader.saltmaster.ext.module.custom_module': 'all'
|
||||
|
||||
External Logging Handlers
|
||||
-------------------------
|
||||
|
|
|
@ -303,6 +303,20 @@ option on the Salt master.
|
|||
|
||||
master_port: 4506
|
||||
|
||||
.. conf_minion:: publish_port
|
||||
|
||||
``publish_port``
|
||||
---------------
|
||||
|
||||
Default: ``4505``
|
||||
|
||||
The port of the master publish server, this needs to coincide with the publish_port
|
||||
option on the Salt master.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
publish_port: 4505
|
||||
|
||||
.. conf_minion:: user
|
||||
|
||||
``user``
|
||||
|
|
|
@ -298,3 +298,9 @@ Syncing grains can be done a number of ways, they are automatically synced when
|
|||
above) the grains can be manually synced and reloaded by calling the
|
||||
:mod:`saltutil.sync_grains <salt.modules.saltutil.sync_grains>` or
|
||||
:mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>` functions.
|
||||
|
||||
.. note::
|
||||
|
||||
When the :conf_minion:`grains_cache` is set to False, the grains dictionary is built
|
||||
and stored in memory on the minion. Every time the minion restarts or
|
||||
``saltutil.refresh_grains`` is run, the grain dictionary is rebuilt from scratch.
|
||||
|
|
|
@ -237,7 +237,7 @@ class SyncClientMixin(object):
|
|||
|
||||
def low(self, fun, low, print_event=True, full_return=False):
|
||||
'''
|
||||
Check for deprecated usage and allow until Salt Oxygen.
|
||||
Check for deprecated usage and allow until Salt Fluorine.
|
||||
'''
|
||||
msg = []
|
||||
if 'args' in low:
|
||||
|
@ -248,7 +248,7 @@ class SyncClientMixin(object):
|
|||
low['kwarg'] = low.pop('kwargs')
|
||||
|
||||
if msg:
|
||||
salt.utils.warn_until('Oxygen', ' '.join(msg))
|
||||
salt.utils.warn_until('Fluorine', ' '.join(msg))
|
||||
|
||||
return self._low(fun, low, print_event=print_event, full_return=full_return)
|
||||
|
||||
|
|
|
@ -451,14 +451,14 @@ def tar(options, tarfile, sources=None, dest=None,
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' archive.tar -cjvf /tmp/salt.tar.bz2 {{grains.saltpath}} template=jinja
|
||||
salt '*' archive.tar cjvf /tmp/salt.tar.bz2 {{grains.saltpath}} template=jinja
|
||||
|
||||
CLI Examples:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Create a tarfile
|
||||
salt '*' archive.tar -cjvf /tmp/tarfile.tar.bz2 /tmp/file_1,/tmp/file_2
|
||||
salt '*' archive.tar cjvf /tmp/tarfile.tar.bz2 /tmp/file_1,/tmp/file_2
|
||||
# Unpack a tarfile
|
||||
salt '*' archive.tar xf foo.tar dest=/target/directory
|
||||
'''
|
||||
|
|
|
@ -1856,14 +1856,14 @@ def line(path, content, match=None, mode=None, location=None,
|
|||
if changed:
|
||||
if show_changes:
|
||||
with salt.utils.fopen(path, 'r') as fp_:
|
||||
path_content = _splitlines_preserving_trailing_newline(
|
||||
fp_.read())
|
||||
changes_diff = ''.join(difflib.unified_diff(
|
||||
path_content, _splitlines_preserving_trailing_newline(body)))
|
||||
path_content = fp_.read().splitlines(True)
|
||||
changes_diff = ''.join(difflib.unified_diff(path_content, body.splitlines(True)))
|
||||
if __opts__['test'] is False:
|
||||
fh_ = None
|
||||
try:
|
||||
fh_ = salt.utils.atomicfile.atomic_open(path, 'w')
|
||||
# Make sure we match the file mode from salt.utils.fopen
|
||||
mode = 'wb' if six.PY2 and salt.utils.is_windows() else 'w'
|
||||
fh_ = salt.utils.atomicfile.atomic_open(path, mode)
|
||||
fh_.write(body)
|
||||
finally:
|
||||
if fh_:
|
||||
|
@ -3764,8 +3764,15 @@ def get_managed(
|
|||
parsed_scheme = urlparsed_source.scheme
|
||||
parsed_path = os.path.join(
|
||||
urlparsed_source.netloc, urlparsed_source.path).rstrip(os.sep)
|
||||
unix_local_source = parsed_scheme in ('file', '')
|
||||
|
||||
if parsed_scheme and parsed_scheme.lower() in 'abcdefghijklmnopqrstuvwxyz':
|
||||
if unix_local_source:
|
||||
sfn = parsed_path
|
||||
if not os.path.exists(sfn):
|
||||
msg = 'Local file source {0} does not exist'.format(sfn)
|
||||
return '', {}, msg
|
||||
|
||||
if parsed_scheme and parsed_scheme.lower() in string.ascii_lowercase:
|
||||
parsed_path = ':'.join([parsed_scheme, parsed_path])
|
||||
parsed_scheme = 'file'
|
||||
|
||||
|
@ -3773,9 +3780,10 @@ def get_managed(
|
|||
source_sum = __salt__['cp.hash_file'](source, saltenv)
|
||||
if not source_sum:
|
||||
return '', {}, 'Source file {0} not found'.format(source)
|
||||
elif not source_hash and parsed_scheme == 'file':
|
||||
elif not source_hash and unix_local_source:
|
||||
source_sum = _get_local_file_source_sum(parsed_path)
|
||||
elif not source_hash and source.startswith(os.sep):
|
||||
# This should happen on Windows
|
||||
source_sum = _get_local_file_source_sum(source)
|
||||
else:
|
||||
if not skip_verify:
|
||||
|
@ -4650,21 +4658,22 @@ def manage_file(name,
|
|||
if source_sum and ('hsum' in source_sum):
|
||||
source_sum['hsum'] = source_sum['hsum'].lower()
|
||||
|
||||
if source and not sfn:
|
||||
# File is not present, cache it
|
||||
sfn = __salt__['cp.cache_file'](source, saltenv)
|
||||
if source:
|
||||
if not sfn:
|
||||
return _error(
|
||||
ret, 'Source file \'{0}\' not found'.format(source))
|
||||
htype = source_sum.get('hash_type', __opts__['hash_type'])
|
||||
# Recalculate source sum now that file has been cached
|
||||
source_sum = {
|
||||
'hash_type': htype,
|
||||
'hsum': get_hash(sfn, form=htype)
|
||||
}
|
||||
# File is not present, cache it
|
||||
sfn = __salt__['cp.cache_file'](source, saltenv)
|
||||
if not sfn:
|
||||
return _error(
|
||||
ret, 'Source file \'{0}\' not found'.format(source))
|
||||
htype = source_sum.get('hash_type', __opts__['hash_type'])
|
||||
# Recalculate source sum now that file has been cached
|
||||
source_sum = {
|
||||
'hash_type': htype,
|
||||
'hsum': get_hash(sfn, form=htype)
|
||||
}
|
||||
|
||||
if keep_mode:
|
||||
if _urlparse(source).scheme in ('salt', 'file') \
|
||||
or source.startswith('/'):
|
||||
if _urlparse(source).scheme in ('salt', 'file', ''):
|
||||
try:
|
||||
mode = __salt__['cp.stat_file'](source, saltenv=saltenv, octal=True)
|
||||
except Exception as exc:
|
||||
|
@ -4694,7 +4703,7 @@ def manage_file(name,
|
|||
# source, and we are not skipping checksum verification, then
|
||||
# verify that it matches the specified checksum.
|
||||
if not skip_verify \
|
||||
and _urlparse(source).scheme not in ('salt', ''):
|
||||
and _urlparse(source).scheme != 'salt':
|
||||
dl_sum = get_hash(sfn, source_sum['hash_type'])
|
||||
if dl_sum != source_sum['hsum']:
|
||||
ret['comment'] = (
|
||||
|
@ -4859,8 +4868,6 @@ def manage_file(name,
|
|||
group=group, mode=dir_mode)
|
||||
|
||||
if source:
|
||||
# It is a new file, set the diff accordingly
|
||||
ret['changes']['diff'] = 'New file'
|
||||
# Apply the new file
|
||||
if not sfn:
|
||||
sfn = __salt__['cp.cache_file'](source, saltenv)
|
||||
|
@ -4884,6 +4891,8 @@ def manage_file(name,
|
|||
)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
# It is a new file, set the diff accordingly
|
||||
ret['changes']['diff'] = 'New file'
|
||||
if not os.path.isdir(contain_dir):
|
||||
if makedirs:
|
||||
_set_mode_and_make_dirs(name, dir_mode, mode, user, group)
|
||||
|
|
|
@ -24,7 +24,7 @@ Values or Entries
|
|||
Values/Entries are name/data pairs. There can be many values in a key. The
|
||||
(Default) value corresponds to the Key, the rest are their own value pairs.
|
||||
|
||||
:depends: - winreg Python module
|
||||
:depends: - PyWin32
|
||||
'''
|
||||
# When production windows installer is using Python 3, Python 2 code can be removed
|
||||
|
||||
|
@ -35,14 +35,13 @@ from __future__ import unicode_literals
|
|||
import sys
|
||||
import logging
|
||||
from salt.ext.six.moves import range # pylint: disable=W0622,import-error
|
||||
from salt.ext import six
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
from salt.ext.six.moves import winreg as _winreg # pylint: disable=import-error,no-name-in-module
|
||||
from win32gui import SendMessageTimeout
|
||||
from win32con import HWND_BROADCAST, WM_SETTINGCHANGE, SMTO_ABORTIFHUNG
|
||||
from win32api import RegCreateKeyEx, RegSetValueEx, RegFlushKey, RegCloseKey, error as win32apiError
|
||||
import win32gui
|
||||
import win32api
|
||||
import win32con
|
||||
import pywintypes
|
||||
HAS_WINDOWS_MODULES = True
|
||||
except ImportError:
|
||||
HAS_WINDOWS_MODULES = False
|
||||
|
@ -60,7 +59,7 @@ __virtualname__ = 'reg'
|
|||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only works on Windows systems with the _winreg python module
|
||||
Only works on Windows systems with the PyWin32
|
||||
'''
|
||||
if not salt.utils.is_windows():
|
||||
return (False, 'reg execution module failed to load: '
|
||||
|
@ -69,104 +68,76 @@ def __virtual__():
|
|||
if not HAS_WINDOWS_MODULES:
|
||||
return (False, 'reg execution module failed to load: '
|
||||
'One of the following libraries did not load: '
|
||||
+ '_winreg, win32gui, win32con, win32api')
|
||||
+ 'win32gui, win32con, win32api')
|
||||
|
||||
return __virtualname__
|
||||
|
||||
|
||||
# winreg in python 2 is hard coded to use codex 'mbcs', which uses
|
||||
# encoding that the user has assign. The function _unicode_to_mbcs
|
||||
# and _unicode_to_mbcs help with this.
|
||||
def _to_mbcs(vdata):
|
||||
'''
|
||||
Converts unicode to to current users character encoding. Use this for values
|
||||
returned by reg functions
|
||||
'''
|
||||
return salt.utils.to_unicode(vdata, 'mbcs')
|
||||
|
||||
|
||||
def _unicode_to_mbcs(instr):
|
||||
def _to_unicode(vdata):
|
||||
'''
|
||||
Converts unicode to to current users character encoding.
|
||||
Converts from current users character encoding to unicode. Use this for
|
||||
parameters being pass to reg functions
|
||||
'''
|
||||
if isinstance(instr, six.text_type):
|
||||
# unicode to windows utf8
|
||||
return instr.encode('mbcs')
|
||||
else:
|
||||
# Assume its byte str or not a str/unicode
|
||||
return instr
|
||||
|
||||
|
||||
def _mbcs_to_unicode(instr):
|
||||
'''
|
||||
Converts from current users character encoding to unicode.
|
||||
When instr has a value of None, the return value of the function
|
||||
will also be None.
|
||||
'''
|
||||
if instr is None or isinstance(instr, six.text_type):
|
||||
return instr
|
||||
else:
|
||||
return six.text_type(instr, 'mbcs')
|
||||
|
||||
|
||||
def _mbcs_to_unicode_wrap(obj, vtype):
|
||||
'''
|
||||
Wraps _mbcs_to_unicode for use with registry vdata
|
||||
'''
|
||||
if vtype == 'REG_BINARY':
|
||||
# We should be able to leave it alone if the user has passed binary data in yaml with
|
||||
# binary !!
|
||||
# In python < 3 this should have type str and in python 3+ this should be a byte array
|
||||
return obj
|
||||
if isinstance(obj, list):
|
||||
return [_mbcs_to_unicode(x) for x in obj]
|
||||
elif isinstance(obj, six.integer_types):
|
||||
return obj
|
||||
else:
|
||||
return _mbcs_to_unicode(obj)
|
||||
return salt.utils.to_unicode(vdata, 'utf-8')
|
||||
|
||||
|
||||
class Registry(object): # pylint: disable=R0903
|
||||
'''
|
||||
Delay '_winreg' usage until this module is used
|
||||
Delay usage until this module is used
|
||||
'''
|
||||
def __init__(self):
|
||||
self.hkeys = {
|
||||
'HKEY_CURRENT_USER': _winreg.HKEY_CURRENT_USER,
|
||||
'HKEY_LOCAL_MACHINE': _winreg.HKEY_LOCAL_MACHINE,
|
||||
'HKEY_USERS': _winreg.HKEY_USERS,
|
||||
'HKCU': _winreg.HKEY_CURRENT_USER,
|
||||
'HKLM': _winreg.HKEY_LOCAL_MACHINE,
|
||||
'HKU': _winreg.HKEY_USERS,
|
||||
'HKEY_CURRENT_USER': win32con.HKEY_CURRENT_USER,
|
||||
'HKEY_LOCAL_MACHINE': win32con.HKEY_LOCAL_MACHINE,
|
||||
'HKEY_USERS': win32con.HKEY_USERS,
|
||||
'HKCU': win32con.HKEY_CURRENT_USER,
|
||||
'HKLM': win32con.HKEY_LOCAL_MACHINE,
|
||||
'HKU': win32con.HKEY_USERS,
|
||||
}
|
||||
self.vtype = {
|
||||
'REG_BINARY': _winreg.REG_BINARY,
|
||||
'REG_DWORD': _winreg.REG_DWORD,
|
||||
'REG_EXPAND_SZ': _winreg.REG_EXPAND_SZ,
|
||||
'REG_MULTI_SZ': _winreg.REG_MULTI_SZ,
|
||||
'REG_SZ': _winreg.REG_SZ
|
||||
'REG_BINARY': win32con.REG_BINARY,
|
||||
'REG_DWORD': win32con.REG_DWORD,
|
||||
'REG_EXPAND_SZ': win32con.REG_EXPAND_SZ,
|
||||
'REG_MULTI_SZ': win32con.REG_MULTI_SZ,
|
||||
'REG_SZ': win32con.REG_SZ,
|
||||
'REG_QWORD': win32con.REG_QWORD
|
||||
}
|
||||
self.opttype = {
|
||||
'REG_OPTION_NON_VOLATILE': _winreg.REG_OPTION_NON_VOLATILE,
|
||||
'REG_OPTION_VOLATILE': _winreg.REG_OPTION_VOLATILE
|
||||
'REG_OPTION_NON_VOLATILE': 0,
|
||||
'REG_OPTION_VOLATILE': 1
|
||||
}
|
||||
# Return Unicode due to from __future__ import unicode_literals
|
||||
self.vtype_reverse = {
|
||||
_winreg.REG_BINARY: 'REG_BINARY',
|
||||
_winreg.REG_DWORD: 'REG_DWORD',
|
||||
_winreg.REG_EXPAND_SZ: 'REG_EXPAND_SZ',
|
||||
_winreg.REG_MULTI_SZ: 'REG_MULTI_SZ',
|
||||
_winreg.REG_SZ: 'REG_SZ'
|
||||
win32con.REG_BINARY: 'REG_BINARY',
|
||||
win32con.REG_DWORD: 'REG_DWORD',
|
||||
win32con.REG_EXPAND_SZ: 'REG_EXPAND_SZ',
|
||||
win32con.REG_MULTI_SZ: 'REG_MULTI_SZ',
|
||||
win32con.REG_SZ: 'REG_SZ',
|
||||
win32con.REG_QWORD: 'REG_QWORD'
|
||||
}
|
||||
self.opttype_reverse = {
|
||||
_winreg.REG_OPTION_NON_VOLATILE: 'REG_OPTION_NON_VOLATILE',
|
||||
_winreg.REG_OPTION_VOLATILE: 'REG_OPTION_VOLATILE'
|
||||
0: 'REG_OPTION_NON_VOLATILE',
|
||||
1: 'REG_OPTION_VOLATILE'
|
||||
}
|
||||
# delete_key_recursive uses this to check the subkey contains enough \
|
||||
# as we do not want to remove all or most of the registry
|
||||
self.subkey_slash_check = {
|
||||
_winreg.HKEY_CURRENT_USER: 0,
|
||||
_winreg.HKEY_LOCAL_MACHINE: 1,
|
||||
_winreg.HKEY_USERS: 1
|
||||
win32con.HKEY_CURRENT_USER: 0,
|
||||
win32con.HKEY_LOCAL_MACHINE: 1,
|
||||
win32con.HKEY_USERS: 1
|
||||
}
|
||||
|
||||
self.registry_32 = {
|
||||
True: _winreg.KEY_READ | _winreg.KEY_WOW64_32KEY,
|
||||
False: _winreg.KEY_READ,
|
||||
True: win32con.KEY_READ | win32con.KEY_WOW64_32KEY,
|
||||
False: win32con.KEY_READ,
|
||||
}
|
||||
|
||||
def __getattr__(self, k):
|
||||
|
@ -189,21 +160,16 @@ def _key_exists(hive, key, use_32bit_registry=False):
|
|||
:return: Returns True if found, False if not found
|
||||
:rtype: bool
|
||||
'''
|
||||
|
||||
if PY2:
|
||||
local_hive = _mbcs_to_unicode(hive)
|
||||
local_key = _unicode_to_mbcs(key)
|
||||
else:
|
||||
local_hive = hive
|
||||
local_key = key
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
|
||||
try:
|
||||
handle = _winreg.OpenKey(hkey, local_key, 0, access_mask)
|
||||
_winreg.CloseKey(handle)
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
win32api.RegCloseKey(handle)
|
||||
return True
|
||||
except WindowsError: # pylint: disable=E0602
|
||||
return False
|
||||
|
@ -222,8 +188,9 @@ def broadcast_change():
|
|||
salt '*' reg.broadcast_change
|
||||
'''
|
||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms644952(v=vs.85).aspx
|
||||
_, res = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0,
|
||||
SMTO_ABORTIFHUNG, 5000)
|
||||
_, res = win32gui.SendMessageTimeout(
|
||||
win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 0,
|
||||
win32con.SMTO_ABORTIFHUNG, 5000)
|
||||
return not bool(res)
|
||||
|
||||
|
||||
|
@ -253,12 +220,8 @@ def list_keys(hive, key=None, use_32bit_registry=False):
|
|||
salt '*' reg.list_keys HKLM 'SOFTWARE'
|
||||
'''
|
||||
|
||||
if PY2:
|
||||
local_hive = _mbcs_to_unicode(hive)
|
||||
local_key = _unicode_to_mbcs(key)
|
||||
else:
|
||||
local_hive = hive
|
||||
local_key = key
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
|
@ -266,12 +229,12 @@ def list_keys(hive, key=None, use_32bit_registry=False):
|
|||
|
||||
subkeys = []
|
||||
try:
|
||||
handle = _winreg.OpenKey(hkey, local_key, 0, access_mask)
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
|
||||
for i in range(_winreg.QueryInfoKey(handle)[0]):
|
||||
subkey = _winreg.EnumKey(handle, i)
|
||||
for i in range(win32api.RegQueryInfoKey(handle)[0]):
|
||||
subkey = win32api.RegEnumKey(handle, i)
|
||||
if PY2:
|
||||
subkeys.append(_mbcs_to_unicode(subkey))
|
||||
subkeys.append(_to_unicode(subkey))
|
||||
else:
|
||||
subkeys.append(subkey)
|
||||
|
||||
|
@ -312,13 +275,8 @@ def list_values(hive, key=None, use_32bit_registry=False, include_default=True):
|
|||
|
||||
salt '*' reg.list_values HKLM 'SYSTEM\\CurrentControlSet\\Services\\Tcpip'
|
||||
'''
|
||||
|
||||
if PY2:
|
||||
local_hive = _mbcs_to_unicode(hive)
|
||||
local_key = _unicode_to_mbcs(key)
|
||||
else:
|
||||
local_hive = hive
|
||||
local_key = key
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
|
@ -327,37 +285,21 @@ def list_values(hive, key=None, use_32bit_registry=False, include_default=True):
|
|||
values = list()
|
||||
|
||||
try:
|
||||
handle = _winreg.OpenKey(hkey, local_key, 0, access_mask)
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
|
||||
for i in range(_winreg.QueryInfoKey(handle)[1]):
|
||||
vname, vdata, vtype = _winreg.EnumValue(handle, i)
|
||||
for i in range(win32api.RegQueryInfoKey(handle)[1]):
|
||||
vname, vdata, vtype = win32api.RegEnumValue(handle, i)
|
||||
|
||||
if not vname:
|
||||
vname = "(Default)"
|
||||
|
||||
value = {'hive': local_hive,
|
||||
'key': local_key,
|
||||
'vname': vname,
|
||||
'vdata': vdata,
|
||||
'vname': _to_mbcs(vname),
|
||||
'vdata': _to_mbcs(vdata),
|
||||
'vtype': registry.vtype_reverse[vtype],
|
||||
'success': True}
|
||||
values.append(value)
|
||||
if include_default:
|
||||
# Get the default value for the key
|
||||
value = {'hive': local_hive,
|
||||
'key': local_key,
|
||||
'vname': '(Default)',
|
||||
'vdata': None,
|
||||
'success': True}
|
||||
try:
|
||||
# QueryValueEx returns unicode data
|
||||
vdata, vtype = _winreg.QueryValueEx(handle, '(Default)')
|
||||
if vdata or vdata in [0, '']:
|
||||
value['vtype'] = registry.vtype_reverse[vtype]
|
||||
value['vdata'] = vdata
|
||||
else:
|
||||
value['comment'] = 'Empty Value'
|
||||
except WindowsError: # pylint: disable=E0602
|
||||
value['vdata'] = ('(value not set)')
|
||||
value['vtype'] = 'REG_SZ'
|
||||
values.append(value)
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.debug(exc)
|
||||
log.debug(r'Cannot find key: {0}\{1}'.format(hive, key))
|
||||
|
@ -403,30 +345,19 @@ def read_value(hive, key, vname=None, use_32bit_registry=False):
|
|||
|
||||
salt '*' reg.read_value HKEY_LOCAL_MACHINE 'SOFTWARE\Salt' 'version'
|
||||
'''
|
||||
|
||||
# If no name is passed, the default value of the key will be returned
|
||||
# The value name is Default
|
||||
|
||||
# Setup the return array
|
||||
if PY2:
|
||||
ret = {'hive': _mbcs_to_unicode(hive),
|
||||
'key': _mbcs_to_unicode(key),
|
||||
'vname': _mbcs_to_unicode(vname),
|
||||
'vdata': None,
|
||||
'success': True}
|
||||
local_hive = _mbcs_to_unicode(hive)
|
||||
local_key = _unicode_to_mbcs(key)
|
||||
local_vname = _unicode_to_mbcs(vname)
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
local_vname = _to_unicode(vname)
|
||||
|
||||
else:
|
||||
ret = {'hive': hive,
|
||||
'key': key,
|
||||
'vname': vname,
|
||||
'vdata': None,
|
||||
'success': True}
|
||||
local_hive = hive
|
||||
local_key = key
|
||||
local_vname = vname
|
||||
ret = {'hive': local_hive,
|
||||
'key': local_key,
|
||||
'vname': local_vname,
|
||||
'vdata': None,
|
||||
'success': True}
|
||||
|
||||
if not vname:
|
||||
ret['vname'] = '(Default)'
|
||||
|
@ -436,19 +367,22 @@ def read_value(hive, key, vname=None, use_32bit_registry=False):
|
|||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
|
||||
try:
|
||||
handle = _winreg.OpenKey(hkey, local_key, 0, access_mask)
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
try:
|
||||
# QueryValueEx returns unicode data
|
||||
vdata, vtype = _winreg.QueryValueEx(handle, local_vname)
|
||||
# RegQueryValueEx returns and accepts unicode data
|
||||
vdata, vtype = win32api.RegQueryValueEx(handle, local_vname)
|
||||
if vdata or vdata in [0, '']:
|
||||
ret['vtype'] = registry.vtype_reverse[vtype]
|
||||
ret['vdata'] = vdata
|
||||
if vtype == 7:
|
||||
ret['vdata'] = [_to_mbcs(i) for i in vdata]
|
||||
else:
|
||||
ret['vdata'] = _to_mbcs(vdata)
|
||||
else:
|
||||
ret['comment'] = 'Empty Value'
|
||||
except WindowsError: # pylint: disable=E0602
|
||||
ret['vdata'] = ('(value not set)')
|
||||
ret['vtype'] = 'REG_SZ'
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
except pywintypes.error as exc: # pylint: disable=E0602
|
||||
log.debug(exc)
|
||||
log.debug('Cannot find key: {0}\\{1}'.format(local_hive, local_key))
|
||||
ret['comment'] = 'Cannot find key: {0}\\{1}'.format(local_hive, local_key)
|
||||
|
@ -555,42 +489,47 @@ def set_value(hive,
|
|||
salt '*' reg.set_value HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' '2015.5.2' \\
|
||||
vtype=REG_LIST vdata='[a,b,c]'
|
||||
'''
|
||||
|
||||
if PY2:
|
||||
try:
|
||||
local_hive = _mbcs_to_unicode(hive)
|
||||
local_key = _mbcs_to_unicode(key)
|
||||
local_vname = _mbcs_to_unicode(vname)
|
||||
local_vtype = _mbcs_to_unicode(vtype)
|
||||
local_vdata = _mbcs_to_unicode_wrap(vdata, local_vtype)
|
||||
except TypeError as exc: # pylint: disable=E0602
|
||||
log.error(exc, exc_info=True)
|
||||
return False
|
||||
else:
|
||||
local_hive = hive
|
||||
local_key = key
|
||||
local_vname = vname
|
||||
local_vdata = vdata
|
||||
local_vtype = vtype
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
local_vname = _to_unicode(vname)
|
||||
local_vtype = _to_unicode(vtype)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
vtype_value = registry.vtype[local_vtype]
|
||||
access_mask = registry.registry_32[use_32bit_registry] | _winreg.KEY_ALL_ACCESS
|
||||
access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS
|
||||
|
||||
# Check data type and cast to expected type
|
||||
# int will automatically become long on 64bit numbers
|
||||
# https://www.python.org/dev/peps/pep-0237/
|
||||
|
||||
# String Types to Unicode
|
||||
if vtype_value in [1, 2]:
|
||||
local_vdata = _to_unicode(vdata)
|
||||
# Don't touch binary...
|
||||
elif vtype_value == 3:
|
||||
local_vdata = vdata
|
||||
# Make sure REG_MULTI_SZ is a list of strings
|
||||
elif vtype_value == 7:
|
||||
local_vdata = [_to_unicode(i) for i in vdata]
|
||||
# Everything else is int
|
||||
else:
|
||||
local_vdata = int(vdata)
|
||||
|
||||
if volatile:
|
||||
create_options = registry.opttype['REG_OPTION_VOLATILE']
|
||||
else:
|
||||
create_options = registry.opttype['REG_OPTION_NON_VOLATILE']
|
||||
|
||||
try:
|
||||
handle, _ = RegCreateKeyEx(hkey, local_key, access_mask,
|
||||
handle, _ = win32api.RegCreateKeyEx(hkey, local_key, access_mask,
|
||||
Options=create_options)
|
||||
RegSetValueEx(handle, local_vname, 0, vtype_value, local_vdata)
|
||||
RegFlushKey(handle)
|
||||
RegCloseKey(handle)
|
||||
win32api.RegSetValueEx(handle, local_vname, 0, vtype_value, local_vdata)
|
||||
win32api.RegFlushKey(handle)
|
||||
win32api.RegCloseKey(handle)
|
||||
broadcast_change()
|
||||
return True
|
||||
except (win32apiError, SystemError, ValueError, TypeError) as exc: # pylint: disable=E0602
|
||||
except (win32api.error, SystemError, ValueError, TypeError) as exc: # pylint: disable=E0602
|
||||
log.error(exc, exc_info=True)
|
||||
return False
|
||||
|
||||
|
@ -626,18 +565,14 @@ def delete_key_recursive(hive, key, use_32bit_registry=False):
|
|||
salt '*' reg.delete_key_recursive HKLM SOFTWARE\\salt
|
||||
'''
|
||||
|
||||
if PY2:
|
||||
local_hive = _mbcs_to_unicode(hive)
|
||||
local_key = _unicode_to_mbcs(key)
|
||||
else:
|
||||
local_hive = hive
|
||||
local_key = key
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
# Instantiate the registry object
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
key_path = local_key
|
||||
access_mask = registry.registry_32[use_32bit_registry] | _winreg.KEY_ALL_ACCESS
|
||||
access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS
|
||||
|
||||
if not _key_exists(local_hive, local_key, use_32bit_registry):
|
||||
return False
|
||||
|
@ -654,17 +589,17 @@ def delete_key_recursive(hive, key, use_32bit_registry=False):
|
|||
i = 0
|
||||
while True:
|
||||
try:
|
||||
subkey = _winreg.EnumKey(_key, i)
|
||||
subkey = win32api.RegEnumKey(_key, i)
|
||||
yield subkey
|
||||
i += 1
|
||||
except WindowsError: # pylint: disable=E0602
|
||||
except pywintypes.error: # pylint: disable=E0602
|
||||
break
|
||||
|
||||
def _traverse_registry_tree(_hkey, _keypath, _ret, _access_mask):
|
||||
'''
|
||||
Traverse the registry tree i.e. dive into the tree
|
||||
'''
|
||||
_key = _winreg.OpenKey(_hkey, _keypath, 0, _access_mask)
|
||||
_key = win32api.RegOpenKeyEx(_hkey, _keypath, 0, _access_mask)
|
||||
for subkeyname in _subkeys(_key):
|
||||
subkeypath = r'{0}\{1}'.format(_keypath, subkeyname)
|
||||
_ret = _traverse_registry_tree(_hkey, subkeypath, _ret, access_mask)
|
||||
|
@ -683,8 +618,8 @@ def delete_key_recursive(hive, key, use_32bit_registry=False):
|
|||
# Delete all sub_keys
|
||||
for sub_key_path in key_list:
|
||||
try:
|
||||
key_handle = _winreg.OpenKey(hkey, sub_key_path, 0, access_mask)
|
||||
_winreg.DeleteKey(key_handle, '')
|
||||
key_handle = win32api.RegOpenKeyEx(hkey, sub_key_path, 0, access_mask)
|
||||
win32api.RegDeleteKey(key_handle, '')
|
||||
ret['Deleted'].append(r'{0}\{1}'.format(hive, sub_key_path))
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.error(exc, exc_info=True)
|
||||
|
@ -723,23 +658,18 @@ def delete_value(hive, key, vname=None, use_32bit_registry=False):
|
|||
salt '*' reg.delete_value HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version'
|
||||
'''
|
||||
|
||||
if PY2:
|
||||
local_hive = _mbcs_to_unicode(hive)
|
||||
local_key = _unicode_to_mbcs(key)
|
||||
local_vname = _unicode_to_mbcs(vname)
|
||||
else:
|
||||
local_hive = hive
|
||||
local_key = key
|
||||
local_vname = vname
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
local_vname = _to_unicode(vname)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry] | _winreg.KEY_ALL_ACCESS
|
||||
access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS
|
||||
|
||||
try:
|
||||
handle = _winreg.OpenKey(hkey, local_key, 0, access_mask)
|
||||
_winreg.DeleteValue(handle, local_vname)
|
||||
_winreg.CloseKey(handle)
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
win32api.RegDeleteValue(handle, local_vname)
|
||||
win32api.RegCloseKey(handle)
|
||||
broadcast_change()
|
||||
return True
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
|
|
|
@ -689,9 +689,24 @@ def _parse_settings_eth(opts, iface_type, enabled, iface):
|
|||
if opt in opts:
|
||||
result[opt] = opts[opt]
|
||||
|
||||
for opt in ['ipaddrs', 'ipv6addrs']:
|
||||
if opt in opts:
|
||||
result[opt] = opts[opt]
|
||||
if 'ipaddrs' in opts:
|
||||
result['ipaddrs'] = []
|
||||
for opt in opts['ipaddrs']:
|
||||
if salt.utils.validate.net.ipv4_addr(opt):
|
||||
ip, prefix = [i.strip() for i in opt.split('/')]
|
||||
result['ipaddrs'].append({'ipaddr': ip, 'prefix': prefix})
|
||||
else:
|
||||
msg = 'ipv4 CIDR is invalid'
|
||||
log.error(msg)
|
||||
raise AttributeError(msg)
|
||||
|
||||
if 'ipv6addrs' in opts:
|
||||
for opt in opts['ipv6addrs']:
|
||||
if not salt.utils.validate.net.ipv6_addr(opt):
|
||||
msg = 'ipv6 CIDR is invalid'
|
||||
log.error(msg)
|
||||
raise AttributeError(msg)
|
||||
result['ipv6addrs'] = opts['ipv6addrs']
|
||||
|
||||
if 'enable_ipv6' in opts:
|
||||
result['enable_ipv6'] = opts['enable_ipv6']
|
||||
|
@ -1055,8 +1070,8 @@ def build_routes(iface, **settings):
|
|||
log.debug("IPv4 routes:\n{0}".format(opts4))
|
||||
log.debug("IPv6 routes:\n{0}".format(opts6))
|
||||
|
||||
routecfg = template.render(routes=opts4)
|
||||
routecfg6 = template.render(routes=opts6)
|
||||
routecfg = template.render(routes=opts4, iface=iface)
|
||||
routecfg6 = template.render(routes=opts6, iface=iface)
|
||||
|
||||
if settings['test']:
|
||||
routes = _read_temp(routecfg)
|
||||
|
|
|
@ -493,6 +493,18 @@ def apply_(mods=None,
|
|||
Values passed this way will override Pillar values set via
|
||||
``pillar_roots`` or an external Pillar source.
|
||||
|
||||
exclude
|
||||
Exclude specific states from execution. Accepts a list of sls names, a
|
||||
comma-separated string of sls names, or a list of dictionaries
|
||||
containing ``sls`` or ``id`` keys. Glob-patterns may be used to match
|
||||
multiple states.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' state.apply exclude=bar,baz
|
||||
salt '*' state.apply exclude=foo*
|
||||
salt '*' state.apply exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
|
||||
|
||||
queue : False
|
||||
Instead of failing immediately when another state run is in progress,
|
||||
queue the new state run to begin running once the other has finished.
|
||||
|
@ -755,6 +767,18 @@ def highstate(test=None, queue=False, **kwargs):
|
|||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
exclude
|
||||
Exclude specific states from execution. Accepts a list of sls names, a
|
||||
comma-separated string of sls names, or a list of dictionaries
|
||||
containing ``sls`` or ``id`` keys. Glob-patterns may be used to match
|
||||
multiple states.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' state.higstate exclude=bar,baz
|
||||
salt '*' state.higstate exclude=foo*
|
||||
salt '*' state.highstate exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
|
||||
|
||||
queue : False
|
||||
Instead of failing immediately when another state run is in progress,
|
||||
queue the new state run to begin running once the other has finished.
|
||||
|
@ -905,6 +929,18 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
|
|||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
exclude
|
||||
Exclude specific states from execution. Accepts a list of sls names, a
|
||||
comma-separated string of sls names, or a list of dictionaries
|
||||
containing ``sls`` or ``id`` keys. Glob-patterns may be used to match
|
||||
multiple states.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' state.sls foo,bar,baz exclude=bar,baz
|
||||
salt '*' state.sls foo,bar,baz exclude=ba*
|
||||
salt '*' state.sls foo,bar,baz exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
|
||||
|
||||
queue : False
|
||||
Instead of failing immediately when another state run is in progress,
|
||||
queue the new state run to begin running once the other has finished.
|
||||
|
|
|
@ -67,7 +67,7 @@ from salt.modules.file import (check_hash, # pylint: disable=W0611
|
|||
lstat, path_exists_glob, write, pardir, join, HASHES, HASHES_REVMAP,
|
||||
comment, uncomment, _add_flags, comment_line, _regex_to_static,
|
||||
_get_line_indent, apply_template_on_contents, dirname, basename,
|
||||
list_backups_dir)
|
||||
list_backups_dir, _assert_occurrence, _starts_till)
|
||||
from salt.modules.file import normpath as normpath_
|
||||
|
||||
from salt.utils import namespaced_function as _namespaced_function
|
||||
|
@ -98,7 +98,7 @@ def __virtual__():
|
|||
global write, pardir, join, _add_flags, apply_template_on_contents
|
||||
global path_exists_glob, comment, uncomment, _mkstemp_copy
|
||||
global _regex_to_static, _get_line_indent, dirname, basename
|
||||
global list_backups_dir, normpath_
|
||||
global list_backups_dir, normpath_, _assert_occurrence, _starts_till
|
||||
|
||||
replace = _namespaced_function(replace, globals())
|
||||
search = _namespaced_function(search, globals())
|
||||
|
@ -165,6 +165,8 @@ def __virtual__():
|
|||
basename = _namespaced_function(basename, globals())
|
||||
list_backups_dir = _namespaced_function(list_backups_dir, globals())
|
||||
normpath_ = _namespaced_function(normpath_, globals())
|
||||
_assert_occurrence = _namespaced_function(_assert_occurrence, globals())
|
||||
_starts_till = _namespaced_function(_starts_till, globals())
|
||||
|
||||
return __virtualname__
|
||||
return (False, "Module win_file: module only works on Windows systems")
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -69,33 +69,33 @@ def halt(timeout=5, in_seconds=False):
|
|||
'''
|
||||
Halt a running system.
|
||||
|
||||
:param int timeout:
|
||||
Number of seconds before halting the system.
|
||||
Default is 5 seconds.
|
||||
Args:
|
||||
|
||||
:return: True is successful.
|
||||
:rtype: bool
|
||||
timeout (int):
|
||||
Number of seconds before halting the system. Default is 5 seconds.
|
||||
|
||||
timeout
|
||||
The wait time before the system will be shutdown.
|
||||
|
||||
in_seconds
|
||||
Whether to treat timeout as seconds or minutes.
|
||||
in_seconds (bool):
|
||||
Whether to treat timeout as seconds or minutes.
|
||||
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' system.halt 5
|
||||
salt '*' system.halt 5 True
|
||||
'''
|
||||
return shutdown(timeout=timeout, in_seconds=in_seconds)
|
||||
|
||||
|
||||
def init(runlevel): # pylint: disable=unused-argument
|
||||
'''
|
||||
Change the system runlevel on sysV compatible systems
|
||||
Change the system runlevel on sysV compatible systems. Not applicable to
|
||||
Windows
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -117,20 +117,19 @@ def poweroff(timeout=5, in_seconds=False):
|
|||
'''
|
||||
Power off a running system.
|
||||
|
||||
:param int timeout:
|
||||
Number of seconds before powering off the system.
|
||||
Default is 5 seconds.
|
||||
Args:
|
||||
|
||||
:return: True if successful
|
||||
:rtype: bool
|
||||
timeout (int):
|
||||
Number of seconds before powering off the system. Default is 5
|
||||
seconds.
|
||||
|
||||
timeout
|
||||
The wait time before the system will be shutdown.
|
||||
in_seconds (bool):
|
||||
Whether to treat timeout as seconds or minutes.
|
||||
|
||||
in_seconds
|
||||
Whether to treat timeout as seconds or minutes.
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
.. versionadded:: 2015.8.0
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -146,35 +145,36 @@ def reboot(timeout=5, in_seconds=False, wait_for_reboot=False, # pylint: disabl
|
|||
'''
|
||||
Reboot a running system.
|
||||
|
||||
:param int timeout:
|
||||
Number of minutes/seconds before rebooting the system. Minutes vs
|
||||
seconds depends on the value of ``in_seconds``.
|
||||
Default is 5 minutes.
|
||||
Args:
|
||||
|
||||
:param bool in_seconds:
|
||||
Whether to treat timeout as seconds or minutes.
|
||||
timeout (int):
|
||||
The number of minutes/seconds before rebooting the system. Use of
|
||||
minutes or seconds depends on the value of ``in_seconds``. Default
|
||||
is 5 minutes.
|
||||
|
||||
.. versionadded:: 2015.8.0
|
||||
in_seconds (bool):
|
||||
``True`` will cause the ``timeout`` parameter to be in seconds.
|
||||
``False`` will be in minutes. Default is ``False``.
|
||||
|
||||
:param bool wait_for_reboot:
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
Sleeps for timeout + 30 seconds after reboot has been initiated.
|
||||
This is useful for use in a highstate for example where
|
||||
you have many states that could be ran after this one. Which you don't want
|
||||
to start until after the restart i.e You could end up with a half finished state.
|
||||
wait_for_reboot (bool)
|
||||
``True`` will sleep for timeout + 30 seconds after reboot has been
|
||||
initiated. This is useful for use in a highstate. For example, you
|
||||
may have states that you want to apply only after the reboot.
|
||||
Default is ``False``.
|
||||
|
||||
.. versionadded:: 2015.8.0
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
:param bool only_on_pending_reboot:
|
||||
only_on_pending_reboot (bool):
|
||||
If this is set to ``True``, then then the reboot will only proceed
|
||||
if the system reports a pending reboot. Setting this parameter to
|
||||
``True`` could be useful when calling this function from a final
|
||||
housekeeping state intended to be executed at the end of a state run
|
||||
(using *order: last*). Default is ``False``.
|
||||
|
||||
If this is set to True, then then the reboot will only proceed
|
||||
if the system reports a pending reboot. Setting this parameter to
|
||||
True could be useful when calling this function from a final housekeeping
|
||||
state intended to be executed
|
||||
at the end of a state run (using *order: last*).
|
||||
|
||||
:return: True if successful (a reboot will occur)
|
||||
:rtype: bool
|
||||
Returns:
|
||||
bool: ``True`` if successful (a reboot will occur), otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -183,21 +183,16 @@ def reboot(timeout=5, in_seconds=False, wait_for_reboot=False, # pylint: disabl
|
|||
salt '*' system.reboot 5
|
||||
salt '*' system.reboot 5 True
|
||||
|
||||
As example of invoking this function from within a final housekeeping state
|
||||
is as follows:
|
||||
|
||||
Example:
|
||||
Invoking this function from a final housekeeping state:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
final housekeeping:
|
||||
final_housekeeping:
|
||||
module.run:
|
||||
- name: system.reboot
|
||||
- only_on_pending_reboot: True
|
||||
- order: last
|
||||
|
||||
'''
|
||||
|
||||
ret = shutdown(timeout=timeout, reboot=True, in_seconds=in_seconds,
|
||||
only_on_pending_reboot=only_on_pending_reboot)
|
||||
|
||||
|
@ -213,52 +208,59 @@ def shutdown(message=None, timeout=5, force_close=True, reboot=False, # pylint:
|
|||
'''
|
||||
Shutdown a running system.
|
||||
|
||||
:param str message:
|
||||
A message to display to the user before shutting down.
|
||||
Args:
|
||||
|
||||
:param int timeout:
|
||||
The length of time that the shutdown dialog box should be displayed, in
|
||||
seconds. While this dialog box is displayed, the shutdown can be stopped
|
||||
by the shutdown_abort function.
|
||||
message (str):
|
||||
The message to display to the user before shutting down.
|
||||
|
||||
If timeout is not zero, InitiateSystemShutdown displays a dialog box on
|
||||
the specified computer. The dialog box displays the name of the user
|
||||
who called the function, displays the message specified by the
|
||||
lpMessage parameter, and prompts the user to log off. The dialog box
|
||||
beeps when it is created and remains on top of other windows in the
|
||||
system. The dialog box can be moved but not closed. A timer counts down
|
||||
the remaining time before a forced shutdown.
|
||||
timeout (int):
|
||||
The length of time (in seconds) that the shutdown dialog box should
|
||||
be displayed. While this dialog box is displayed, the shutdown can
|
||||
be aborted using the ``system.shutdown_abort`` function.
|
||||
|
||||
If timeout is zero, the computer shuts down without displaying the
|
||||
dialog box, and the shutdown cannot be stopped by shutdown_abort.
|
||||
If timeout is not zero, InitiateSystemShutdown displays a dialog box
|
||||
on the specified computer. The dialog box displays the name of the
|
||||
user who called the function, the message specified by the lpMessage
|
||||
parameter, and prompts the user to log off. The dialog box beeps
|
||||
when it is created and remains on top of other windows (system
|
||||
modal). The dialog box can be moved but not closed. A timer counts
|
||||
down the remaining time before the shutdown occurs.
|
||||
|
||||
Default is 5 minutes
|
||||
If timeout is zero, the computer shuts down immediately without
|
||||
displaying the dialog box and cannot be stopped by
|
||||
``system.shutdown_abort``.
|
||||
|
||||
:param bool in_seconds:
|
||||
Whether to treat timeout as seconds or minutes.
|
||||
Default is 5 minutes
|
||||
|
||||
.. versionadded:: 2015.8.0
|
||||
in_seconds (bool):
|
||||
``True`` will cause the ``timeout`` parameter to be in seconds.
|
||||
``False`` will be in minutes. Default is ``False``.
|
||||
|
||||
:param bool force_close:
|
||||
True to force close all open applications. False displays a dialog box
|
||||
instructing the user to close the applications.
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
:param bool reboot:
|
||||
True restarts the computer immediately after shutdown.
|
||||
False caches to disk and safely powers down the system.
|
||||
force_close (bool):
|
||||
``True`` will force close all open applications. ``False`` will
|
||||
display a dialog box instructing the user to close open
|
||||
applications. Default is ``True``.
|
||||
|
||||
:param bool only_on_pending_reboot:
|
||||
If this is set to True, then then shutdown will only proceed
|
||||
if the system reports a pending reboot.
|
||||
reboot (bool):
|
||||
``True`` restarts the computer immediately after shutdown. ``False``
|
||||
powers down the system. Default is ``False``.
|
||||
|
||||
:return: True if successful (a shutdown or reboot will occur)
|
||||
:rtype: bool
|
||||
only_on_pending_reboot (bool):
|
||||
If ``True`` the shutdown will only proceed if there is a reboot
|
||||
pending. ``False`` will shutdown the system. Default is ``False``.
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
``True`` if successful (a shutdown or reboot will occur), otherwise
|
||||
``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' system.shutdown 5
|
||||
salt '*' system.shutdown "System will shutdown in 5 minutes"
|
||||
'''
|
||||
timeout = _convert_minutes_seconds(timeout, in_seconds)
|
||||
|
||||
|
@ -284,8 +286,8 @@ def shutdown_hard():
|
|||
'''
|
||||
Shutdown a running system with no timeout or warning.
|
||||
|
||||
:return: True if successful
|
||||
:rtype: bool
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -301,8 +303,8 @@ def shutdown_abort():
|
|||
Abort a shutdown. Only available while the dialog box is being
|
||||
displayed to the user. Once the shutdown has initiated, it cannot be aborted
|
||||
|
||||
:return: True if successful
|
||||
:rtype: bool
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -326,8 +328,8 @@ def lock():
|
|||
'''
|
||||
Lock the workstation.
|
||||
|
||||
:return: True if successful
|
||||
:rtype: bool
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -342,12 +344,15 @@ def set_computer_name(name):
|
|||
'''
|
||||
Set the Windows computer name
|
||||
|
||||
:param str name:
|
||||
The new name to give the computer. Requires a reboot to take effect.
|
||||
Args:
|
||||
|
||||
:return:
|
||||
Returns a dictionary containing the old and new names if successful.
|
||||
False if not.
|
||||
name (str):
|
||||
The new name to give the computer. Requires a reboot to take effect.
|
||||
|
||||
Returns:
|
||||
dict:
|
||||
Returns a dictionary containing the old and new names if successful.
|
||||
``False`` if not.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -376,9 +381,10 @@ def get_pending_computer_name():
|
|||
retrieving the pending computer name, ``False`` will be returned, and an
|
||||
error message will be logged to the minion log.
|
||||
|
||||
:return:
|
||||
Returns the pending name if pending restart. Returns none if not pending
|
||||
restart.
|
||||
Returns:
|
||||
str:
|
||||
Returns the pending name if pending restart. Returns ``None`` if not
|
||||
pending restart.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -400,8 +406,8 @@ def get_computer_name():
|
|||
'''
|
||||
Get the Windows computer name
|
||||
|
||||
:return:
|
||||
Returns the computer name if found. Otherwise returns False
|
||||
Returns:
|
||||
str: Returns the computer name if found. Otherwise returns ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -417,10 +423,13 @@ def set_computer_desc(desc=None):
|
|||
'''
|
||||
Set the Windows computer description
|
||||
|
||||
:param str desc:
|
||||
The computer description
|
||||
Args:
|
||||
|
||||
:return: False if it fails. Description if successful.
|
||||
desc (str):
|
||||
The computer description
|
||||
|
||||
Returns:
|
||||
str: Description if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -460,10 +469,9 @@ def get_system_info():
|
|||
'''
|
||||
Get system information.
|
||||
|
||||
:return:
|
||||
Returns a Dictionary containing information about the system to include
|
||||
Returns:
|
||||
dict: Dictionary containing information about the system to include
|
||||
name, description, version, etc...
|
||||
:rtype: dict
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -514,8 +522,10 @@ def get_system_info():
|
|||
def get_computer_desc():
|
||||
'''
|
||||
Get the Windows computer description
|
||||
:return:
|
||||
Returns the computer description if found. Otherwise returns False
|
||||
|
||||
Returns:
|
||||
str: Returns the computer description if found. Otherwise returns
|
||||
``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -532,12 +542,12 @@ get_computer_description = salt.utils.alias_function(get_computer_desc, 'get_com
|
|||
|
||||
def get_hostname():
|
||||
'''
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
Get the hostname of the windows minion
|
||||
|
||||
:return:
|
||||
Returns the hostname of the windows minion
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
Returns:
|
||||
str: Returns the hostname of the windows minion
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -552,13 +562,16 @@ def get_hostname():
|
|||
|
||||
def set_hostname(hostname):
|
||||
'''
|
||||
Set the hostname of the windows minion, requires a restart before this will
|
||||
be updated.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
Set the hostname of the windows minion, requires a restart before this
|
||||
will be updated.
|
||||
Args:
|
||||
hostname (str): The hostname to set
|
||||
|
||||
:param str hostname:
|
||||
The hostname to set
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -580,37 +593,41 @@ def join_domain(domain,
|
|||
account_exists=False,
|
||||
restart=False):
|
||||
'''
|
||||
Join a computer to an Active Directory domain. Requires reboot.
|
||||
Join a computer to an Active Directory domain. Requires a reboot.
|
||||
|
||||
:param str domain:
|
||||
The domain to which the computer should be joined, e.g.
|
||||
``example.com``
|
||||
Args:
|
||||
|
||||
:param str username:
|
||||
Username of an account which is authorized to join computers to the
|
||||
specified domain. Need to be either fully qualified like
|
||||
``user@domain.tld`` or simply ``user``
|
||||
domain (str):
|
||||
The domain to which the computer should be joined, e.g.
|
||||
``example.com``
|
||||
|
||||
:param str password:
|
||||
Password of the specified user
|
||||
username (str):
|
||||
Username of an account which is authorized to join computers to the
|
||||
specified domain. Needs to be either fully qualified like
|
||||
``user@domain.tld`` or simply ``user``
|
||||
|
||||
:param str account_ou:
|
||||
The DN of the OU below which the account for this computer should be
|
||||
created when joining the domain, e.g.
|
||||
``ou=computers,ou=departm_432,dc=my-company,dc=com``
|
||||
password (str):
|
||||
Password of the specified user
|
||||
|
||||
:param bool account_exists:
|
||||
If set to ``True`` the computer will only join the domain if the account
|
||||
already exists. If set to ``False`` the computer account will be created
|
||||
if it does not exist, otherwise it will use the existing account.
|
||||
Default is False
|
||||
account_ou (str):
|
||||
The DN of the OU below which the account for this computer should be
|
||||
created when joining the domain, e.g.
|
||||
``ou=computers,ou=departm_432,dc=my-company,dc=com``
|
||||
|
||||
:param bool restart: Restarts the computer after a successful join
|
||||
account_exists (bool):
|
||||
If set to ``True`` the computer will only join the domain if the
|
||||
account already exists. If set to ``False`` the computer account
|
||||
will be created if it does not exist, otherwise it will use the
|
||||
existing account. Default is ``False``
|
||||
|
||||
.. versionadded:: 2015.8.2/2015.5.7
|
||||
restart (bool):
|
||||
``True`` will restart the computer after a successful join. Default
|
||||
is ``False``
|
||||
|
||||
:returns: Returns a dictionary if successful. False if unsuccessful.
|
||||
:rtype: dict, bool
|
||||
.. versionadded:: 2015.8.2/2015.5.7
|
||||
|
||||
Returns:
|
||||
dict: Returns a dictionary if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -678,34 +695,41 @@ def unjoin_domain(username=None,
|
|||
disable=False,
|
||||
restart=False):
|
||||
r'''
|
||||
Unjoin a computer from an Active Directory Domain. Requires restart.
|
||||
Unjoin a computer from an Active Directory Domain. Requires a restart.
|
||||
|
||||
:param username:
|
||||
Username of an account which is authorized to manage computer accounts
|
||||
on the domain. Need to be fully qualified like ``user@domain.tld`` or
|
||||
``domain.tld\user``. If domain not specified, the passed domain will be
|
||||
used. If computer account doesn't need to be disabled, can be None.
|
||||
Args:
|
||||
|
||||
:param str password:
|
||||
Password of the specified user
|
||||
username (str):
|
||||
Username of an account which is authorized to manage computer
|
||||
accounts on the domain. Needs to be a fully qualified name like
|
||||
``user@domain.tld`` or ``domain.tld\user``. If the domain is not
|
||||
specified, the passed domain will be used. If the computer account
|
||||
doesn't need to be disabled after the computer is unjoined, this can
|
||||
be ``None``.
|
||||
|
||||
:param str domain: The domain from which to unjoin the computer. Can be None
|
||||
password (str):
|
||||
The password of the specified user
|
||||
|
||||
:param str workgroup: The workgroup to join the computer to. Default is
|
||||
``WORKGROUP``
|
||||
domain (str):
|
||||
The domain from which to unjoin the computer. Can be ``None``
|
||||
|
||||
.. versionadded:: 2015.8.2/2015.5.7
|
||||
workgroup (str):
|
||||
The workgroup to join the computer to. Default is ``WORKGROUP``
|
||||
|
||||
:param bool disable:
|
||||
Disable the computer account in Active Directory. True to disable.
|
||||
Default is False
|
||||
.. versionadded:: 2015.8.2/2015.5.7
|
||||
|
||||
:param bool restart: Restart the computer after successful unjoin
|
||||
disable (bool):
|
||||
``True`` to disable the computer account in Active Directory.
|
||||
Default is ``False``
|
||||
|
||||
.. versionadded:: 2015.8.2/2015.5.7
|
||||
restart (bool):
|
||||
``True`` will restart the computer after successful unjoin. Default
|
||||
is ``False``
|
||||
|
||||
:returns: Returns a dictionary if successful. False if unsuccessful.
|
||||
:rtype: dict, bool
|
||||
.. versionadded:: 2015.8.2/2015.5.7
|
||||
|
||||
Returns:
|
||||
dict: Returns a dictionary if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -772,8 +796,8 @@ def get_domain_workgroup():
|
|||
.. versionadded:: 2015.5.7
|
||||
.. versionadded:: 2015.8.2
|
||||
|
||||
:return: The name of the domain or workgroup
|
||||
:rtype: str
|
||||
Returns:
|
||||
str: The name of the domain or workgroup
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -793,13 +817,16 @@ def get_domain_workgroup():
|
|||
|
||||
def _try_parse_datetime(time_str, fmts):
|
||||
'''
|
||||
Attempts to parse the input time_str as a date.
|
||||
A helper function that attempts to parse the input time_str as a date.
|
||||
|
||||
:param str time_str: A string representing the time
|
||||
:param list fmts: A list of date format strings
|
||||
Args:
|
||||
|
||||
:return: Returns a datetime object if parsed properly. Otherwise None
|
||||
:rtype datetime
|
||||
time_str (str): A string representing the time
|
||||
|
||||
fmts (list): A list of date format strings
|
||||
|
||||
Returns:
|
||||
datetime: Returns a datetime object if parsed properly, otherwise None
|
||||
'''
|
||||
result = None
|
||||
for fmt in fmts:
|
||||
|
@ -815,8 +842,8 @@ def get_system_time():
|
|||
'''
|
||||
Get the system time.
|
||||
|
||||
:return: Returns the system time in HH:MM:SS AM/PM format.
|
||||
:rtype: str
|
||||
Returns:
|
||||
str: Returns the system time in HH:MM:SS AM/PM format.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -841,15 +868,17 @@ def set_system_time(newtime):
|
|||
'''
|
||||
Set the system time.
|
||||
|
||||
:param str newtime:
|
||||
The time to set. Can be any of the following formats.
|
||||
- HH:MM:SS AM/PM
|
||||
- HH:MM AM/PM
|
||||
- HH:MM:SS (24 hour)
|
||||
- HH:MM (24 hour)
|
||||
Args:
|
||||
|
||||
:return: Returns True if successful. Otherwise False.
|
||||
:rtype: bool
|
||||
newtime (str):
|
||||
The time to set. Can be any of the following formats:
|
||||
- HH:MM:SS AM/PM
|
||||
- HH:MM AM/PM
|
||||
- HH:MM:SS (24 hour)
|
||||
- HH:MM (24 hour)
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -881,15 +910,17 @@ def set_system_date_time(years=None,
|
|||
element will be used. For example, if you don't pass the year, the current
|
||||
system year will be used. (Used by set_system_date and set_system_time)
|
||||
|
||||
:param int years: Years digit, ie: 2015
|
||||
:param int months: Months digit: 1 - 12
|
||||
:param int days: Days digit: 1 - 31
|
||||
:param int hours: Hours digit: 0 - 23
|
||||
:param int minutes: Minutes digit: 0 - 59
|
||||
:param int seconds: Seconds digit: 0 - 59
|
||||
Args:
|
||||
|
||||
:return: True if successful. Otherwise False.
|
||||
:rtype: bool
|
||||
years (int): Years digit, ie: 2015
|
||||
months (int): Months digit: 1 - 12
|
||||
days (int): Days digit: 1 - 31
|
||||
hours (int): Hours digit: 0 - 23
|
||||
minutes (int): Minutes digit: 0 - 59
|
||||
seconds (int): Seconds digit: 0 - 59
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -954,8 +985,8 @@ def get_system_date():
|
|||
'''
|
||||
Get the Windows system date
|
||||
|
||||
:return: Returns the system date.
|
||||
:rtype: str
|
||||
Returns:
|
||||
str: Returns the system date
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -971,14 +1002,18 @@ def set_system_date(newdate):
|
|||
'''
|
||||
Set the Windows system date. Use <mm-dd-yy> format for the date.
|
||||
|
||||
:param str newdate:
|
||||
The date to set. Can be any of the following formats
|
||||
- YYYY-MM-DD
|
||||
- MM-DD-YYYY
|
||||
- MM-DD-YY
|
||||
- MM/DD/YYYY
|
||||
- MM/DD/YY
|
||||
- YYYY/MM/DD
|
||||
Args:
|
||||
newdate (str):
|
||||
The date to set. Can be any of the following formats
|
||||
- YYYY-MM-DD
|
||||
- MM-DD-YYYY
|
||||
- MM-DD-YY
|
||||
- MM/DD/YYYY
|
||||
- MM/DD/YY
|
||||
- YYYY/MM/DD
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -1003,8 +1038,8 @@ def start_time_service():
|
|||
'''
|
||||
Start the Windows time service
|
||||
|
||||
:return: True if successful. Otherwise False
|
||||
:rtype: bool
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -1019,8 +1054,8 @@ def stop_time_service():
|
|||
'''
|
||||
Stop the Windows time service
|
||||
|
||||
:return: True if successful. Otherwise False
|
||||
:rtype: bool
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -1033,13 +1068,15 @@ def stop_time_service():
|
|||
|
||||
def get_pending_component_servicing():
|
||||
'''
|
||||
Determine whether there are pending Component Based Servicing tasks that require a reboot.
|
||||
|
||||
:return: A boolean representing whether there are pending Component Based Servicing tasks.
|
||||
:rtype: bool
|
||||
Determine whether there are pending Component Based Servicing tasks that
|
||||
require a reboot.
|
||||
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if there are pending Component Based Servicing tasks,
|
||||
otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -1062,13 +1099,15 @@ def get_pending_component_servicing():
|
|||
|
||||
def get_pending_domain_join():
|
||||
'''
|
||||
Determine whether there is a pending domain join action that requires a reboot.
|
||||
|
||||
:return: A boolean representing whether there is a pending domain join action.
|
||||
:rtype: bool
|
||||
Determine whether there is a pending domain join action that requires a
|
||||
reboot.
|
||||
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if there is a pending domain join action, otherwise
|
||||
``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -1103,13 +1142,15 @@ def get_pending_domain_join():
|
|||
|
||||
def get_pending_file_rename():
|
||||
'''
|
||||
Determine whether there are pending file rename operations that require a reboot.
|
||||
|
||||
:return: A boolean representing whether there are pending file rename operations.
|
||||
:rtype: bool
|
||||
Determine whether there are pending file rename operations that require a
|
||||
reboot.
|
||||
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if there are pending file rename operations, otherwise
|
||||
``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -1137,13 +1178,15 @@ def get_pending_file_rename():
|
|||
|
||||
def get_pending_servermanager():
|
||||
'''
|
||||
Determine whether there are pending Server Manager tasks that require a reboot.
|
||||
|
||||
:return: A boolean representing whether there are pending Server Manager tasks.
|
||||
:rtype: bool
|
||||
Determine whether there are pending Server Manager tasks that require a
|
||||
reboot.
|
||||
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if there are pending Server Manager tasks, otherwise
|
||||
``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -1176,11 +1219,11 @@ def get_pending_update():
|
|||
'''
|
||||
Determine whether there are pending updates that require a reboot.
|
||||
|
||||
:return: A boolean representing whether there are pending updates.
|
||||
:rtype: bool
|
||||
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if there are pending updates, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -1209,28 +1252,24 @@ REBOOT_REQUIRED_NAME = 'Reboot required'
|
|||
|
||||
def set_reboot_required_witnessed():
|
||||
r'''
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
This function is used to remember that
|
||||
an event indicating that a reboot is required was witnessed.
|
||||
This function relies on the salt-minion's ability to create the following
|
||||
volatile registry key in the *HKLM* hive:
|
||||
This function is used to remember that an event indicating that a reboot is
|
||||
required was witnessed. This function relies on the salt-minion's ability to
|
||||
create the following volatile registry key in the *HKLM* hive:
|
||||
|
||||
*SYSTEM\\CurrentControlSet\\Services\\salt-minion\\Volatile-Data*
|
||||
|
||||
Because this registry key is volatile, it will not persist
|
||||
beyond the current boot session.
|
||||
Also, in the scope of this key, the name *'Reboot required'* will be
|
||||
assigned the value of *1*.
|
||||
Because this registry key is volatile, it will not persist beyond the
|
||||
current boot session. Also, in the scope of this key, the name *'Reboot
|
||||
required'* will be assigned the value of *1*.
|
||||
|
||||
(For the time being, this this function is being used
|
||||
whenever an install completes with exit code 3010 and
|
||||
this usage can be extended where appropriate in the future.)
|
||||
For the time being, this function is being used whenever an install
|
||||
completes with exit code 3010 and can be extended where appropriate in the
|
||||
future.
|
||||
|
||||
:return: A boolean indicating whether or not the salt minion was
|
||||
able to perform the necessary registry operations.
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
:rtype: bool
|
||||
Returns:
|
||||
bool: ``True`` if successful, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -1249,20 +1288,18 @@ def set_reboot_required_witnessed():
|
|||
|
||||
def get_reboot_required_witnessed():
|
||||
'''
|
||||
Determine if at any time during the current boot session the salt minion
|
||||
witnessed an event indicating that a reboot is required.
|
||||
|
||||
This function will return ``True`` if an install completed with exit
|
||||
code 3010 during the current boot session and can be extended where
|
||||
appropriate in the future.
|
||||
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
This tells us if, at any time during the current boot session
|
||||
the salt minion witnessed an event indicating
|
||||
that a reboot is required.
|
||||
(For the time being, this function will return True
|
||||
if an install completed with exit code 3010 during the current
|
||||
boot session and this usage can be extended where appropriate
|
||||
in the future)
|
||||
|
||||
:return: a boolean which will be True if the salt-minion reported
|
||||
a required reboot during the current boot session, otherwise False.
|
||||
|
||||
:rtype: bool
|
||||
Returns:
|
||||
bool: ``True`` if the ``Requires reboot`` registry flag is set to ``1``,
|
||||
otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -1281,11 +1318,11 @@ def get_pending_reboot():
|
|||
'''
|
||||
Determine whether there is a reboot pending.
|
||||
|
||||
:return: A boolean representing whether reboots are pending.
|
||||
:rtype: bool
|
||||
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if the system is pending reboot, otherwise ``False``
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
|
|
@ -106,6 +106,13 @@ A REST API for Salt
|
|||
expire_responses : True
|
||||
Whether to check for and kill HTTP responses that have exceeded the
|
||||
default timeout.
|
||||
|
||||
.. deprecated:: 2016.11.9, 2017.7.3, Oxygen
|
||||
|
||||
The "expire_responses" configuration setting, which corresponds
|
||||
to the ``timeout_monitor`` setting in CherryPy, is no longer
|
||||
supported in CherryPy versions >= 12.0.0.
|
||||
|
||||
max_request_body_size : ``1048576``
|
||||
Maximum size for the HTTP request body.
|
||||
collect_stats : False
|
||||
|
@ -490,6 +497,8 @@ import salt.ext.six as six
|
|||
# Import Salt libs
|
||||
import salt
|
||||
import salt.auth
|
||||
import salt.exceptions
|
||||
import salt.utils
|
||||
import salt.utils.event
|
||||
|
||||
# Import salt-api libs
|
||||
|
@ -734,7 +743,8 @@ def hypermedia_handler(*args, **kwargs):
|
|||
except (salt.exceptions.SaltDaemonNotRunning,
|
||||
salt.exceptions.SaltReqTimeoutError) as exc:
|
||||
raise cherrypy.HTTPError(503, exc.strerror)
|
||||
except (cherrypy.TimeoutError, salt.exceptions.SaltClientTimeout):
|
||||
except (cherrypy.TimeoutError if hasattr(cherrypy, 'TimeoutError') else None,
|
||||
salt.exceptions.SaltClientTimeout):
|
||||
raise cherrypy.HTTPError(504)
|
||||
except cherrypy.CherryPyException:
|
||||
raise
|
||||
|
@ -2548,8 +2558,6 @@ class API(object):
|
|||
'server.socket_port': self.apiopts.get('port', 8000),
|
||||
'server.thread_pool': self.apiopts.get('thread_pool', 100),
|
||||
'server.socket_queue_size': self.apiopts.get('queue_size', 30),
|
||||
'engine.timeout_monitor.on': self.apiopts.get(
|
||||
'expire_responses', True),
|
||||
'max_request_body_size': self.apiopts.get(
|
||||
'max_request_body_size', 1048576),
|
||||
'debug': self.apiopts.get('debug', False),
|
||||
|
@ -2567,6 +2575,14 @@ class API(object):
|
|||
},
|
||||
}
|
||||
|
||||
if salt.utils.version_cmp(cherrypy.__version__, '12.0.0') < 0:
|
||||
# CherryPy >= 12.0 no longer supports "timeout_monitor", only set
|
||||
# this config option when using an older version of CherryPy.
|
||||
# See Issue #44601 for more information.
|
||||
conf['global']['engine.timeout_monitor.on'] = self.apiopts.get(
|
||||
'expire_responses', True
|
||||
)
|
||||
|
||||
if cpstats and self.apiopts.get('collect_stats', False):
|
||||
conf['/']['tools.cpstats.on'] = True
|
||||
|
||||
|
|
|
@ -142,6 +142,17 @@ def get_printout(out, opts=None, **kwargs):
|
|||
# See Issue #29796 for more information.
|
||||
out = opts['output']
|
||||
|
||||
# Handle setting the output when --static is passed.
|
||||
if not out and opts.get('static'):
|
||||
if opts.get('output'):
|
||||
out = opts['output']
|
||||
elif opts.get('fun', '').split('.')[0] == 'state':
|
||||
# --static doesn't have an output set at this point, but if we're
|
||||
# running a state function and "out" hasn't already been set, we
|
||||
# should set the out variable to "highstate". Otherwise state runs
|
||||
# are set to "nested" below. See Issue #44556 for more information.
|
||||
out = 'highstate'
|
||||
|
||||
if out == 'text':
|
||||
out = 'txt'
|
||||
elif out is None or out == '':
|
||||
|
|
|
@ -254,14 +254,14 @@ def returner(ret):
|
|||
with _get_serv(ret, commit=True) as cur:
|
||||
sql = '''INSERT INTO salt_returns
|
||||
(fun, jid, return, id, success, full_ret, alter_time)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s)'''
|
||||
VALUES (%s, %s, %s, %s, %s, %s, to_timestamp(%s))'''
|
||||
|
||||
cur.execute(sql, (ret['fun'], ret['jid'],
|
||||
psycopg2.extras.Json(ret['return']),
|
||||
ret['id'],
|
||||
ret.get('success', False),
|
||||
psycopg2.extras.Json(ret),
|
||||
time.strftime('%Y-%m-%d %H:%M:%S %z', time.localtime())))
|
||||
time.time()))
|
||||
except salt.exceptions.SaltMasterError:
|
||||
log.critical('Could not store return with pgjsonb returner. PostgreSQL server unavailable.')
|
||||
|
||||
|
@ -278,9 +278,9 @@ def event_return(events):
|
|||
tag = event.get('tag', '')
|
||||
data = event.get('data', '')
|
||||
sql = '''INSERT INTO salt_events (tag, data, master_id, alter_time)
|
||||
VALUES (%s, %s, %s, %s)'''
|
||||
VALUES (%s, %s, %s, to_timestamp(%s))'''
|
||||
cur.execute(sql, (tag, psycopg2.extras.Json(data),
|
||||
__opts__['id'], time.strftime('%Y-%m-%d %H:%M:%S %z', time.localtime())))
|
||||
__opts__['id'], time.time()))
|
||||
|
||||
|
||||
def save_load(jid, load, minions=None):
|
||||
|
|
|
@ -662,7 +662,7 @@ class State(object):
|
|||
.format(', '.join(VALID_PILLAR_ENC))
|
||||
)
|
||||
self._pillar_enc = pillar_enc
|
||||
if initial_pillar is not None:
|
||||
if initial_pillar:
|
||||
self.opts['pillar'] = initial_pillar
|
||||
if self._pillar_override:
|
||||
self.opts['pillar'] = salt.utils.dictupdate.merge(
|
||||
|
|
|
@ -299,7 +299,7 @@ def present(name,
|
|||
|
||||
identifier
|
||||
Custom-defined identifier for tracking the cron line for future crontab
|
||||
edits. This defaults to the state id
|
||||
edits. This defaults to the state name
|
||||
|
||||
special
|
||||
A special keyword to specify periodicity (eg. @reboot, @hourly...).
|
||||
|
@ -386,7 +386,7 @@ def absent(name,
|
|||
|
||||
identifier
|
||||
Custom-defined identifier for tracking the cron line for future crontab
|
||||
edits. This defaults to the state id
|
||||
edits. This defaults to the state name
|
||||
|
||||
special
|
||||
The special keyword used in the job (eg. @reboot, @hourly...).
|
||||
|
|
|
@ -1605,6 +1605,9 @@ def managed(name,
|
|||
'name': name,
|
||||
'result': True}
|
||||
|
||||
if not name:
|
||||
return _error(ret, 'Destination file name is required')
|
||||
|
||||
if mode is not None and salt.utils.is_windows():
|
||||
return _error(ret, 'The \'mode\' option is not supported on Windows')
|
||||
|
||||
|
@ -1755,8 +1758,6 @@ def managed(name,
|
|||
ret['comment'] = 'Error while applying template on contents'
|
||||
return ret
|
||||
|
||||
if not name:
|
||||
return _error(ret, 'Must provide name to file.exists')
|
||||
user = _test_owner(kwargs, user=user)
|
||||
if salt.utils.is_windows():
|
||||
if group is not None:
|
||||
|
|
|
@ -696,7 +696,7 @@ def edited_conf(name, lxc_conf=None, lxc_conf_unset=None):
|
|||
# to keep this function around and cannot officially remove it. Progress of
|
||||
# the new function will be tracked in https://github.com/saltstack/salt/issues/35523
|
||||
salt.utils.warn_until(
|
||||
'Oxygen',
|
||||
'Fluorine',
|
||||
'This state is unsuitable for setting parameters that appear more '
|
||||
'than once in an LXC config file, or parameters which must appear in '
|
||||
'a certain order (such as when configuring more than one network '
|
||||
|
|
|
@ -59,6 +59,7 @@ from __future__ import absolute_import
|
|||
|
||||
# Import python libs
|
||||
import logging
|
||||
import salt.utils
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -186,13 +187,14 @@ def present(name,
|
|||
use_32bit_registry=use_32bit_registry)
|
||||
|
||||
if vdata == reg_current['vdata'] and reg_current['success']:
|
||||
ret['comment'] = '{0} in {1} is already configured'.\
|
||||
format(vname if vname else '(Default)', name)
|
||||
ret['comment'] = u'{0} in {1} is already configured' \
|
||||
''.format(salt.utils.to_unicode(vname, 'utf-8') if vname else u'(Default)',
|
||||
salt.utils.to_unicode(name, 'utf-8'))
|
||||
return ret
|
||||
|
||||
add_change = {'Key': r'{0}\{1}'.format(hive, key),
|
||||
'Entry': '{0}'.format(vname if vname else '(Default)'),
|
||||
'Value': '{0}'.format(vdata)}
|
||||
'Entry': u'{0}'.format(salt.utils.to_unicode(vname, 'utf-8') if vname else u'(Default)'),
|
||||
'Value': salt.utils.to_unicode(vdata, 'utf-8')}
|
||||
|
||||
# Check for test option
|
||||
if __opts__['test']:
|
||||
|
|
|
@ -65,7 +65,8 @@ def exists(name, index=None):
|
|||
'''
|
||||
Add the directory to the system PATH at index location
|
||||
|
||||
index: where the directory should be placed in the PATH (default: None)
|
||||
index: where the directory should be placed in the PATH (default: None).
|
||||
This is 0-indexed, so 0 means to prepend at the very start of the PATH.
|
||||
[Note: Providing no index will append directory to PATH and
|
||||
will not enforce its location within the PATH.]
|
||||
|
||||
|
@ -96,7 +97,7 @@ def exists(name, index=None):
|
|||
|
||||
try:
|
||||
currIndex = sysPath.index(path)
|
||||
if index:
|
||||
if index is not None:
|
||||
index = int(index)
|
||||
if index < 0:
|
||||
index = len(sysPath) + index + 1
|
||||
|
@ -115,7 +116,7 @@ def exists(name, index=None):
|
|||
except ValueError:
|
||||
pass
|
||||
|
||||
if not index:
|
||||
if index is None:
|
||||
index = len(sysPath) # put it at the end
|
||||
ret['changes']['added'] = '{0} will be added at index {1}'.format(name, index)
|
||||
if __opts__['test']:
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
/{{route.netmask}}
|
||||
{%- endif -%}
|
||||
{%- if route.gateway %} via {{route.gateway}}
|
||||
{%- else %} dev {{iface}}
|
||||
{%- endif %}
|
||||
{% endfor -%}
|
||||
|
|
|
@ -19,12 +19,17 @@ DEVICE="{{name}}"
|
|||
{%endif%}{% if ipaddr_end %}IPADDR_END="{{ipaddr_end}}"
|
||||
{%endif%}{% if netmask %}NETMASK="{{netmask}}"
|
||||
{%endif%}{% if prefix %}PREFIX="{{prefix}}"
|
||||
{%endif%}{% if ipaddrs %}{% for i in ipaddrs -%}
|
||||
IPADDR{{loop.index}}="{{i['ipaddr']}}"
|
||||
PREFIX{{loop.index}}="{{i['prefix']}}"
|
||||
{% endfor -%}
|
||||
{%endif%}{% if gateway %}GATEWAY="{{gateway}}"
|
||||
{%endif%}{% if enable_ipv6 %}IPV6INIT="yes"
|
||||
{% if ipv6_autoconf %}IPV6_AUTOCONF="{{ipv6_autoconf}}"
|
||||
{%endif%}{% if dhcpv6c %}DHCPV6C="{{dhcpv6c}}"
|
||||
{%endif%}{% if ipv6addr %}IPV6ADDR="{{ipv6addr}}"
|
||||
{%endif%}{% if ipv6gateway %}IPV6_DEFAULTGW="{{ipv6gateway}}"
|
||||
{%endif%}{% if ipv6addrs %}IPV6ADDR_SECONDARIES="{{ ipv6addrs|join(' ') }}"
|
||||
{%endif%}{% if ipv6_peerdns %}IPV6_PEERDNS="{{ipv6_peerdns}}"
|
||||
{%endif%}{% if ipv6_defroute %}IPV6_DEFROUTE="{{ipv6_defroute}}"
|
||||
{%endif%}{% if ipv6_peerroutes %}IPV6_PEERROUTES="{{ipv6_peerroutes}}"
|
||||
|
|
|
@ -1115,10 +1115,10 @@ def format_call(fun,
|
|||
continue
|
||||
extra[key] = copy.deepcopy(value)
|
||||
|
||||
# We'll be showing errors to the users until Salt Oxygen comes out, after
|
||||
# We'll be showing errors to the users until Salt Fluorine comes out, after
|
||||
# which, errors will be raised instead.
|
||||
warn_until(
|
||||
'Oxygen',
|
||||
'Fluorine',
|
||||
'It\'s time to start raising `SaltInvocationError` instead of '
|
||||
'returning warnings',
|
||||
# Let's not show the deprecation warning on the console, there's no
|
||||
|
@ -1155,7 +1155,7 @@ def format_call(fun,
|
|||
'{0}. If you were trying to pass additional data to be used '
|
||||
'in a template context, please populate \'context\' with '
|
||||
'\'key: value\' pairs. Your approach will work until Salt '
|
||||
'Oxygen is out.{1}'.format(
|
||||
'Fluorine is out.{1}'.format(
|
||||
msg,
|
||||
'' if 'full' not in ret else ' Please update your state files.'
|
||||
)
|
||||
|
@ -3070,6 +3070,8 @@ def to_unicode(s, encoding=None):
|
|||
'''
|
||||
Given str or unicode, return unicode (str for python 3)
|
||||
'''
|
||||
if s is None:
|
||||
return s
|
||||
if six.PY3:
|
||||
return to_str(s, encoding)
|
||||
else:
|
||||
|
|
|
@ -120,6 +120,8 @@ class _AtomicWFile(object):
|
|||
self._fh.close()
|
||||
if os.path.isfile(self._filename):
|
||||
shutil.copymode(self._filename, self._tmp_filename)
|
||||
st = os.stat(self._filename)
|
||||
os.chown(self._tmp_filename, st.st_uid, st.st_gid)
|
||||
atomic_rename(self._tmp_filename, self._filename)
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
|
|
|
@ -26,6 +26,16 @@ REMOTE_PROTOS = ('http', 'https', 'ftp', 'swift', 's3')
|
|||
VALID_PROTOS = ('salt', 'file') + REMOTE_PROTOS
|
||||
|
||||
|
||||
def __clean_tmp(tmp):
|
||||
'''
|
||||
Remove temporary files
|
||||
'''
|
||||
try:
|
||||
salt.utils.rm_rf(tmp)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def guess_archive_type(name):
|
||||
'''
|
||||
Guess an archive type (tar, zip, or rar) by its file extension
|
||||
|
@ -93,7 +103,15 @@ def copyfile(source, dest, backup_mode='', cachedir=''):
|
|||
fstat = os.stat(dest)
|
||||
except OSError:
|
||||
pass
|
||||
shutil.move(tgt, dest)
|
||||
|
||||
# The move could fail if the dest has xattr protections, so delete the
|
||||
# temp file in this case
|
||||
try:
|
||||
shutil.move(tgt, dest)
|
||||
except Exception:
|
||||
__clean_tmp(tgt)
|
||||
raise
|
||||
|
||||
if fstat is not None:
|
||||
os.chown(dest, fstat.st_uid, fstat.st_gid)
|
||||
os.chmod(dest, fstat.st_mode)
|
||||
|
@ -111,10 +129,7 @@ def copyfile(source, dest, backup_mode='', cachedir=''):
|
|||
subprocess.call(cmd, stdout=dev_null, stderr=dev_null)
|
||||
if os.path.isfile(tgt):
|
||||
# The temp file failed to move
|
||||
try:
|
||||
os.remove(tgt)
|
||||
except Exception:
|
||||
pass
|
||||
__clean_tmp(tgt)
|
||||
|
||||
|
||||
def rename(src, dst):
|
||||
|
|
|
@ -3,12 +3,23 @@
|
|||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import getpass
|
||||
import grp
|
||||
import pwd
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
# Posix only
|
||||
try:
|
||||
import grp
|
||||
import pwd
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Windows only
|
||||
try:
|
||||
import win32file
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Import Salt Testing libs
|
||||
from salttesting import skipIf
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
|
@ -23,6 +34,16 @@ import salt.utils
|
|||
from salt.modules import file as filemod
|
||||
|
||||
|
||||
def symlink(source, link_name):
|
||||
'''
|
||||
Handle symlinks on Windows with Python < 3.2
|
||||
'''
|
||||
if salt.utils.is_windows():
|
||||
win32file.CreateSymbolicLink(link_name, source)
|
||||
else:
|
||||
os.symlink(source, link_name)
|
||||
|
||||
|
||||
class FileModuleTest(integration.ModuleCase):
|
||||
'''
|
||||
Validate the file module
|
||||
|
@ -30,27 +51,27 @@ class FileModuleTest(integration.ModuleCase):
|
|||
def setUp(self):
|
||||
self.myfile = os.path.join(integration.TMP, 'myfile')
|
||||
with salt.utils.fopen(self.myfile, 'w+') as fp:
|
||||
fp.write('Hello\n')
|
||||
fp.write('Hello' + os.linesep)
|
||||
self.mydir = os.path.join(integration.TMP, 'mydir/isawesome')
|
||||
if not os.path.isdir(self.mydir):
|
||||
# left behind... Don't fail because of this!
|
||||
os.makedirs(self.mydir)
|
||||
self.mysymlink = os.path.join(integration.TMP, 'mysymlink')
|
||||
if os.path.islink(self.mysymlink):
|
||||
if os.path.islink(self.mysymlink) or os.path.isfile(self.mysymlink):
|
||||
os.remove(self.mysymlink)
|
||||
os.symlink(self.myfile, self.mysymlink)
|
||||
symlink(self.myfile, self.mysymlink)
|
||||
self.mybadsymlink = os.path.join(integration.TMP, 'mybadsymlink')
|
||||
if os.path.islink(self.mybadsymlink):
|
||||
if os.path.islink(self.mybadsymlink) or os.path.isfile(self.mybadsymlink):
|
||||
os.remove(self.mybadsymlink)
|
||||
os.symlink('/nonexistentpath', self.mybadsymlink)
|
||||
symlink('/nonexistentpath', self.mybadsymlink)
|
||||
super(FileModuleTest, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.isfile(self.myfile):
|
||||
os.remove(self.myfile)
|
||||
if os.path.islink(self.mysymlink):
|
||||
if os.path.islink(self.mysymlink) or os.path.isfile(self.mysymlink):
|
||||
os.remove(self.mysymlink)
|
||||
if os.path.islink(self.mybadsymlink):
|
||||
if os.path.islink(self.mybadsymlink) or os.path.isfile(self.mybadsymlink):
|
||||
os.remove(self.mybadsymlink)
|
||||
shutil.rmtree(self.mydir, ignore_errors=True)
|
||||
super(FileModuleTest, self).tearDown()
|
||||
|
@ -293,6 +314,23 @@ class FileModuleTest(integration.ModuleCase):
|
|||
else:
|
||||
self.assertItemsEqual(ret, ['file://' + self.myfile, 'filehash'])
|
||||
|
||||
def test_file_line_changes_format(self):
|
||||
'''
|
||||
Test file.line changes output formatting.
|
||||
|
||||
Issue #41474
|
||||
'''
|
||||
ret = self.minion_run('file.line', self.myfile, 'Goodbye',
|
||||
mode='insert', after='Hello')
|
||||
self.assertIn('Hello' + os.linesep + '+Goodbye', ret)
|
||||
|
||||
def test_file_line_content(self):
|
||||
self.minion_run('file.line', self.myfile, 'Goodbye',
|
||||
mode='insert', after='Hello')
|
||||
with salt.utils.fopen(self.myfile, 'r') as fp:
|
||||
content = fp.read()
|
||||
self.assertEqual(content, 'Hello' + os.linesep + 'Goodbye' + os.linesep)
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(FileModuleTest)
|
||||
|
|
|
@ -106,6 +106,62 @@ class OutputReturnTest(integration.ShellCase):
|
|||
trace = traceback.format_exc()
|
||||
self.assertEqual(trace, '')
|
||||
|
||||
def test_output_highstate(self):
|
||||
'''
|
||||
Regression tests for the highstate outputter. Calls a basic state with various
|
||||
flags. Each comparison should be identical when successful.
|
||||
'''
|
||||
# Test basic highstate output. No frills.
|
||||
expected = ['minion:', ' ID: simple-ping', ' Function: module.run',
|
||||
' Name: test.ping', ' Result: True',
|
||||
' Comment: Module function test.ping executed',
|
||||
' Changes: ', ' ret:', ' True',
|
||||
'Summary for minion', 'Succeeded: 1 (changed=1)', 'Failed: 0',
|
||||
'Total states run: 1']
|
||||
state_run = self.run_salt('"minion" state.sls simple-ping')
|
||||
|
||||
for expected_item in expected:
|
||||
self.assertIn(expected_item, state_run)
|
||||
|
||||
# Test highstate output while also passing --out=highstate.
|
||||
# This is a regression test for Issue #29796
|
||||
state_run = self.run_salt('"minion" state.sls simple-ping --out=highstate')
|
||||
|
||||
for expected_item in expected:
|
||||
self.assertIn(expected_item, state_run)
|
||||
|
||||
# Test highstate output when passing --static and running a state function.
|
||||
# See Issue #44556.
|
||||
state_run = self.run_salt('"minion" state.sls simple-ping --static')
|
||||
|
||||
for expected_item in expected:
|
||||
self.assertIn(expected_item, state_run)
|
||||
|
||||
# Test highstate output when passing --static and --out=highstate.
|
||||
# See Issue #44556.
|
||||
state_run = self.run_salt('"minion" state.sls simple-ping --static --out=highstate')
|
||||
|
||||
for expected_item in expected:
|
||||
self.assertIn(expected_item, state_run)
|
||||
|
||||
def test_output_highstate_falls_back_nested(self):
|
||||
'''
|
||||
Tests outputter when passing --out=highstate with a non-state call. This should
|
||||
fall back to "nested" output.
|
||||
'''
|
||||
expected = ['minion:', ' True']
|
||||
ret = self.run_salt('"minion" test.ping --out=highstate')
|
||||
self.assertEqual(ret, expected)
|
||||
|
||||
def test_static_simple(self):
|
||||
'''
|
||||
Tests passing the --static option with a basic test.ping command. This
|
||||
should be the "nested" output.
|
||||
'''
|
||||
expected = ['minion:', ' True']
|
||||
ret = self.run_salt('"minion" test.ping --static')
|
||||
self.assertEqual(ret, expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
|
|
@ -104,9 +104,9 @@ def _test_managed_file_mode_keep_helper(testcase, local=False):
|
|||
# Get the current mode so that we can put the file back the way we
|
||||
# found it when we're done.
|
||||
grail_fs_mode = os.stat(grail_fs_path).st_mode
|
||||
initial_mode = 504 # 0770 octal
|
||||
new_mode_1 = 384 # 0600 octal
|
||||
new_mode_2 = 420 # 0644 octal
|
||||
initial_mode = 0o770
|
||||
new_mode_1 = 0o600
|
||||
new_mode_2 = 0o644
|
||||
|
||||
# Set the initial mode, so we can be assured that when we set the mode
|
||||
# to "keep", we're actually changing the permissions of the file to the
|
||||
|
@ -587,6 +587,86 @@ class FileTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
|
|||
for typ in managed_files:
|
||||
os.remove(managed_files[typ])
|
||||
|
||||
def test_managed_local_source_with_source_hash(self):
|
||||
'''
|
||||
Make sure that we enforce the source_hash even with local files
|
||||
'''
|
||||
name = os.path.join(integration.TMP, 'local_source_with_source_hash')
|
||||
local_path = os.path.join(
|
||||
integration.FILES, 'file', 'base', 'grail', 'scene33')
|
||||
actual_hash = '567fd840bf1548edc35c48eb66cdd78bfdfcccff'
|
||||
# Reverse the actual hash
|
||||
bad_hash = actual_hash[::-1]
|
||||
|
||||
def remove_file():
|
||||
try:
|
||||
os.remove(name)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
def do_test(clean=False):
|
||||
for proto in ('file://', ''):
|
||||
source = proto + local_path
|
||||
log.debug('Trying source %s', source)
|
||||
try:
|
||||
ret = self.run_state(
|
||||
'file.managed',
|
||||
name=name,
|
||||
source=source,
|
||||
source_hash='sha1={0}'.format(bad_hash))
|
||||
self.assertSaltFalseReturn(ret)
|
||||
ret = ret[next(iter(ret))]
|
||||
# Shouldn't be any changes
|
||||
self.assertFalse(ret['changes'])
|
||||
# Check that we identified a hash mismatch
|
||||
self.assertIn(
|
||||
'does not match actual checksum', ret['comment'])
|
||||
|
||||
ret = self.run_state(
|
||||
'file.managed',
|
||||
name=name,
|
||||
source=source,
|
||||
source_hash='sha1={0}'.format(actual_hash))
|
||||
self.assertSaltTrueReturn(ret)
|
||||
finally:
|
||||
if clean:
|
||||
remove_file()
|
||||
|
||||
remove_file()
|
||||
log.debug('Trying with nonexistant destination file')
|
||||
do_test()
|
||||
log.debug('Trying with destination file already present')
|
||||
with salt.utils.fopen(name, 'w'):
|
||||
pass
|
||||
try:
|
||||
do_test(clean=False)
|
||||
finally:
|
||||
remove_file()
|
||||
|
||||
def test_managed_local_source_does_not_exist(self):
|
||||
'''
|
||||
Make sure that we exit gracefully when a local source doesn't exist
|
||||
'''
|
||||
name = os.path.join(integration.TMP, 'local_source_does_not_exist')
|
||||
local_path = os.path.join(
|
||||
integration.FILES, 'file', 'base', 'grail', 'scene99')
|
||||
|
||||
for proto in ('file://', ''):
|
||||
source = proto + local_path
|
||||
log.debug('Trying source %s', source)
|
||||
ret = self.run_state(
|
||||
'file.managed',
|
||||
name=name,
|
||||
source=source)
|
||||
self.assertSaltFalseReturn(ret)
|
||||
ret = ret[next(iter(ret))]
|
||||
# Shouldn't be any changes
|
||||
self.assertFalse(ret['changes'])
|
||||
# Check that we identified a hash mismatch
|
||||
self.assertIn(
|
||||
'does not exist', ret['comment'])
|
||||
|
||||
def test_directory(self):
|
||||
'''
|
||||
file.directory
|
||||
|
|
|
@ -31,6 +31,14 @@ from salt.grains import core
|
|||
core.__salt__ = {}
|
||||
core.__opts__ = {}
|
||||
log = logging.getLogger(__name__)
|
||||
IPv4Address = salt.ext.ipaddress.IPv4Address
|
||||
IPv6Address = salt.ext.ipaddress.IPv6Address
|
||||
IP4_LOCAL = '127.0.0.1'
|
||||
IP4_ADD1 = '10.0.0.1'
|
||||
IP4_ADD2 = '10.0.0.2'
|
||||
IP6_LOCAL = '::1'
|
||||
IP6_ADD1 = '2001:4860:4860::8844'
|
||||
IP6_ADD2 = '2001:4860:4860::8888'
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
|
@ -483,6 +491,130 @@ PATCHLEVEL = 3
|
|||
'Docker'
|
||||
)
|
||||
|
||||
def _check_ipaddress(self, value, ip_v):
|
||||
'''
|
||||
check if ip address in a list is valid
|
||||
'''
|
||||
for val in value:
|
||||
assert isinstance(val, six.string_types)
|
||||
ip_method = 'is_ipv{0}'.format(ip_v)
|
||||
self.assertTrue(getattr(salt.utils.network, ip_method)(val))
|
||||
|
||||
def _check_empty(self, key, value, empty):
|
||||
'''
|
||||
if empty is False and value does not exist assert error
|
||||
if empty is True and value exists assert error
|
||||
'''
|
||||
if not empty and not value:
|
||||
raise Exception("{0} is empty, expecting a value".format(key))
|
||||
elif empty and value:
|
||||
raise Exception("{0} is suppose to be empty. value: {1} \
|
||||
exists".format(key, value))
|
||||
|
||||
@skipIf(not salt.utils.is_linux(), 'System is not Linux')
|
||||
def test_fqdn_return(self):
|
||||
'''
|
||||
test ip4 and ip6 return values
|
||||
'''
|
||||
net_ip4_mock = [IP4_LOCAL, IP4_ADD1, IP4_ADD2]
|
||||
net_ip6_mock = [IP6_LOCAL, IP6_ADD1, IP6_ADD2]
|
||||
|
||||
self._run_fqdn_tests(net_ip4_mock, net_ip6_mock,
|
||||
ip4_empty=False, ip6_empty=False)
|
||||
|
||||
@skipIf(not salt.utils.is_linux(), 'System is not Linux')
|
||||
def test_fqdn6_empty(self):
|
||||
'''
|
||||
test when ip6 is empty
|
||||
'''
|
||||
net_ip4_mock = [IP4_LOCAL, IP4_ADD1, IP4_ADD2]
|
||||
net_ip6_mock = []
|
||||
|
||||
self._run_fqdn_tests(net_ip4_mock, net_ip6_mock,
|
||||
ip4_empty=False)
|
||||
|
||||
@skipIf(not salt.utils.is_linux(), 'System is not Linux')
|
||||
def test_fqdn4_empty(self):
|
||||
'''
|
||||
test when ip4 is empty
|
||||
'''
|
||||
net_ip4_mock = []
|
||||
net_ip6_mock = [IP6_LOCAL, IP6_ADD1, IP6_ADD2]
|
||||
|
||||
self._run_fqdn_tests(net_ip4_mock, net_ip6_mock,
|
||||
ip6_empty=False)
|
||||
|
||||
@skipIf(not salt.utils.is_linux(), 'System is not Linux')
|
||||
def test_fqdn_all_empty(self):
|
||||
'''
|
||||
test when both ip4 and ip6 are empty
|
||||
'''
|
||||
net_ip4_mock = []
|
||||
net_ip6_mock = []
|
||||
|
||||
self._run_fqdn_tests(net_ip4_mock, net_ip6_mock)
|
||||
|
||||
def _run_fqdn_tests(self, net_ip4_mock, net_ip6_mock,
|
||||
ip6_empty=True, ip4_empty=True):
|
||||
|
||||
def _check_type(key, value, ip4_empty, ip6_empty):
|
||||
'''
|
||||
check type and other checks
|
||||
'''
|
||||
assert isinstance(value, list)
|
||||
|
||||
if '4' in key:
|
||||
self._check_empty(key, value, ip4_empty)
|
||||
self._check_ipaddress(value, ip_v='4')
|
||||
elif '6' in key:
|
||||
self._check_empty(key, value, ip6_empty)
|
||||
self._check_ipaddress(value, ip_v='6')
|
||||
|
||||
ip4_mock = [(2, 1, 6, '', (IP4_ADD1, 0)),
|
||||
(2, 3, 0, '', (IP4_ADD2, 0))]
|
||||
ip6_mock = [(10, 1, 6, '', (IP6_ADD1, 0, 0, 0)),
|
||||
(10, 3, 0, '', (IP6_ADD2, 0, 0, 0))]
|
||||
|
||||
with patch.dict(core.__opts__, {'ipv6': False}):
|
||||
with patch.object(salt.utils.network, 'ip_addrs',
|
||||
MagicMock(return_value=net_ip4_mock)):
|
||||
with patch.object(salt.utils.network, 'ip_addrs6',
|
||||
MagicMock(return_value=net_ip6_mock)):
|
||||
with patch.object(core.socket, 'getaddrinfo', side_effect=[ip4_mock, ip6_mock]):
|
||||
get_fqdn = core.ip_fqdn()
|
||||
ret_keys = ['fqdn_ip4', 'fqdn_ip6', 'ipv4', 'ipv6']
|
||||
for key in ret_keys:
|
||||
value = get_fqdn[key]
|
||||
_check_type(key, value, ip4_empty, ip6_empty)
|
||||
|
||||
@skipIf(not salt.utils.is_linux(), 'System is not Linux')
|
||||
def test_dns_return(self):
|
||||
'''
|
||||
test the return for a dns grain. test for issue:
|
||||
https://github.com/saltstack/salt/issues/41230
|
||||
'''
|
||||
resolv_mock = {'domain': '', 'sortlist': [], 'nameservers':
|
||||
[IPv4Address(IP4_ADD1),
|
||||
IPv6Address(IP6_ADD1)], 'ip4_nameservers':
|
||||
[IPv4Address(IP4_ADD1)],
|
||||
'search': ['test.saltstack.com'], 'ip6_nameservers':
|
||||
[IPv6Address(IP6_ADD1)], 'options': []}
|
||||
ret = {'dns': {'domain': '', 'sortlist': [], 'nameservers':
|
||||
[IP4_ADD1, IP6_ADD1], 'ip4_nameservers':
|
||||
[IP4_ADD1], 'search': ['test.saltstack.com'],
|
||||
'ip6_nameservers': [IP6_ADD1], 'options':
|
||||
[]}}
|
||||
self._run_dns_test(resolv_mock, ret)
|
||||
|
||||
def _run_dns_test(self, resolv_mock, ret):
|
||||
with patch.object(salt.utils, 'is_windows',
|
||||
MagicMock(return_value=False)):
|
||||
with patch.dict(core.__opts__, {'ipv6': False}):
|
||||
with patch.object(salt.utils.dns, 'parse_resolv',
|
||||
MagicMock(return_value=resolv_mock)):
|
||||
get_dns = core.dns()
|
||||
self.assertEqual(get_dns, ret)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
|
|
@ -14,6 +14,7 @@ from salttesting.mock import (
|
|||
patch)
|
||||
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salt.ext.six.moves import range
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
|
@ -62,7 +63,6 @@ class RhipTestCase(TestCase):
|
|||
'''
|
||||
with patch.dict(rh_ip.__grains__, {'os': 'Fedora'}):
|
||||
with patch.object(rh_ip, '_raise_error_iface', return_value=None):
|
||||
|
||||
self.assertRaises(AttributeError,
|
||||
rh_ip.build_interface,
|
||||
'iface', 'slave', True)
|
||||
|
@ -72,34 +72,53 @@ class RhipTestCase(TestCase):
|
|||
rh_ip.build_interface,
|
||||
'iface', 'eth', True, netmask='255.255.255.255', prefix=32,
|
||||
test=True)
|
||||
self.assertRaises(AttributeError,
|
||||
rh_ip.build_interface,
|
||||
'iface', 'eth', True, ipaddrs=['A'],
|
||||
test=True)
|
||||
self.assertRaises(AttributeError,
|
||||
rh_ip.build_interface,
|
||||
'iface', 'eth', True, ipv6addrs=['A'],
|
||||
test=True)
|
||||
|
||||
with patch.object(rh_ip, '_parse_settings_bond', MagicMock()):
|
||||
mock = jinja2.exceptions.TemplateNotFound('foo')
|
||||
with patch.object(jinja2.Environment,
|
||||
'get_template',
|
||||
MagicMock(side_effect=mock)):
|
||||
self.assertEqual(rh_ip.build_interface('iface',
|
||||
'vlan',
|
||||
True), '')
|
||||
|
||||
with patch.object(rh_ip, '_read_temp', return_value='A'):
|
||||
for osrelease in range(5, 8):
|
||||
with patch.dict(rh_ip.__grains__, {'os': 'RedHat', 'osrelease': str(osrelease)}):
|
||||
with patch.object(rh_ip, '_raise_error_iface', return_value=None):
|
||||
with patch.object(rh_ip, '_parse_settings_bond', MagicMock()):
|
||||
mock = jinja2.exceptions.TemplateNotFound('foo')
|
||||
with patch.object(jinja2.Environment,
|
||||
'get_template', MagicMock()):
|
||||
'get_template',
|
||||
MagicMock(side_effect=mock)):
|
||||
self.assertEqual(rh_ip.build_interface('iface',
|
||||
'vlan',
|
||||
True,
|
||||
test='A'),
|
||||
'A')
|
||||
True), '')
|
||||
|
||||
with patch.object(rh_ip, '_write_file_iface',
|
||||
return_value=None):
|
||||
with patch.object(os.path, 'join',
|
||||
return_value='A'):
|
||||
with patch.object(rh_ip, '_read_file',
|
||||
with patch.object(rh_ip, '_read_temp', return_value='A'):
|
||||
with patch.object(jinja2.Environment,
|
||||
'get_template', MagicMock()):
|
||||
self.assertEqual(rh_ip.build_interface('iface',
|
||||
'vlan',
|
||||
True,
|
||||
test='A'),
|
||||
'A')
|
||||
|
||||
with patch.object(rh_ip, '_write_file_iface',
|
||||
return_value=None):
|
||||
with patch.object(os.path, 'join',
|
||||
return_value='A'):
|
||||
self.assertEqual(rh_ip.build_interface
|
||||
('iface', 'vlan',
|
||||
True), 'A')
|
||||
with patch.object(rh_ip, '_read_file',
|
||||
return_value='A'):
|
||||
self.assertEqual(rh_ip.build_interface
|
||||
('iface', 'vlan',
|
||||
True), 'A')
|
||||
if osrelease > 6:
|
||||
with patch.dict(rh_ip.__salt__, {'network.interfaces': lambda: {'eth': True}}):
|
||||
self.assertEqual(rh_ip.build_interface
|
||||
('iface', 'eth', True,
|
||||
ipaddrs=['127.0.0.1/8']), 'A')
|
||||
self.assertEqual(rh_ip.build_interface
|
||||
('iface', 'eth', True,
|
||||
ipv6addrs=['fc00::1/128']), 'A')
|
||||
|
||||
def test_build_routes(self):
|
||||
'''
|
||||
|
|
|
@ -581,7 +581,7 @@ class FileTestCase(TestCase):
|
|||
'file.copy': mock_cp,
|
||||
'file.manage_file': mock_ex,
|
||||
'cmd.run_all': mock_cmd_fail}):
|
||||
comt = ('Must provide name to file.exists')
|
||||
comt = ('Destination file name is required')
|
||||
ret.update({'comment': comt, 'name': '', 'pchanges': {}})
|
||||
self.assertDictEqual(filestate.managed(''), ret)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue