Merge branch '2016.3' into 2016_3_develop

This commit is contained in:
Mike Place 2016-09-26 21:47:32 +09:00
commit 4956d7d5a3
No known key found for this signature in database
GPG key ID: 9136F4F13705CFD3
16 changed files with 405 additions and 285 deletions

View file

@ -2315,9 +2315,9 @@ exposed.
.. code-block:: yaml
minionfs_whitelist:
- base
- v1.*
- 'mybranch\d+'
- server01
- dev*
- 'mail\d+.mydomain.tld'
.. conf_master:: minionfs_blacklist
@ -2341,9 +2341,9 @@ exposed.
.. code-block:: yaml
minionfs_blacklist:
- base
- v1.*
- 'mybranch\d+'
- server01
- dev*
- 'mail\d+.mydomain.tld'
.. _pillar-configuration:

View file

@ -4,155 +4,149 @@
MinionFS Backend Walkthrough
============================
Propagating Files
=================
.. versionadded:: 2014.1.0
Sometimes, one might need to propagate files that are generated on a minion.
Salt already has a feature to send files from a minion to the master.
Enabling File Propagation
=========================
To enable propagation, the :conf_master:`file_recv` option needs to be set to ``True``.
.. code-block:: yaml
file_recv: True
These changes require a restart of the master, then new requests for the
``salt://minion-id/`` protocol will send files that are pushed by ``cp.push``
from ``minion-id`` to the master.
.. code-block:: bash
salt 'minion-id' cp.push /path/to/the/file
This command will store the file, including its full path, under
:conf_master:`cachedir` ``/master/minions/minion-id/files``. With the default
:conf_master:`cachedir` the example file above would be stored as
`/var/cache/salt/master/minions/minion-id/files/path/to/the/file`.
.. note::
This walkthrough assumes basic knowledge of Salt and :mod:`cp.push
<salt.modules.cp.push>`. To get up to speed, check out the
:doc:`walkthrough </topics/tutorials/walkthrough>`.
MinionFS Backend
================
Sometimes it is desirable to deploy a file located on one minion to one or more
other minions. This is supported in Salt, and can be accomplished in two parts:
Since it is not a good idea to expose the whole :conf_master:`cachedir`, MinionFS
should be used to send these files to other minions.
#. Minion support for pushing files to the master (using :py:func:`cp.push
<salt.modules.cp.push>`)
Simple Configuration
====================
#. The :mod:`minionfs <salt.fileserver.minionfs>` fileserver backend
To use the minionfs backend only two configuration changes are required on the
master. The :conf_master:`fileserver_backend` option needs to contain a value of
``minion`` and :conf_master:`file_recv` needs to be set to true:
This walkthrough will show how to use both of these features.
Enabling File Push
==================
To set the master to accept files pushed from minions, the
:conf_master:`file_recv` option in the master config file must be set to
``True`` (the default is ``False``).
.. code-block:: yaml
file_recv: True
.. note::
This change requires a restart of the salt-master service.
Pushing Files
=============
Once this has been done, files can be pushed to the master using the
:py:func:`cp.push <salt.modules.cp.push>` function:
.. code-block:: bash
salt 'minion-id' cp.push /path/to/the/file
This command will store the file in a subdirectory named ``minions`` under the
master's :conf_master:`cachedir`. On most masters, this path will be
``/var/cache/salt/master/minions``. Within this directory will be one directory
for each minion which has pushed a file to the master, and underneath that the
full path to the file on the minion. So, for example, if a minion with an ID of
``dev1`` pushed a file ``/var/log/myapp.log`` to the master, it would be saved
to ``/var/cache/salt/master/minions/dev1/var/log/myapp.log``.
Serving Pushed Files Using MinionFS
===================================
While it is certainly possible to add ``/var/cache/salt/master/minions`` to the
master's :conf_master:`file_roots` and serve these files, it may only be
desirable to expose files pushed from certain minions. Adding
``/var/cache/salt/master/minions/<minion-id>`` for each minion that needs to be
exposed can be cumbersome and prone to errors.
Enter :mod:`minionfs <salt.fileserver.minionfs>`. This fileserver backend will
make files pushed using :py:func:`cp.push <salt.modules.cp.push>` available to
the Salt fileserver, and provides an easy mechanism to restrict which minions'
pushed files are made available.
Simple Configuration
--------------------
To use the :mod:`minionfs <salt.fileserver.minionfs>` backend, add ``minion``
to the list of backends in the :conf_master:`fileserver_backend` configuration
option on the master:
.. code-block:: yaml
file_recv: True
fileserver_backend:
- roots
- minion
.. note::
As described earlier, ``file_recv: True`` is also needed to enable the
master to receive files pushed from minions. As always, changes to the
master configuration require a restart of the ``salt-master`` service.
Files made available via :mod:`minionfs <salt.fileserver.minionfs>` are by
default located at ``salt://<minion-id>/path/to/file``. Think back to the
earlier example, in which ``dev1`` pushed a file ``/var/log/myapp.log`` to the
master. With :mod:`minionfs <salt.fileserver.minionfs>` enabled, this file
would be addressable in Salt at ``salt://dev1/var/log/myapp.log``.
If many minions have pushed to the master, this will result in many directories
in the root of the Salt fileserver. For this reason, it is recommended to use
the :conf_master:`minionfs_mountpoint` config option to organize these files
underneath a subdirectory:
.. code-block:: yaml
minionfs_mountpoint: salt://minionfs
Using the above mountpoint, the file in the example would be located at
``salt://minionfs/dev1/var/log/myapp.log``.
Restricting Certain Minions' Files from Being Available Via MinionFS
--------------------------------------------------------------------
A whitelist and blacklist can be used to restrict the minions whose pushed
files are available via :mod:`minionfs <salt.fileserver.minionfs>`. These lists
can be managed using the :conf_master:`minionfs_whitelist` and
:conf_master:`minionfs_blacklist` config options. Click the links for both of
them for a detailed explanation of how to use them.
A more complex configuration example, which uses both a whitelist and
blacklist, can be found below:
.. code-block:: yaml
file_recv: True
These changes require a restart of the master, then new requests for the
``salt://minion-id/`` protocol will send files that are pushed by ``cp.push``
from ``minion-id`` to the master.
fileserver_backend:
- roots
- minion
.. note::
minionfs_mountpoint: salt://minionfs
All of the files that are pushed to the master are going to be available to
all of the minions. If this is not what you want, please remove ``minion``
from :conf_master:`fileserver_backend` in the master config file.
minionfs_whitelist:
- host04
- web*
- 'mail\d+\.domain\.tld'
.. note::
minionfs_whitelist:
- web21
Having directories with the same name as your minions in the root
that can be accessed like ``salt://minion-id/`` might cause confusion.
Potential Concerns
------------------
Commandline Example
===================
* There is no access control in place to restrict which minions have access to
files served up by :mod:`minionfs <salt.fileserver.minionfs>`. All minions
will have access to these files.
Lets assume that we are going to generate SSH keys on a minion called
``minion-source`` and put the public part in ``~/.ssh/authorized_keys`` of root
user of a minion called ``minion-destination``.
First, lets make sure that ``/root/.ssh`` exists and has the right permissions:
.. code-block:: bash
[root@salt-master file]# salt '*' file.mkdir dir_path=/root/.ssh user=root group=root mode=700
minion-source:
None
minion-destination:
None
We create an RSA key pair without a passphrase [*]_:
.. code-block:: bash
[root@salt-master file]# salt 'minion-source' cmd.run 'ssh-keygen -N "" -f /root/.ssh/id_rsa'
minion-source:
Generating public/private rsa key pair.
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
9b:cd:1c:b9:c2:93:8e:ad:a3:52:a0:8b:0a:cc:d4:9b root@minion-source
The key's randomart image is:
+--[ RSA 2048]----+
| |
| |
| |
| o . |
| o o S o |
|= + . B o |
|o+ E B = |
|+ . .+ o |
|o ...ooo |
+-----------------+
and we send the public part to the master to be available to all minions:
.. code-block:: bash
[root@salt-master file]# salt 'minion-source' cp.push /root/.ssh/id_rsa.pub
minion-source:
True
now it can be seen by everyone:
.. code-block:: bash
[root@salt-master file]# salt 'minion-destination' cp.list_master_dirs
minion-destination:
- .
- etc
- minion-source/root
- minion-source/root/.ssh
Lets copy that as the only authorized key to ``minion-destination``:
.. code-block:: bash
[root@salt-master file]# salt 'minion-destination' cp.get_file salt://minion-source/root/.ssh/id_rsa.pub /root/.ssh/authorized_keys
minion-destination:
/root/.ssh/authorized_keys
Or we can use a more elegant and salty way to add an SSH key:
.. code-block:: bash
[root@salt-master file]# salt 'minion-destination' ssh.set_auth_key_from_file user=root source=salt://minion-source/root/.ssh/id_rsa.pub
minion-destination:
new
.. [*] Yes, that was the actual key on my server, but the server is already destroyed.
* Unless the :conf_master:`minionfs_whitelist` and/or
:conf_master:`minionfs_blacklist` config options are used, all minions which
push files to the master will have their files made available via
:mod:`minionfs <salt.fileserver.minionfs>`.

View file

@ -798,7 +798,6 @@ def setup_multiprocessing_logging_listener(opts, queue=None):
target=__process_multiprocessing_logging_queue,
args=(opts, queue or get_multiprocessing_logging_queue(),)
)
__MP_LOGGING_QUEUE_PROCESS.daemon = True
__MP_LOGGING_QUEUE_PROCESS.start()
__MP_LOGGING_LISTENER_CONFIGURED = True

View file

@ -539,7 +539,8 @@ class Master(SMaster):
'reload': salt.crypt.Crypticle.generate_key_string
}
log.info('Creating master process manager')
self.process_manager = salt.utils.process.ProcessManager(name='Master_ProcessManager')
# Since there are children having their own ProcessManager we should wait for kill more time.
self.process_manager = salt.utils.process.ProcessManager(wait_for_kill=5)
pub_channels = []
log.info('Creating master publisher process')
for transport, opts in iter_transport_opts(self.opts):
@ -726,7 +727,9 @@ class ReqServer(SignalHandlingMultiprocessingProcess):
except os.error:
pass
self.process_manager = salt.utils.process.ProcessManager(name='ReqServer_ProcessManager')
# Wait for kill should be less then parent's ProcessManager.
self.process_manager = salt.utils.process.ProcessManager(name='ReqServer_ProcessManager',
wait_for_kill=1)
req_channels = []
tcp_only = True

View file

@ -6,6 +6,7 @@ A module to wrap (non-Windows) archive calls
'''
from __future__ import absolute_import
import os
import logging
import contextlib # For < 2.7 compat
import logging
@ -21,6 +22,8 @@ __func_alias__ = {
'zip_': 'zip'
}
log = logging.getLogger(__name__)
HAS_ZIPFILE = False
try:
@ -535,8 +538,12 @@ def unzip(zip_file, dest, excludes=None, options=None, template=None,
salt '*' archive.unzip /tmp/zipfile.zip /home/strongbad/ password='BadPassword'
'''
if options:
log.warning("Options '{0}' ignored, only works with unzip binary.".format(options))
# https://bugs.python.org/issue15795
log.warning('Due to bug 15795 in python\'s zip lib, the permissions of the'
' extracted files may not be preserved when using archive.unzip')
log.warning('To preserve the permissions of extracted files, use'
' archive.cmd_unzip')
if not excludes:
excludes = []
if runas:

View file

@ -36,9 +36,13 @@ def __virtual__():
salt-minion running as SYSTEM.
'''
if not salt.utils.is_windows():
return (False, 'Cannot load module chocolatey: Chocolatey requires Windows')
elif __grains__['osrelease'] in ('XP', '2003Server'):
return (False, 'Cannot load module chocolatey: Chocolatey requires Windows Vista or later')
return (False, 'Cannot load module chocolatey: Chocolatey requires '
'Windows')
if __grains__['osrelease'] in ('XP', '2003Server'):
return (False, 'Cannot load module chocolatey: Chocolatey requires '
'Windows Vista or later')
return 'chocolatey'
@ -72,7 +76,7 @@ def _find_chocolatey(context, salt):
if 'chocolatey._path' in context:
return context['chocolatey._path']
choc_defaults = ['C:\\Chocolatey\\bin\\chocolatey.bat',
'C:\\ProgramData\\Chocolatey\\bin\\chocolatey.exe', ]
'C:\\ProgramData\\Chocolatey\\bin\\chocolatey.exe', ]
choc_path = salt['cmd.which']('chocolatey.exe')
if not choc_path:
@ -244,11 +248,11 @@ def list_(narrow=None,
if narrow:
cmd.append(narrow)
if salt.utils.is_true(all_versions):
cmd.append('-AllVersions')
cmd.append('-allversions')
if salt.utils.is_true(pre_versions):
cmd.append('-Prerelease')
cmd.append('-prerelease')
if source:
cmd.extend(['-Source', source])
cmd.extend(['-source', source])
if local_only:
cmd.extend(['-localonly'])
@ -277,6 +281,9 @@ def list_webpi():
Instructs Chocolatey to pull a full package list from the Microsoft Web PI
repository.
Returns:
str: List of webpi packages
CLI Example:
.. code-block:: bash
@ -284,7 +291,7 @@ def list_webpi():
salt '*' chocolatey.list_webpi
'''
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'list', '-Source', 'webpi']
cmd = [choc_path, 'list', '-source', 'webpi']
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
@ -300,6 +307,9 @@ def list_windowsfeatures():
Instructs Chocolatey to pull a full package list from the Windows Features
list, via the Deployment Image Servicing and Management tool.
Returns:
str: List of Windows Features
CLI Example:
.. code-block:: bash
@ -307,7 +317,7 @@ def list_windowsfeatures():
salt '*' chocolatey.list_windowsfeatures
'''
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'list', '-Source', 'windowsfeatures']
cmd = [choc_path, 'list', '-source', 'windowsfeatures']
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
@ -330,36 +340,52 @@ def install(name,
'''
Instructs Chocolatey to install a package.
name
The name of the package to be installed. Only accepts a single argument.
Args:
version
Install a specific version of the package. Defaults to latest version.
name (str):
The name of the package to be installed. Only accepts a single
argument.
source
Chocolatey repository (directory, share or remote URL feed) the package
comes from. Defaults to the official Chocolatey feed.
version (str):
Install a specific version of the package. Defaults to latest
version.
force
Reinstall the current version of an existing package.
source (str):
Chocolatey repository (directory, share or remote URL feed) the
package comes from. Defaults to the official Chocolatey feed.
pre_versions
Include pre-release packages. Defaults to False.
Alternative Sources:
install_args
A list of install arguments you want to pass to the installation process
i.e product key or feature list
- cygwin
- python
- ruby
- webpi
- windowsfeatures
override_args
Set to true if you want to override the original install arguments (for the native installer)
in the package and use your own. When this is set to False install_args will be appended to the end of the
default arguments
force (bool):
Reinstall the current version of an existing package.
force_x86
Force x86 (32bit) installation on 64 bit systems. Defaults to false.
pre_versions (bool):
Include pre-release packages. Defaults to False.
package_args
A list of arguments you want to pass to the package
install_args (str):
A list of install arguments you want to pass to the installation
process i.e product key or feature list
override_args (bool):
Set to true if you want to override the original install arguments
(for the native installer) in the package and use your own. When
this is set to False install_args will be appended to the end of the
default arguments
force_x86 (str):
Force x86 (32bit) installation on 64 bit systems. Defaults to false.
package_args (str):
A list of arguments you want to pass to the package
Returns:
str: The output of the ``chocolatey`` command
CLI Example:
@ -373,29 +399,30 @@ def install(name,
# chocolatey helpfully only supports a single package argument
cmd = [choc_path, 'install', name]
if version:
cmd.extend(['-Version', version])
cmd.extend(['-version', version])
if source:
cmd.extend(['-Source', source])
cmd.extend(['-source', source])
if salt.utils.is_true(force):
cmd.extend(['-Force'])
cmd.append('-force')
if salt.utils.is_true(pre_versions):
cmd.extend(['-PreRelease'])
cmd.append('-prerelease')
if install_args:
cmd.extend(['-InstallArguments', install_args])
cmd.extend(['-installarguments', install_args])
if override_args:
cmd.extend(['-OverrideArguments'])
cmd.append('-overridearguments')
if force_x86:
cmd.extend(['-forcex86'])
cmd.append('-forcex86')
if package_args:
cmd.extend(['-PackageParameters', package_args])
cmd.extend(['-packageparameters', package_args])
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
if result['retcode'] not in [0, 1641, 3010]:
err = 'Running chocolatey failed: {0}'.format(result['stderr'])
log.error(err)
raise CommandExecutionError(err)
elif name == 'chocolatey':
if name == 'chocolatey':
_clear_context(__context__)
return result['stdout']
@ -424,21 +451,10 @@ def install_cygwin(name, install_args=None, override_args=False):
salt '*' chocolatey.install_cygwin <package name>
salt '*' chocolatey.install_cygwin <package name> install_args=<args> override_args=True
'''
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'cygwin', name]
if install_args:
cmd.extend(['-InstallArguments', install_args])
if override_args:
cmd.extend(['-OverrideArguments'])
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
err = 'Running chocolatey failed: {0}'.format(result['stderr'])
log.error(err)
raise CommandExecutionError(err)
return result['stdout']
return install(name,
source='cygwin',
install_args=install_args,
override_args=override_args)
def install_gem(name, version=None, install_args=None, override_args=False):
@ -470,23 +486,11 @@ def install_gem(name, version=None, install_args=None, override_args=False):
salt '*' chocolatey.install_gem <package name> version=<package version>
salt '*' chocolatey.install_gem <package name> install_args=<args> override_args=True
'''
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'gem', name]
if version:
cmd.extend(['-Version', version])
if install_args:
cmd.extend(['-InstallArguments', install_args])
if override_args:
cmd.extend(['-OverrideArguments'])
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
err = 'Running chocolatey failed: {0}'.format(result['stderr'])
log.error(err)
raise CommandExecutionError(err)
return result['stdout']
return install(name,
version=version,
source='ruby',
install_args=install_args,
override_args=override_args)
def install_missing(name, version=None, source=None):
@ -525,9 +529,9 @@ def install_missing(name, version=None, source=None):
# chocolatey helpfully only supports a single package argument
cmd = [choc_path, 'installmissing', name]
if version:
cmd.extend(['-Version', version])
cmd.extend(['-version', version])
if source:
cmd.extend(['-Source', source])
cmd.extend(['-source', source])
# Shouldn't need this as this code should never run on v0.9.9 and newer
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
@ -568,23 +572,11 @@ def install_python(name, version=None, install_args=None, override_args=False):
salt '*' chocolatey.install_python <package name> version=<package version>
salt '*' chocolatey.install_python <package name> install_args=<args> override_args=True
'''
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'python', name]
if version:
cmd.extend(['-Version', version])
if install_args:
cmd.extend(['-InstallArguments', install_args])
if override_args:
cmd.extend(['-OverrideArguments'])
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
err = 'Running chocolatey failed: {0}'.format(result['stderr'])
log.error(err)
raise CommandExecutionError(err)
return result['stdout']
return install(name,
version=version,
source='python',
install_args=install_args,
override_args=override_args)
def install_windowsfeatures(name):
@ -601,17 +593,7 @@ def install_windowsfeatures(name):
salt '*' chocolatey.install_windowsfeatures <package name>
'''
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'windowsfeatures', name]
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
err = 'Running chocolatey failed: {0}'.format(result['stderr'])
log.error(err)
raise CommandExecutionError(err)
return result['stdout']
return install(name, source='windowsfeatures')
def install_webpi(name, install_args=None, override_args=False):
@ -637,21 +619,10 @@ def install_webpi(name, install_args=None, override_args=False):
salt '*' chocolatey.install_webpi <package name>
salt '*' chocolatey.install_webpi <package name> install_args=<args> override_args=True
'''
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'webpi', name]
if install_args:
cmd.extend(['-InstallArguments', install_args])
if override_args:
cmd.extend(['-OverrideArguments'])
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
err = 'Running chocolatey failed: {0}'.format(result['stderr'])
log.error(err)
raise CommandExecutionError(err)
return result['stdout']
return install(name,
source='webpi',
install_args=install_args,
override_args=override_args)
def uninstall(name, version=None, uninstall_args=None, override_args=False):
@ -686,15 +657,107 @@ def uninstall(name, version=None, uninstall_args=None, override_args=False):
# chocolatey helpfully only supports a single package argument
cmd = [choc_path, 'uninstall', name]
if version:
cmd.extend(['-Version', version])
cmd.extend(['-version', version])
if uninstall_args:
cmd.extend(['-UninstallArguments', uninstall_args])
cmd.extend(['-uninstallarguments', uninstall_args])
if override_args:
cmd.extend(['-OverrideArguments'])
cmd.extend(['-overridearguments'])
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
if result['retcode'] not in [0, 1605, 1614, 1641]:
err = 'Running chocolatey failed: {0}'.format(result['stderr'])
log.error(err)
raise CommandExecutionError(err)
return result['stdout']
def upgrade(name,
version=None,
source=None,
force=False,
pre_versions=False,
install_args=None,
override_args=False,
force_x86=False,
package_args=None):
'''
.. version-added:: 2016.3.4
Instructs Chocolatey to upgrade packages on the system. (update is being
deprecated)
Args:
name (str):
The name of the package to update, or "all" to update everything
installed on the system.
version (str):
Install a specific version of the package. Defaults to latest
version.
source (str):
Chocolatey repository (directory, share or remote URL feed) the
package comes from. Defaults to the official Chocolatey feed.
force (bool):
Reinstall the **same** version already installed
pre_versions (bool):
Include pre-release packages in comparison. Defaults to False.
install_args (str):
A list of install arguments you want to pass to the installation
process i.e product key or feature list
override_args (str):
Set to true if you want to override the original install arguments
(for the native installer) in the package and use your own. When
this is set to False install_args will be appended to the end of the
default arguments
force_x86
Force x86 (32bit) installation on 64 bit systems. Defaults to false.
package_args
A list of arguments you want to pass to the package
Returns:
str: Results of the ``chocolatey`` command
CLI Example:
.. code-block:: bash
salt "*" chocolatey.upgrade all
salt "*" chocolatey.upgrade <package name> pre_versions=True
'''
# chocolatey helpfully only supports a single package argument
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'upgrade', name]
if version:
cmd.extend(['-version', version])
if source:
cmd.extend(['-source', source])
if salt.utils.is_true(force):
cmd.append('-force')
if salt.utils.is_true(pre_versions):
cmd.append('-prerelease')
if install_args:
cmd.extend(['-installarguments', install_args])
if override_args:
cmd.append('-overridearguments')
if force_x86:
cmd.append('-forcex86')
if package_args:
cmd.extend(['-packageparameters', package_args])
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] not in [0, 1641, 3010]:
err = 'Running chocolatey failed: {0}'.format(result['stderr'])
log.error(err)
raise CommandExecutionError(err)
@ -726,15 +789,19 @@ def update(name, source=None, pre_versions=False):
'''
# chocolatey helpfully only supports a single package argument
choc_path = _find_chocolatey(__context__, __salt__)
if _LooseVersion(chocolatey_version()) >= _LooseVersion('0.9.8.24'):
log.warning('update is deprecated, using upgrade')
return upgrade(name, source=source, pre_versions=pre_versions)
cmd = [choc_path, 'update', name]
if source:
cmd.extend(['-Source', source])
cmd.extend(['-source', source])
if salt.utils.is_true(pre_versions):
cmd.append('-PreRelease')
cmd.append('-prerelease')
cmd.extend(_yes(__context__))
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
if result['retcode'] not in [0, 1641, 3010]:
err = 'Running chocolatey failed: {0}'.format(result['stderr'])
log.error(err)
raise CommandExecutionError(err)
@ -776,11 +843,11 @@ def version(name, check_remote=False, source=None, pre_versions=False):
cmd = [choc_path, 'list', name]
if not salt.utils.is_true(check_remote):
cmd.append('-LocalOnly')
cmd.append('-localonly')
if salt.utils.is_true(pre_versions):
cmd.append('-Prerelease')
cmd.append('-prerelease')
if source:
cmd.extend(['-Source', source])
cmd.extend(['-source', source])
result = __salt__['cmd.run_all'](cmd, python_shell=False)
@ -797,7 +864,8 @@ def version(name, check_remote=False, source=None, pre_versions=False):
for line in res:
if 'packages found' not in line and 'packages installed' not in line:
for name, ver in ver_re.findall(line):
ret[name] = ver
if name not in ['Did', 'Features?', 'Chocolatey']:
ret[name] = ver
return ret
@ -827,7 +895,7 @@ def add_source(name, source_location, username=None, password=None):
'''
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'sources', 'Add', '-Name', name, "-Source", source_location]
cmd = [choc_path, 'sources', 'add', '-name', name, "-source", source_location]
if username:
cmd.extend(['-u', username])
if password:
@ -854,7 +922,7 @@ def _change_source_state(name, state):
'''
choc_path = _find_chocolatey(__context__, __salt__)
cmd = [choc_path, 'source', state, "-Name", name]
cmd = [choc_path, 'source', state, "-name", name]
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:

View file

@ -46,10 +46,11 @@ except ImportError:
# Import salt libs
import salt.utils
import salt.utils.atomicfile
import salt.utils.find
import salt.utils.filebuffer
import salt.utils.files
import salt.utils.atomicfile
import salt.utils.templates
import salt.utils.url
from salt.exceptions import CommandExecutionError, SaltInvocationError, get_error_message as _get_error_message

View file

@ -23,7 +23,7 @@ def __virtual__():
def _ssh_flag(identity_path):
return '--ssh "ssh -i {0}"'.format(identity_path)
return ['--ssh', 'ssh -i {0}'.format(identity_path)]
def revision(cwd, rev='tip', short=False, user=None):
@ -181,7 +181,7 @@ def pull(cwd, opts=None, user=None, identity=None, repository=None):
'''
cmd = ['hg', 'pull']
if identity:
cmd.append(_ssh_flag(identity))
cmd.extend(_ssh_flag(identity))
if opts:
for opt in opts.split():
cmd.append(opt)
@ -250,7 +250,7 @@ def clone(cwd, repository, opts=None, user=None, identity=None):
for opt in opts.split():
cmd.append('{0}'.format(opt))
if identity:
cmd.append(_ssh_flag(identity))
cmd.extend(_ssh_flag(identity))
return __salt__['cmd.run'](cmd, runas=user, python_shell=False)

View file

@ -2908,12 +2908,21 @@ def privileges_grant(name,
if object_type == 'group':
query = 'GRANT {0} TO "{1}" WITH ADMIN OPTION'.format(
object_name, name)
elif (object_type in ('table', 'sequence') and
object_name.upper() == 'ALL'):
query = 'GRANT {0} ON ALL {1}S IN SCHEMA {2} TO ' \
'"{3}" WITH GRANT OPTION'.format(
_grants, object_type.upper(), prepend, name)
else:
query = 'GRANT {0} ON {1} {2} TO "{3}" WITH GRANT OPTION'.format(
_grants, object_type.upper(), on_part, name)
else:
if object_type == 'group':
query = 'GRANT {0} TO "{1}"'.format(object_name, name)
elif (object_type in ('table', 'sequence') and
object_name.upper() == 'ALL'):
query = 'GRANT {0} ON ALL {1}S IN SCHEMA {2} TO "{3}"'.format(
_grants, object_type.upper(), prepend, name)
else:
query = 'GRANT {0} ON {1} {2} TO "{3}"'.format(
_grants, object_type.upper(), on_part, name)

View file

@ -1126,10 +1126,11 @@ def upgrade(refresh=True, skip_verify=False):
refresh_db()
old = list_pkgs()
to_append = ''
if skip_verify:
to_append = '--no-gpg-checks'
__zypper__(systemd_scope=_systemd_scope()).noraise.call('update', '--auto-agree-with-licenses', to_append)
__zypper__(systemd_scope=_systemd_scope()).noraise.call('update', '--auto-agree-with-licenses', '--no-gpg-checks')
else:
__zypper__(systemd_scope=_systemd_scope()).noraise.call('update', '--auto-agree-with-licenses')
if __zypper__.exit_code not in __zypper__.SUCCESS_EXIT_CODES:
ret['result'] = False
ret['comment'] = (__zypper__.stdout() + os.linesep + __zypper__.stderr()).strip()

View file

@ -375,10 +375,16 @@ def extracted(name,
log.debug('Extracting {0} to {1}'.format(filename, name))
if archive_format == 'zip':
if use_cmd_unzip:
files = __salt__['archive.cmd_unzip'](filename, name, options=zip_options, trim_output=trim_output, **kwargs)
if password is None and salt.utils.which('unzip'):
files = __salt__['archive.cmd_unzip'](filename, name, trim_output=trim_output)
else:
files = __salt__['archive.unzip'](filename, name, options=zip_options, trim_output=trim_output, password=password, **kwargs)
# https://bugs.python.org/issue15795
if password is not None:
log.warning('Password supplied: using archive.unzip')
if not salt.utils.which('unzip'):
log.warning('Cannot find unzip command for archive.cmd_unzip:'
' using archive.unzip instead')
files = __salt__['archive.unzip'](filename, name, trim_output=trim_output, password=password)
elif archive_format == 'rar':
files = __salt__['archive.unrar'](filename, name, trim_output=trim_output, **kwargs)
else:

View file

@ -93,7 +93,8 @@ def present(name,
Name of the role to which privileges should be granted
object_name
Name of the object on which the grant is to be performed
Name of the object on which the grant is to be performed.
'ALL' may be used for objects of type 'table' or 'sequence'.
object_type
The object type, which can be one of the following:

View file

@ -467,7 +467,10 @@ def _interfaces_ifconfig(out):
if not salt.utils.is_sunos():
ipv6scope = mmask6.group(3) or mmask6.group(4)
addr_obj['scope'] = ipv6scope.lower() if ipv6scope is not None else ipv6scope
if addr_obj['address'] != '::' and addr_obj['prefixlen'] != 0: # SunOS sometimes has ::/0 as inet6 addr when using addrconf
# SunOS sometimes has ::/0 as inet6 addr when using addrconf
if not salt.utils.is_sunos() \
or addr_obj['address'] != '::' \
and addr_obj['prefixlen'] != 0:
data['inet6'].append(addr_obj)
data['up'] = updown
if iface in ret:

View file

@ -29,6 +29,7 @@ from distutils.command.build import build
from distutils.command.clean import clean
from distutils.command.sdist import sdist
from distutils.command.install_lib import install_lib
from ctypes.util import find_library
# pylint: enable=E0611
try:
@ -447,6 +448,9 @@ class DownloadWindowsDlls(Command):
dest = os.path.join(os.path.dirname(sys.executable), '{fname}.dll')
with indent_log():
for fname in ('libeay32', 'ssleay32', 'libsodium', 'msvcr120'):
# See if the library is already on the system
if find_library(fname):
continue
furl = url.format(bits=platform_bits[:2], fname=fname)
fdest = dest.format(fname=fname)
if not os.path.exists(fdest):

View file

@ -143,6 +143,7 @@ class TestModulesGrains(integration.ModuleCase):
get_grain, int, msg='grain: {0} is not an int or empty'.format(grain))
@destructiveTest
class GrainsAppendTestCase(integration.ModuleCase):
'''
Tests written specifically for the grains.append function.
@ -150,13 +151,11 @@ class GrainsAppendTestCase(integration.ModuleCase):
GRAIN_KEY = 'salttesting-grain-key'
GRAIN_VAL = 'my-grain-val'
@destructiveTest
def tearDown(self):
test_grain = self.run_function('grains.get', [self.GRAIN_KEY])
if test_grain and test_grain == [self.GRAIN_VAL]:
self.run_function('grains.remove', [self.GRAIN_KEY, self.GRAIN_VAL])
@destructiveTest
def test_grains_append(self):
'''
Tests the return of a simple grains.append call.
@ -164,7 +163,6 @@ class GrainsAppendTestCase(integration.ModuleCase):
ret = self.run_function('grains.append', [self.GRAIN_KEY, self.GRAIN_VAL])
self.assertEqual(ret[self.GRAIN_KEY], [self.GRAIN_VAL])
@destructiveTest
def test_grains_append_val_already_present(self):
'''
Tests the return of a grains.append call when the value is already present in the grains list.
@ -178,7 +176,6 @@ class GrainsAppendTestCase(integration.ModuleCase):
ret = self.run_function('grains.append', [self.GRAIN_KEY, self.GRAIN_VAL])
self.assertEqual(messaging, ret)
@destructiveTest
def test_grains_append_val_is_list(self):
'''
Tests the return of a grains.append call when val is passed in as a list.
@ -187,7 +184,6 @@ class GrainsAppendTestCase(integration.ModuleCase):
ret = self.run_function('grains.append', [self.GRAIN_KEY, [self.GRAIN_VAL, second_grain]])
self.assertEqual(ret[self.GRAIN_KEY], [self.GRAIN_VAL, second_grain])
@destructiveTest
def test_grains_append_call_twice(self):
'''
Tests the return of a grains.append call when the value is already present

View file

@ -1301,6 +1301,34 @@ class PostgresTestCase(TestCase):
host='testhost', port='testport',
password='testpassword', user='testuser', runas='user')
# Test grant on all tables
with patch('salt.modules.postgres._run_psql',
Mock(return_value={'retcode': 0})):
with patch('salt.modules.postgres.has_privileges',
Mock(return_value=False)):
ret = postgres.privileges_grant(
'baruwa',
'ALL',
'table',
'SELECT',
maintenance_db='db_name',
runas='user',
host='testhost',
port='testport',
user='testuser',
password='testpassword'
)
query = 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "baruwa"'
postgres._run_psql.assert_called_once_with(
['/usr/bin/pgsql', '--no-align', '--no-readline',
'--no-password', '--username', 'testuser', '--host',
'testhost', '--port', 'testport', '--dbname', 'db_name',
'-c', query],
host='testhost', port='testport',
password='testpassword', user='testuser', runas='user')
def test_privileges_grant_group(self):
'''
Test granting privileges on group