Merge remote-tracking branch 'upstream/develop' into sam_dev1

This commit is contained in:
Samuel M Smith 2014-10-29 14:47:46 -06:00
commit 4b82b72702
87 changed files with 2032 additions and 1375 deletions

View File

@ -8,7 +8,10 @@ Call for speakers now open. Early-bird and group discounts.
</p>
<h4>SaltStack training</h4>
<p>
<a href="http://www.saltstack.com/training/">
<img src="{{ pathto('_static/images/salt-training.png', 1) }}" alt="" style="padding-bottom: 1em;">
Now offering remote attendee training!
{# <img src="{{ pathto('_static/images/salt-training.png', 1) }}" alt="" style="padding-bottom: 1em;"> #}
</a>
</p>
{% endif %}

View File

@ -10,5 +10,5 @@
<p>Latest Salt release: <a href="{{ pathto('topics/releases/{0}'.format(release)) }}">{{ release }}</a></p>
<p>Try the shiny new release candidate of Salt,
<a href="{{ pathto('topics/releases/2014.7.0') }}">v2014.7.0rc3</a>! More info
<a href="{{ pathto('topics/releases/releasecandidate') }}">here.</a></p>
<a href="{{ pathto('topics/releases/2014.7.0') }}">v2014.7.0rc6</a>! More info
<a href="{{ pathto('topics/releases/releasecandidate') }}">here</a>.</p>

View File

@ -28,8 +28,9 @@ How to Use it
.. note::
Since this option changes the basic behavior of the state runtime states
should be executed in
Since this option changes the basic behavior of the state runtime, after
it is enabled states should be executed using `test=True` to ensure that
the desired behavior is preserved.
Since this behavior can dramatically change the flow of configuration
management inside of Salt it is disabled by default. But enabling it is easy.

View File

@ -210,10 +210,10 @@ examples of "changes" dictionaries.)
If the "changes" key contains a populated dictionary, it means that the
pre-required state expects changes to occur when the state is actually
executed, as opposed to the test-run. The pre-required state will now
actually run. If the pre-required state executes successfully, the
pre-requiring state will then execute. If the pre-required state fails, the
pre-requiring state will not execute.
executed, as opposed to the test-run. The pre-requiring state will now
actually run. If the pre-requiring state executes successfully, the
pre-required state will then execute. If the pre-requiring state fails, the
pre-required state will not execute.
If the "changes" key contains an empty dictionary, this means that changes are
not expected by the pre-required state. Neither the pre-required state nor the

View File

@ -15,3 +15,4 @@ Full list of builtin wheel modules
file_roots
key
pillar_roots
minions

View File

@ -0,0 +1,7 @@
==================
salt.wheel.minions
==================
.. automodule:: salt.wheel.minions
:members:

View File

@ -5,24 +5,19 @@ OS X
Dependency Installation
-----------------------
When installing via Homebrew, dependency resolution is handled for you.
When using Homebrew, install this way:
.. code-block:: bash
brew install saltstack
sudo brew install saltstack
When using macports, zmq, swig, and pip may need to be installed this way:
When using MacPorts, install this way:
.. code-block:: bash
sudo port install py-zmq
sudo port install py27-m2crypto
sudo port install py27-crypto
sudo port install py27-msgpack
sudo port install swig-python
sudo port install py-pip
For installs using the OS X system python, pip install needs to use 'sudo':
sudo port install salt
When only using the OS X system's pip, install this way:
.. code-block:: bash
@ -47,7 +42,7 @@ Now the salt-master should run without errors:
.. code-block:: bash
sudo /usr/local/share/python/salt-master --log-level=all
sudo salt-master --log-level=all
Post-installation tasks
=======================

View File

@ -108,6 +108,18 @@ If this repo is added *before* Salt is installed, then installing either
additional states to upgrade ZeroMQ and pyzmq are unnecessary.
Package Management
==================
Salt's interface to :mod:`yum <salt.modules.yumpkg>` makes heavy use of the
**repoquery** utility, from the yum-utils_ package. This package will be
installed as a dependency if salt is installed via EPEL. However, if salt has
been installed using pip, or a host is being managed using salt-ssh, then as of
version 2014.7.0 yum-utils_ will be installed automatically to satisfy this
dependency.
.. _yum-utils: http://yum.baseurl.org/wiki/YumUtils
Post-installation tasks
=======================

View File

@ -38,6 +38,9 @@ Mapping Events to Reactor SLS Files
Reactor SLS files and event tags are associated in the master config file.
By default this is /etc/salt/master, or /etc/salt/master.d/reactor.conf.
.. versionadded:: 2014.7.0
Added Reactor support for ``salt://`` file paths.
In the master config section 'reactor:' is a list of event tags to be matched
and each event tag has a list of reactor SLS files to be run.
@ -172,14 +175,28 @@ Understanding the Structure of Reactor Formulas
===============================================
While the reactor system uses the same data structure as the state system, this
data does not translate the same way to operations. In state files formula
information is mapped to the state functions, but in the reactor system
information is mapped to a number of available subsystems on the master. These
systems are the :strong:`LocalClient` and the :strong:`Runners`. The
:strong:`state declaration` field takes a reference to the function to call in
each interface. So to trigger a salt-run call the :strong:`state declaration`
field will start with :strong:`runner`, followed by the runner function to
call. This means that a call to what would be on the command line
data does not translate the same way to function calls.
.. versionchanged:: 2014.7.0
The ``cmd`` prefix was renamed to ``local`` for consistency with other
parts of Salt. A backward-compatible alias was added for ``cmd``.
In state files the minion generates the data structure locally and uses that to
call local state functions. In the reactor system the master generates a data
structure that is used to call methods on one of Salt's client interfaces
described in :ref:`the Python API documentation <client-apis>`.
* :py:class:`~salt.client.LocalClient` is used to call Execution modules
remotely on minions. (The :command:`salt` CLI program uses this also.)
* :py:class:`~salt.runner.RunnerClient` calls Runner modules locally on the
master.
* :py:class:`~salt.wheel.WheelClient` calls Wheel modules locally on the
master.
The :strong:`state declaration` field takes a reference to the function to call
in each interface. So to trigger a salt-run call the :strong:`state
declaration` field will start with :strong:`runner`, followed by the runner
function to call. This means that a call to what would be on the command line
:strong:`salt-run manage.up` will be :strong:`runner.manage.up`. An example of
this in a reactor formula would look like this:

View File

@ -6,6 +6,20 @@ This release is the largest Salt release ever, with more features and commits
then any previous release of Salt. Everything from the new RAET transport to
major updates in Salt Cloud and the merging of Salt API into the main project.
.. important::
The Fedora/RHEL/CentOS **salt-master** package has been modified for this
release. The following components of Salt have been broken out and placed
into their own packages:
* salt-syndic
* salt-cloud
* salt-ssh
When the **salt-master** package is upgraded, these components will be
removed, and they will need to be manually installed.
New Transport!
==============
@ -29,12 +43,12 @@ Simply stated, users running Salt with RAET should expect some hiccups as we
hammer out the update. This is a BETA release of Salt RAET.
For information about how to use Salt with RAET please see the
:doc:`tutorial </topics/transports/raet/programming_intro>`.
:doc:`tutorial </topics/transports/raet/index>`.
Salt SSH Enhancements
=====================
Salt SSH has just entered a new league, which substantial updates and
Salt SSH has just entered a new league, with substantial updates and
improvements to make salt-ssh more reliable and easier then ever! From new
features like the ansible roster and fileserver backends to the new pypi
salt-ssh installer to lowered deps and a swath of bugfixes, salt-ssh is
@ -58,7 +72,7 @@ which may be seen can be safely ignored.
Fileserver Backends
-------------------
Salt-ssh can now use the salt fileserver backend system, this allows for
Salt-ssh can now use the salt fileserver backend system. This allows for
the gitfs, hgfs, s3, and many more ways to centrally store states to be easily
used with salt-ssh. This also allows for a distributed team to easily use
a centralized source.
@ -78,8 +92,8 @@ to use salt-ssh with teams.
No More sshpass
---------------
Thanks to the enhancements in the salt vt system salt-ssh no longer requires
sshpass to send passwords to ssh, this also makes the manipulation of ssh
Thanks to the enhancements in the salt vt system, salt-ssh no longer requires
sshpass to send passwords to ssh. This also makes the manipulation of ssh
calls substantially more flexible, allowing for intercepting ssh calls in
a much more fluid way.
@ -109,11 +123,11 @@ More Thin Directory Options
---------------------------
Salt ssh functions by copying a subset of the salt code, or `salt thin` down
to the target system. In the past this was always transfered to /tmp/.salt
to the target system. In the past this was always transferred to /tmp/.salt
and cached there for subsequent commands.
Now, salt thin can be sent to a random directory and removed when the call
is complete with the `-W` option. The new `-w` option still uses a static
is complete with the `-W` option. The new `-W` option still uses a static
location but will clean up that location when finished.
The default `salt thin` location is now user defined, allowing multiple users
@ -125,9 +139,9 @@ State System Enhancements
New Imperative State Keyword "Listen"
-------------------------------------
The new ``listen`` keyword allows for completely imperative states by calling
the ``mod_watch()`` routine after all states have run instead of re-ordering
the states.
The new ``listen`` and ``listen_in`` keywords allow for completely imperative
states by calling the ``mod_watch()`` routine after all states have run instead
of re-ordering the states.
Mod Aggregate Runtime Manipulator
---------------------------------
@ -137,7 +151,7 @@ state data during execution. This allows for state definitions to be aggregated
dynamically at runtime.
The best example is found in the :mod:`pkg <salt.states.pkg>` state. If
``mod_aggregate`` is turned on, then when the first pkg state is reached the
``mod_aggregate`` is turned on, then when the first pkg state is reached, the
state system will scan all of the other running states for pkg states and take
all other packages set for install and install them all at once in the first
pkg state.
@ -152,7 +166,15 @@ For more documentation on ``mod_aggregate``, see :doc:`the documentation
New Requisites: onchanges and onfail
------------------------------------
New requisites!
The new ``onchanges`` and ``onchanges_in`` requisites make a state apply only if
there are changes in the required state. This is useful to execute post hooks
after changes occur on a system.
The other new requisites, ``onfail`` and ``onfail_in``, allow for a state to run
in reaction to the failure of another state.
For more information about these new requisites, see the
:doc:`requisites documentation </ref/states/requisites>`.
Global onlyif and unless
@ -200,7 +222,7 @@ Fileserver Backends in salt-call
Fileserver backends like gitfs can now be used without a salt master! Just add
the fileserver backend configuration to the minion config and execute
salt-call. This has been a much-requested feature and we are heppy to finally
salt-call. This has been a much-requested feature and we are happy to finally
bring it to our users.
Amazon Execution Modules

View File

@ -8,7 +8,7 @@ Salt SSH
.. note::
On many systems, ``salt-ssh`` will be in its own package, usually named
On many systems, the ``salt-ssh`` executable will be in its own package, usually named
``salt-ssh``.
In version 0.17.0 of Salt a new transport system was introduced, the ability

View File

@ -6,8 +6,10 @@ The RAET Transport
The RAET transport is in very early development, it is functional but no
promises are yet made as to its reliability or security.
This document is also not yet complete
As for reliability and security, the encryption used has been audited and
our tests show that raet is reliable. With this said we are still conducting
more security audits and pushing the reliability.
This document outlines the encryption used in RAET
.. versionadded:: 2014.7.0
@ -23,57 +25,12 @@ processes on multiple machines. Messages can also be restricted, allowing
processes to be sent messages of specific types from specific sources
allowing for trust to be established.
Why?
====
Customer and User Request
-------------------------
Why make an alternative transport for Salt? There are many reasons, but the
primary motivation came from customer requests, many large companies came with
requests to run Salt over an alternative transport, the reasoning was varied,
from performance and scaling improvements to licensing concerns. These
customers have partnered with SaltStack to make RAET a reality.
RAET Reliability
================
RAET is reliable, hence the name (Reliable Asynchronous Event Transport).
The concern posed by some over RAET reliability is based on the fact that
RAET used UDP instead of TCP and UDP does not have built in reliability.
RAET itself implements the needed reliability layers that are not natively
present in UDP, this allows RAET to dynamically optimize packet delivery
in a way that keeps it both reliable and asynchronous.
RAET and ZeroMQ
===============
When using RAET, ZeroMQ is not required. RAET is a complete networking
replacement. It is noteworthy that RAET is not a ZeroMQ replacement in a
general sense, the ZeroMQ constructs are not reproduced in RAET, but they are
instead implemented in such a way that is specific to Salt's needs.
RAET is primarily an async communication layer over truly async connections,
defaulting to UDP. ZeroMQ is over TCP and abstracts async constructs within the
socket layer.
Salt is not dropping ZeroMQ support and has no immediate plans to do so.
Encryption
==========
RAET uses Dan Bernstein's NACL encryption libraries and CurveCP handshake.
The libnacl python binding binds to both libsodium and tweetnacl to execute
the underlying cryptography.
Using RAET in Salt
==================
Using RAET in Salt is easy, the main difference is that the core dependencies
change, instead of needing pycrypto, M2Crypto, ZeroMQ and PYZMQ, the packages
libsodium, libnacl and ioflo are required. Encryption is handled very cleanly
libsodium, libnacl, ioflo and raet are required. Encryption is handled very cleanly
by libnacl, while the queueing and flow control is handled by
ioflo. Distribution packages are forthcoming, but libsodium can be easily
installed from source, or many distributions do ship packages for it.
@ -104,3 +61,77 @@ Now start salt as it would normally be started, the minion will connect to the
master and share long term keys, which can then in turn be managed via
salt-key. Remote execution and salt states will function in the same way as
with Salt over ZeroMQ.
Limitations
===========
The 2014.7 release of RAET is not complete! The Syndic and Multi Master have
not been completed yet and these are slated for completetion in the Lithium
release.
Also, Salt-Raet allows for more control over the client but these hooks have
not been implimented yet, thereforre the client still uses the same system
as the ZeroMQ client. This means that the extra reliability that RAET exposes
has not yet been implimented in the CLI client.
Why?
====
Customer and User Request
-------------------------
Why make an alternative transport for Salt? There are many reasons, but the
primary motivation came from customer requests, many large companies came with
requests to run Salt over an alternative transport, the reasoning was varied,
from performance and scaling improvements to licensing concerns. These
customers have partnered with SaltStack to make RAET a reality.
More Capabilities
-----------------
RAET has been designed to allow salt to have greater communication
capabilities. It has been designed to allow for development into features
which out ZeroMQ topologies can't match.
Many of the proposed features are still under development and will be
announced as they enter proff of concept phases, but these features include
`salt-fuse` - a filesystem over salt, `salt-vt` - a paralell api driven shell
over the salt transport and many others.
RAET Reliability
================
RAET is reliable, hence the name (Reliable Asynchronous Event Transport).
The concern posed by some over RAET reliability is based on the fact that
RAET uses UDP instead of TCP and UDP does not have built in reliability.
RAET itself implements the needed reliability layers that are not natively
present in UDP, this allows RAET to dynamically optimize packet delivery
in a way that keeps it both reliable and asynchronous.
RAET and ZeroMQ
===============
When using RAET, ZeroMQ is not required. RAET is a complete networking
replacement. It is noteworthy that RAET is not a ZeroMQ replacement in a
general sense, the ZeroMQ constructs are not reproduced in RAET, but they are
instead implemented in such a way that is specific to Salt's needs.
RAET is primarily an async communication layer over truly async connections,
defaulting to UDP. ZeroMQ is over TCP and abstracts async constructs within the
socket layer.
Salt is not dropping ZeroMQ support and has no immediate plans to do so.
Encryption
==========
RAET uses Dan Bernstein's NACL encryption libraries and CurveCP handshake.
The libnacl python binding binds to both libsodium and tweetnacl to execute
the underlying cryptography. This allows us to completely rely on an
externally developed cryptography system.
For more information on libsodium and CurveCP please see:
http://doc.libsodium.org/
http://curvecp.org/

View File

@ -103,7 +103,7 @@ to them asking that they fetch their pillars from the master:
salt '*' saltutil.refresh_pillar
Now that the minions have the new pillar, it can be retreived:
Now that the minions have the new pillar, it can be retrieved:
.. code-block:: bash

View File

@ -1,3 +1,18 @@
-------------------------------------------------------------------
Thu Oct 16 19:26:57 UTC 2014 - aboe76@gmail.com
- Updated to 2014.1.13 a bugfix release on 2014.1.12
+ fix module run exit code (issue 16420)
+ salt cloud Check the exit status code of scp before assuming it has failed. (issue 16599)
-------------------------------------------------------------------
Fri Oct 10 18:47:07 UTC 2014 - aboe76@gmail.com
ff
- Updated to 2014.1.12 a bugfix release on 2014.1.11
+ Fix scp_file always failing (which broke salt-cloud) (issue 16437)
+ Fix regression in pillar in masterless (issue 16210, issue 16416, issue 16428)
-------------------------------------------------------------------
Wed Sep 10 18:10:50 UTC 2014 - aboe76@gmail.com

View File

@ -15,9 +15,8 @@
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
Name: salt
Version: 2014.1.11
Version: 2014.1.13
Release: 0
Summary: A parallel remote execution system
License: Apache-2.0

View File

@ -1,7 +1,7 @@
Index: salt-2014.1.8/pkg/salt-master.service
===================================================================
--- salt-2014.1.11.orig/pkg/salt-master.service
+++ salt-2014.1.11/pkg/salt-master.service
--- salt-2014.1.13.orig/pkg/salt-master.service
+++ salt-2014.1.13/pkg/salt-master.service
@@ -3,8 +3,10 @@ Description=The Salt Master Server
After=syslog.target network.target

View File

@ -540,7 +540,7 @@ class Single(object):
'root_dir': os.path.join(self.thin_dir, 'running_data'),
'id': self.id,
'sock_dir': '/',
}).strip()
}, width=1000).strip()
self.target = kwargs
self.target.update(args)
self.serial = salt.payload.Serial(opts)

View File

@ -93,6 +93,7 @@ def unpack_ext(ext_path):
'var',
'cache',
'salt',
'minion',
'extmods')
tfile = tarfile.TarFile.gzopen(ext_path)
tfile.extractall(path=modcache)

View File

@ -101,9 +101,9 @@ def avail_images(call=None):
items = query(method='images')
ret = {}
for image in items['images']:
ret[image['name']] = {}
ret[image['id']] = {}
for item in image.keys():
ret[image['name']][item] = str(image[item])
ret[image['id']][item] = str(image[item])
return ret

View File

@ -106,12 +106,12 @@ def avail_images(call=None):
items = query(method='images', command='?page=' + str(page))
for image in items['images']:
ret[image['name']] = {}
ret[image['id']] = {}
for item in image.keys():
ret[image['name']][item] = str(image[item])
ret[image['id']][item] = str(image[item])
page += 1
fetch = next in items['links']['pages']
fetch = 'next' in items['links']['pages']
return ret

View File

@ -43,63 +43,64 @@ Setting up Service Account Authentication:
- Consider using a more secure location for your private key.
Supported commands:
# Create a few instances fro profile_name in /etc/salt/cloud.profiles
- salt-cloud -p profile_name inst1 inst2 inst3
# Delete an instance
- salt-cloud -d inst1
# Look up data on an instance
- salt-cloud -a show_instance inst2
# List available locations (aka 'zones') for provider 'gce'
- salt-cloud --list-locations gce
# List available instance sizes (aka 'machine types') for provider 'gce'
- salt-cloud --list-sizes gce
# List available images for provider 'gce'
- salt-cloud --list-images gce
# Create a persistent disk
- salt-cloud -f create_disk gce disk_name=pd location=us-central1-b ima...
# Permanently delete a persistent disk
- salt-cloud -f delete_disk gce disk_name=pd
# Attach an existing disk to an existing instance
- salt-cloud -a attach_disk myinstance disk_name=mydisk mode=READ_ONLY
# Detach a disk from an instance
- salt-cloud -a detach_disk myinstance disk_name=mydisk
# Show information about the named disk
- salt-cloud -a show_disk myinstance disk_name=pd
- salt-cloud -f show_disk gce disk_name=pd
# Create a snapshot of a persistent disk
- salt-cloud -f create_snapshot gce name=snap-1 disk_name=pd
# Permanently delete a disk snapshot
- salt-cloud -f delete_snapshot gce name=snap-1
# Show information about the named snapshot
- salt-cloud -f show_snapshot gce name=snap-1
# Create a network
- salt-cloud -f create_network gce name=mynet cidr=10.10.10.0/24
# Delete a network
- salt-cloud -f delete_network gce name=mynet
# Show info for a network
- salt-cloud -f show_network gce name=mynet
# Create a firewall rule
- salt-cloud -f create_fwrule gce name=fw1 network=mynet allow=tcp:80
# Delete a firewall rule
- salt-cloud -f delete_fwrule gce name=fw1
# Show info for a firewall rule
-salt-cloud -f show_fwrule gce name=fw1
# Create a load-balancer HTTP health check
- salt-cloud -f create_hc gce name=hc path=/ port=80
# Delete a load-balancer HTTP health check
- salt-cloud -f delete_hc gce name=hc
# Show info about an HTTP health check
- salt-cloud -f show_hc gce name=hc
# Create a load-balancer configuration
- salt-cloud -f create_lb gce name=lb region=us-central1 ports=80 ...
# Delete a load-balancer configuration
- salt-cloud -f delete_lb gce name=lb
# Show details about load-balancer
- salt-cloud -f show_lb gce name=lb
# Add member to load-balancer
- salt-cloud -f attach_lb gce name=lb member=www1
# Remove member from load-balancer
- salt-cloud -f detach_lb gce name=lb member=www1
# Create a few instances fro profile_name in /etc/salt/cloud.profiles
- salt-cloud -p profile_name inst1 inst2 inst3
# Delete an instance
- salt-cloud -d inst1
# Look up data on an instance
- salt-cloud -a show_instance inst2
# List available locations (aka 'zones') for provider 'gce'
- salt-cloud --list-locations gce
# List available instance sizes (aka 'machine types') for provider 'gce'
- salt-cloud --list-sizes gce
# List available images for provider 'gce'
- salt-cloud --list-images gce
# Create a persistent disk
- salt-cloud -f create_disk gce disk_name=pd location=us-central1-b ima...
# Permanently delete a persistent disk
- salt-cloud -f delete_disk gce disk_name=pd
# Attach an existing disk to an existing instance
- salt-cloud -a attach_disk myinstance disk_name=mydisk mode=READ_ONLY
# Detach a disk from an instance
- salt-cloud -a detach_disk myinstance disk_name=mydisk
# Show information about the named disk
- salt-cloud -a show_disk myinstance disk_name=pd
- salt-cloud -f show_disk gce disk_name=pd
# Create a snapshot of a persistent disk
- salt-cloud -f create_snapshot gce name=snap-1 disk_name=pd
# Permanently delete a disk snapshot
- salt-cloud -f delete_snapshot gce name=snap-1
# Show information about the named snapshot
- salt-cloud -f show_snapshot gce name=snap-1
# Create a network
- salt-cloud -f create_network gce name=mynet cidr=10.10.10.0/24
# Delete a network
- salt-cloud -f delete_network gce name=mynet
# Show info for a network
- salt-cloud -f show_network gce name=mynet
# Create a firewall rule
- salt-cloud -f create_fwrule gce name=fw1 network=mynet allow=tcp:80
# Delete a firewall rule
- salt-cloud -f delete_fwrule gce name=fw1
# Show info for a firewall rule
-salt-cloud -f show_fwrule gce name=fw1
# Create a load-balancer HTTP health check
- salt-cloud -f create_hc gce name=hc path=/ port=80
# Delete a load-balancer HTTP health check
- salt-cloud -f delete_hc gce name=hc
# Show info about an HTTP health check
- salt-cloud -f show_hc gce name=hc
# Create a load-balancer configuration
- salt-cloud -f create_lb gce name=lb region=us-central1 ports=80 ...
# Delete a load-balancer configuration
- salt-cloud -f delete_lb gce name=lb
# Show details about load-balancer
- salt-cloud -f show_lb gce name=lb
# Add member to load-balancer
- salt-cloud -f attach_lb gce name=lb member=www1
# Remove member from load-balancer
- salt-cloud -f detach_lb gce name=lb member=www1
.. code-block:: yaml

View File

@ -17,7 +17,7 @@
# CREATED: 10/15/2012 09:49:37 PM WEST
#======================================================================================================================
set -o nounset # Treat unset variables as an error
__ScriptVersion="2014.10.14"
__ScriptVersion="2014.10.28"
__ScriptName="bootstrap-salt.sh"
#======================================================================================================================
@ -202,6 +202,7 @@ _INSECURE_DL=${BS_INSECURE_DL:-$BS_FALSE}
_WGET_ARGS=${BS_WGET_ARGS:-}
_CURL_ARGS=${BS_CURL_ARGS:-}
_FETCH_ARGS=${BS_FETCH_ARGS:-}
_ENABLE_EXTERNAL_ZMQ_REPOS=${BS_ENABLE_EXTERNAL_ZMQ_REPOS:-$BS_FALSE}
_SALT_MASTER_ADDRESS=${BS_SALT_MASTER_ADDRESS:-null}
_SALT_MINION_ID="null"
# __SIMPLIFY_VERSION is mostly used in Solaris based distributions
@ -242,6 +243,7 @@ usage() {
-D Show debug output.
-c Temporary configuration directory
-g Salt repository URL. (default: git://github.com/saltstack/salt.git)
-G Insteady of cloning from git://github.com/saltstack/salt.git, clone from https://github.com/saltstack/salt.git (Usually necessary on systems which have the regular git protocol port blocked, where https usualy is not)
-k Temporary directory holding the minion keys which will pre-seed
the master.
-s Sleep time used when waiting for daemons to start, restart and when checking
@ -271,12 +273,13 @@ usage() {
-p Extra-package to install while installing salt dependencies. One package
per -p flag. You're responsible for providing the proper package name.
-H Use the specified http proxy for the installation
-Z Enable external software source for newer ZeroMQ(Only available for RHEL/CentOS/Fedora based distributions)
EOT
} # ---------- end of function usage ----------
while getopts ":hvnDc:g:k:MSNXCPFUKIA:i:Lp:H:" opt
while getopts ":hvnDc:Gg:k:MSNXCPFUKIA:i:Lp:H:Z" opt
do
case "${opt}" in
@ -297,6 +300,13 @@ do
fi
;;
g ) _SALT_REPO_URL=$OPTARG ;;
G ) if [ "${_SALT_REPO_URL}" = "${_SALTSTACK_REPO_URL}" ]; then
_SALTSTACK_REPO_URL="https://github.com/saltstack/salt.git"
_SALT_REPO_URL=${_SALTSTACK_REPO_URL}
else
_SALTSTACK_REPO_URL="https://github.com/saltstack/salt.git"
fi
;;
k ) _TEMP_KEYS_DIR="$OPTARG"
# If the configuration directory does not exist, error out
if [ ! -d "$_TEMP_KEYS_DIR" ]; then
@ -319,6 +329,7 @@ do
L ) _INSTALL_CLOUD=$BS_TRUE ;;
p ) _EXTRA_PACKAGES="$_EXTRA_PACKAGES $OPTARG" ;;
H ) _HTTP_PROXY="$OPTARG" ;;
Z) _ENABLE_EXTERNAL_ZMQ_REPOS=$BS_TRUE ;;
\?) echo
@ -1124,7 +1135,10 @@ __git_clone_and_checkout() {
echodebug "Installed git version: $(git --version | awk '{ print $3 }')"
__SALT_GIT_CHECKOUT_PARENT_DIR=$(dirname "${__SALT_GIT_CHECKOUT_DIR}")
local __SALT_GIT_CHECKOUT_PARENT_DIR=$(dirname "${__SALT_GIT_CHECKOUT_DIR}" 2>/dev/null)
__SALT_GIT_CHECKOUT_PARENT_DIR="${__SALT_GIT_CHECKOUT_PARENT_DIR:-/tmp/git}"
local __SALT_CHECKOUT_REPONAME="$(basename "${__SALT_GIT_CHECKOUT_DIR}" 2>/dev/null)"
__SALT_CHECKOUT_REPONAME="${__SALT_CHECKOUT_REPONAME:-salt}"
[ -d "${__SALT_GIT_CHECKOUT_PARENT_DIR}" ] || mkdir "${__SALT_GIT_CHECKOUT_PARENT_DIR}"
cd "${__SALT_GIT_CHECKOUT_PARENT_DIR}"
if [ -d "${__SALT_GIT_CHECKOUT_DIR}" ]; then
@ -1170,7 +1184,7 @@ __git_clone_and_checkout() {
if [ "$(git clone --help | grep 'single-branch')" != "" ]; then
# The "--single-branch" option is supported, attempt shallow cloning
echoinfo "Attempting to shallow clone $GIT_REV from Salt's repository ${_SALT_REPO_URL}"
git clone --depth 1 --branch "$GIT_REV" "$_SALT_REPO_URL"
git clone --depth 1 --branch "$GIT_REV" "$_SALT_REPO_URL" "$__SALT_CHECKOUT_REPONAME"
if [ $? -eq 0 ]; then
cd "${__SALT_GIT_CHECKOUT_DIR}"
__SHALLOW_CLONE="${BS_TRUE}"
@ -1178,17 +1192,17 @@ __git_clone_and_checkout() {
# Shallow clone above failed(missing upstream tags???), let's resume the old behaviour.
echowarn "Failed to shallow clone."
echoinfo "Resuming regular git clone and remote SaltStack repository addition procedure"
git clone "$_SALT_REPO_URL" || return 1
git clone "$_SALT_REPO_URL" "$__SALT_CHECKOUT_REPONAME" || return 1
cd "${__SALT_GIT_CHECKOUT_DIR}"
fi
else
echodebug "Shallow cloning not possible. Required git version not met."
git clone "$_SALT_REPO_URL" || return 1
git clone "$_SALT_REPO_URL" "$__SALT_CHECKOUT_REPONAME" || return 1
cd "${__SALT_GIT_CHECKOUT_DIR}"
fi
else
echowarn "The git revision being installed does not match a Salt version tag. Shallow cloning disabled"
git clone "$_SALT_REPO_URL" || return 1
git clone "$_SALT_REPO_URL" "$__SALT_CHECKOUT_REPONAME" || return 1
cd "${__SALT_GIT_CHECKOUT_DIR}"
fi
@ -1540,7 +1554,7 @@ __check_services_debian() {
servicename=$1
echodebug "Checking if service ${servicename} is enabled"
# shellcheck disable=SC2086,SC2046
# shellcheck disable=SC2086,SC2046,SC2144
if [ -f /etc/rc$(runlevel | awk '{ print $2 }').d/S*${servicename} ]; then
echodebug "Service ${servicename} is enabled"
return 0
@ -1695,6 +1709,10 @@ install_ubuntu_deps() {
__apt_get_install_noinput python-apt
if [ "$DISTRO_MAJOR_VERSION" -gt 12 ] || ([ "$DISTRO_MAJOR_VERSION" -eq 12 ] && [ "$DISTRO_MINOR_VERSION" -gt 03 ]); then
if [ "$_ENABLE_EXTERNAL_ZMQ_REPOS" -eq $BS_TRUE ]; then
echoinfo "Installing ZMQ>=4/PyZMQ>=14 from Chris Lea's PPA repository"
add-apt-repository -y ppa:chris-lea/zeromq || return 1
fi
__apt_get_install_noinput python-requests
__PIP_PACKAGES=""
else
@ -2360,6 +2378,10 @@ install_debian_check_services() {
# Fedora Install Functions
#
install_fedora_deps() {
if [ "$_ENABLE_EXTERNAL_ZMQ_REPOS" -eq $BS_TRUE ]; then
__install_saltstack_copr_zeromq_repository || return 1
fi
__PACKAGES="yum-utils PyYAML libyaml m2crypto python-crypto python-jinja2 python-msgpack python-zmq python-requests"
if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then
@ -2415,7 +2437,7 @@ install_fedora_stable_post() {
install_fedora_git_deps() {
install_fedora_deps || return 1
yum install -y git || return 1
yum install -y git systemd-python || return 1
__git_clone_and_checkout || return 1
@ -2531,9 +2553,28 @@ __install_epel_repository() {
return 0
}
__install_saltstack_copr_zeromq_repository() {
echoinfo "Installing Zeromq >=4 and PyZMQ>=14 from SaltStack's COPR repository"
if [ ! -f /etc/yum.repos.d/saltstack-zeromq4.repo ]; then
if [ "${DISTRO_NAME_L}" = "fedora" ]; then
__REPOTYPE="${DISTRO_NAME_L}"
else
__REPOTYPE="epel"
fi
wget -O /etc/yum.repos.d/saltstack-zeromq4.repo \
"https://copr.fedoraproject.org/coprs/saltstack/zeromq4/repo/${__REPOTYPE}-${DISTRO_MAJOR_VERSION}/saltstack-zeromq4-${__REPOTYPE}-${DISTRO_MAJOR_VERSION}.repo" || return 1
fi
return 0
}
install_centos_stable_deps() {
__install_epel_repository || return 1
if [ "$_ENABLE_EXTERNAL_ZMQ_REPOS" -eq $BS_TRUE ]; then
__install_saltstack_copr_zeromq_repository || return 1
fi
if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then
yum -y update || return 1
fi
@ -2674,7 +2715,7 @@ install_centos_git() {
}
install_centos_git_post() {
for fname in minion master minion api; do
for fname in minion master syndic api; do
# Skip if not meant to be installed
[ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue
@ -3344,7 +3385,7 @@ install_arch_linux_git_deps() {
pacman -R --noconfirm --needed python2-distribute
pacman -Sy --noconfirm --needed git python2-crypto python2-setuptools python2-jinja \
python2-m2crypto python2-markupsafe python2-msgpack python2-psutil python2-yaml \
python2-pyzmq zeromq python2-requests || return 1
python2-pyzmq zeromq python2-requests python2-systemd || return 1
__git_clone_and_checkout || return 1
@ -3656,9 +3697,9 @@ install_freebsd_git() {
# Install from git
if [ ! -f salt/syspaths.py ]; then
# We still can't provide the system paths, salt 0.16.x
/usr/local/bin/python setup.py install || return 1
/usr/local/bin/python2 setup.py install || return 1
else
/usr/local/bin/python setup.py install \
/usr/local/bin/python2 setup.py install \
--salt-root-dir=/usr/local \
--salt-config-dir="${_SALT_ETC_DIR}" \
--salt-cache-dir=/var/cache/salt \

View File

@ -294,7 +294,7 @@ DEFAULT_MINION_OPTS = {
'failhard': False,
'autoload_dynamic_modules': True,
'environment': None,
'extension_modules': os.path.join(salt.syspaths.CACHE_DIR, 'extmods'),
'extension_modules': '',
'state_top': 'top.sls',
'startup_states': '',
'sls_list': [],

View File

@ -21,6 +21,7 @@ import salt.crypt
import salt.loader
import salt.payload
import salt.transport
import salt.fileserver
import salt.utils
import salt.utils.templates
import salt.utils.gzip_util

View File

@ -1489,7 +1489,8 @@ class ClearFuncs(object):
pass
elif os.path.isfile(pubfn_rejected):
# The key has been rejected, don't place it in pending
log.info('Public key rejected for {id}'.format(**load))
log.info('Public key rejected for {0}. Key is present in '
'rejection key dir.'.format(load['id']))
eload = {'result': False,
'id': load['id'],
'pub': load['pub']}
@ -2254,14 +2255,17 @@ class ClearFuncs(object):
}
}
# Retrieve the jid
if not clear_load['jid']:
fstr = '{0}.prep_jid'.format(self.opts['master_job_cache'])
try:
clear_load['jid'] = self.mminion.returners[fstr](nocache=extra.get('nocache', False))
except TypeError: # The returner is not present
log.error('The requested returner {0} could not be loaded. Publication not sent.'.format(fstr.split('.')[0]))
return {}
# TODO Error reporting over the master event bus
fstr = '{0}.prep_jid'.format(self.opts['master_job_cache'])
try:
clear_load['jid'] = self.mminion.returners[fstr](nocache=extra.get('nocache', False),
# the jid in clear_load can be None, '', or something else.
# this is an attempt to clean up the value before passing to plugins
passed_jid=clear_load['jid'] if clear_load.get('jid') else None)
except TypeError: # The returner is not present
log.error('The requested returner {0} could not be loaded. Publication not sent.'.format(fstr.split('.')[0]))
return {}
# TODO Error reporting over the master event bus
self.event.fire_event({'minions': minions}, clear_load['jid'])
new_job_load = {

View File

@ -105,10 +105,10 @@ def resolve_dns(opts):
if opts['retry_dns']:
while True:
import salt.log
msg = ('Master hostname: {0} not found. Retrying in {1} '
msg = ('Master hostname: \'{0}\' not found. Retrying in {1} '
'seconds').format(opts['master'], opts['retry_dns'])
if salt.log.is_console_configured():
log.warn(msg)
log.error(msg)
else:
print('WARNING: {0}'.format(msg))
time.sleep(opts['retry_dns'])
@ -711,6 +711,8 @@ class Minion(MinionBase):
' {0}'.format(opts['master']))
if opts['master_shuffle']:
shuffle(opts['master'])
elif opts['__role'] == 'syndic':
log.info('Syndic setting master_syndic to \'{0}\''.format(opts['master']))
# if failed=True, the minion was previously connected
# we're probably called from the minions main-event-loop
@ -1971,16 +1973,18 @@ class Syndic(Minion):
'''
Lock onto the publisher. This is the main event loop for the syndic
'''
# Instantiate the local client
self.local = salt.client.get_local_client(self.opts['_minion_conf_file'])
self.local.event.subscribe('')
self.local.opts['interface'] = self._syndic_interface
signal.signal(signal.SIGTERM, self.clean_die)
log.debug('Syndic {0!r} trying to tune in'.format(self.opts['id']))
self._init_context_and_poller()
# Instantiate the local client
self.local = salt.client.get_local_client(self.opts['_minion_conf_file'])
self.local.event.subscribe('')
self.local.opts['interface'] = self._syndic_interface
# register the event sub to the poller
self.poller.register(self.local.event.sub)
# Start with the publish socket
# Share the poller with the event object
self.socket = self.context.socket(zmq.SUB)

469
salt/modules/drac.py Normal file
View File

@ -0,0 +1,469 @@
# -*- coding: utf-8 -*-
'''
Manage Dell DRAC
'''
import salt.utils
import logging
log = logging.getLogger(__name__)
def __virtual__():
'''
'''
if salt.utils.which('racadm'):
return True
return False
def __parse_drac(output):
'''
Parse Dell DRAC output
'''
drac = {}
section = ''
for i in output.splitlines():
if len(i.rstrip()) > 0 and '=' in i:
if section in drac:
drac[section].update(dict(
[[prop.strip() for prop in i.split('=')]]
))
else:
section = i.strip()[:-1]
if section not in drac and section:
drac[section] = {}
return drac
def __execute_cmd(command):
'''
Execute rac commands
'''
cmd = __salt__['cmd.run_all']('racadm {0}'.format(command))
if cmd['retcode'] != 0:
log.warn('racadm return an exit code \'{0}\'.'.format(cmd['retcode']))
return False
return True
def system_info():
'''
Return System information
CLI Example:
.. code-block:: bash
salt dell drac.getsysinfo
'''
drac = {}
section = ''
cmd = __salt__['cmd.run_all']('racadm getsysinfo')
if cmd['retcode'] != 0:
log.warn('racadm return an exit code \'{0}\'.'.format(cmd['retcode']))
return __parse_drac(cmd['stdout'])
def network_info():
'''
Return Network Configuration
CLI Example:
.. code-block:: bash
salt dell drac.getniccfg
'''
cmd = __salt__['cmd.run_all']('racadm getniccfg')
if cmd['retcode'] != 0:
log.warn('racadm return an exit code \'{0}\'.'.format(cmd['retcode']))
return __parse_drac(cmd['stdout'])
def nameservers(*ns):
'''
Configure the nameservers on the DRAC
CLI Example:
.. code-block:: bash
salt dell drac.nameservers [NAMESERVERS]
salt dell drac.nameservers ns1.example.com ns2.example.com
'''
if len(ns) > 2:
log.warn('racadm only supports two nameservers')
return False
for i in range(1, len(ns) + 1):
if not __execute_cmd('config -g cfgLanNetworking -o \
cfgDNSServer{0} {1}'.format(i, ns[i - 1])):
return False
return True
def syslog(server, enable=True):
'''
Configure syslog remote logging, by default syslog will automatically be
enabled if a server is specified. However, if you want to disable syslog
you will need to specify a server followed by False
CLI Example:
.. code-block:: bash
salt dell drac.syslog [SYSLOG IP] [ENABLE/DISABLE]
salt dell drac.syslog 0.0.0.0 False
'''
if enable:
if __execute_cmd('config -g cfgRemoteHosts -o \
cfgRhostsSyslogEnable 1'):
return __execute_cmd('config -g cfgRemoteHosts -o \
cfgRhostsSyslogServer1 {0}'.format(server))
return __execute_cmd('config -g cfgRemoteHosts -o cfgRhostsSyslogEnable 0')
def email_alerts(action):
'''
Enable/Disable email alerts
CLI Example:
.. code-block:: bash
salt dell drac.email_alerts True
salt dell drac.email_alerts False
'''
if action:
return __execute_cmd('config -g cfgEmailAlert -o \
cfgEmailAlertEnable -i 1 1')
else:
return __execute_cmd('config -g cfgEmailAlert -o \
cfgEmailAlertEnable -i 1 0')
def list_users():
'''
List all DRAC users
CLI Example:
.. code-block:: bash
salt dell drac.list_users
'''
users = {}
_username = ''
for i in range(1, 12):
cmd = __salt__['cmd.run_all']('racadm getconfig -g \
cfgUserAdmin -i {0}'.format(i))
if cmd['retcode'] != 0:
log.warn('racadm return an exit \
code \'{0}\'.'.format(cmd['retcode']))
for user in cmd['stdout'].splitlines():
if 'cfgUserAdminIndex' in user or user.startswith('#'):
continue
(k, v) = user.split('=')
if k.startswith('cfgUserAdminUserName'):
_username = v.strip()
if v:
users[_username] = {'index': i}
else:
break
else:
users[_username].update({k: v})
return users
def delete_user(username, uid=None):
'''
Delete a user
CLI Example:
.. code-block:: bash
salt dell drac.delete_user [USERNAME] [UID - optional]
salt dell drac.delete_user diana 4
'''
if uid is None:
user = list_users()
uid = user[username]['index']
if uid:
return __execute_cmd('config -g cfgUserAdmin -o \
cfgUserAdminUserName -i {0} ""'.format(uid))
else:
log.warn('\'{0}\' does not exist'.format(username))
return False
return True
def change_password(username, password, uid=None):
'''
Change users password
CLI Example:
.. code-block:: bash
salt dell drac.change_password [USERNAME] [PASSWORD] [UID - optional]
salt dell drac.change_password diana secret
'''
if uid is None:
user = list_users()
uid = user[username]['index']
if uid:
return __execute_cmd('config -g cfgUserAdmin -o \
cfgUserAdminPassword -i {0} {1}'.format(uid, password))
else:
log.warn('\'{0}\' does not exist'.format(username))
return False
return True
def create_user(username, password, permissions):
'''
Create user accounts
CLI Example:
.. code-block:: bash
salt dell drac.create_user [USERNAME] [PASSWORD] [PRIVELEGES]
salt dell drac.create_user diana secret login,test_alerts,clear_logs
DRAC Priveleges
* login : Login to iDRAC
* drac : Configure iDRAC
* user_management : Configure Users
* clear_logs : Clear Logs
* server_control_commands : Execute Server Control Commands
* console_redirection : Access Console Redirection
* virtual_media : Access Virtual Media
* test_alerts : Test Alerts
* debug_commands : Execute Debug Commands
'''
_uids = set()
user = list_users()
if username in user:
log.warn('\'{0}\' already exists'.format(username))
return False
for i in user.keys():
_uids.add(user[i]['index'])
uid = sorted(list(set(xrange(2, 12)) - _uids), reverse=True).pop()
# Create user accountvfirst
if not __execute_cmd('config -g cfgUserAdmin -o \
cfgUserAdminUserName -i {0} {1}'.format(uid, username)):
delete_user(username, uid)
return False
# Configure users permissions
if not set_permissions(username, permissions, uid):
log.warn('unable to set user permissions')
delete_user(username, uid)
return False
# Configure users password
if not change_password(username, password, uid):
log.warn('unable to set user password')
delete_user(username, uid)
return False
# Enable users admin
if not __execute_cmd('config -g cfgUserAdmin -o \
cfgUserAdminEnable -i {0} 1'.format(uid)):
delete_user(username, uid)
return False
return True
def set_permissions(username, permissions, uid=None):
'''
Configure users permissions
CLI Example:
.. code-block:: bash
salt dell drac.set_permissions [USERNAME] [PRIVELEGES] [USER INDEX - optional]
salt dell drac.set_permissions diana login,test_alerts,clear_logs 4
DRAC Priveleges
* login : Login to iDRAC
* drac : Configure iDRAC
* user_management : Configure Users
* clear_logs : Clear Logs
* server_control_commands : Execute Server Control Commands
* console_redirection : Access Console Redirection
* virtual_media : Access Virtual Media
* test_alerts : Test Alerts
* debug_commands : Execute Debug Commands
'''
privileges = {'login': '0x0000001',
'drac': '0x0000002',
'user_management': '0x0000004',
'clear_logs': '0x0000008',
'server_control_commands': '0x0000010',
'console_redirection': '0x0000020',
'virtual_media': '0x0000040',
'test_alerts': '0x0000080',
'debug_commands': '0x0000100'}
permission = 0
# When users don't provide a user ID we need to search for this
if uid is None:
user = list_users()
uid = user[username]['index']
# Generate privilege bit mask
for i in permissions.split(','):
perm = i.strip()
if perm in privileges:
permission += int(privileges[perm], 16)
return __execute_cmd('config -g cfgUserAdmin -o \
cfgUserAdminPrivilege -i {0} 0x{1:08X}'.format(uid, permission))
def set_snmp(community):
'''
Configure SNMP community string
CLI Example:
.. code-block:: bash
salt dell drac.set_snmp [COMMUNITY]
salt dell drac.set_snmp public
'''
return __execute_cmd('config -g cfgOobSnmp -o \
cfgOobSnmpAgentCommunity {0}'.format(community))
def set_network(ip, netmask, gateway):
'''
Configure Network
CLI Example:
.. code-block:: bash
salt dell drac.set_network [DRAC IP] [NETMASK] [GATEWAY]
salt dell drac.set_network 192.168.0.2 255.255.255.0 192.168.0.1
'''
return __execute_cmd('setniccfg -s {0} {1} {2}'.format(
ip, netmask, gateway
))
def server_reboot():
'''
Issues a power-cycle operation on the managed server. This action is
similar to pressing the power button on the system's front panel to
power down and then power up the system.
CLI Example:
.. code-block:: bash
salt dell drac.server_reboot
'''
return __execute_cmd('serveraction powercycle')
def server_poweroff():
'''
Powers down the managed server.
CLI Example:
.. code-block:: bash
salt dell drac.server_poweroff
'''
return __execute_cmd('serveraction powerdown')
def server_poweron():
'''
Powers up the managed server.
CLI Example:
.. code-block:: bash
salt dell drac.server_poweron
'''
return __execute_cmd('serveraction powerup')
def server_hardreset():
'''
Performs a reset (reboot) operation on the managed server.
CLI Example:
.. code-block:: bash
salt dell drac.server_hardreset
'''
return __execute_cmd('serveraction hardreset')
def server_pxe():
'''
Configure server to PXE perform a one off PXE boot
CLI Example:
.. code-block:: bash
salt dell drac.server_pxe
'''
if __execute_cmd('config -g cfgServerInfo -o \
cfgServerFirstBootDevice PXE'):
if __execute_cmd('config -g cfgServerInfo -o cfgServerBootOnce 1'):
return server_reboot
else:
log.warn('failed to set boot order')
return False
log.warn('failed to to configure PXE boot')
return False

View File

@ -98,8 +98,9 @@ def list_pkgs(versions_as_list=False, **kwargs):
salt '*' pkg.list_pkgs
'''
versions_as_list = salt.utils.is_true(versions_as_list)
# 'removed' not yet implemented or not applicable
if salt.utils.is_true(kwargs.get('removed')):
# 'removed', 'purge_desired' not yet implemented or not applicable
if any([salt.utils.is_true(kwargs.get(x))
for x in ('removed', 'purge_desired')]):
return {}
if 'pkg.list_pkgs' in __context__:

View File

@ -197,6 +197,7 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
process_dependency_links=False,
__env__=None,
saltenv='base',
env_vars=None,
use_vt=False):
'''
Install packages with pip
@ -311,6 +312,11 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
Enable the processing of dependency links
use_vt
Use VT terminal emulation (see ouptut while installing)
env_vars
Set environment variables that some builds will depend on. For example,
a Python C-module may have a Makefile that needs INCLUDE_PATH set to
pick up a header file while compiling.
CLI Example:
@ -576,6 +582,9 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
if process_dependency_links:
cmd.append('--process-dependency-links')
if env_vars:
os.environ.update(env_vars)
try:
cmd_kwargs = dict(runas=user, cwd=cwd, saltenv=saltenv, use_vt=use_vt)
if bin_env and os.path.isdir(bin_env):

View File

@ -29,7 +29,7 @@ def __virtual__():
enabled = ('amazon', 'xcp', 'xenserver')
if os_family == 'redhat' or os_grain in enabled:
if os_family in ['redhat', 'suse'] or os_grain in enabled:
return __virtualname__
return False
@ -183,3 +183,34 @@ def file_dict(*packages):
files.append(line)
ret[pkg] = files
return {'errors': errors, 'packages': ret}
def owner(*paths):
'''
Return the name of the package that owns the file. Multiple file paths can
be passed. If a single path is passed, a string will be returned,
and if multiple paths are passed, a dictionary of file/package name pairs
will be returned.
If the file is not owned by a package, or is not present on the minion,
then an empty string will be returned for that path.
CLI Examples:
.. code-block:: bash
salt '*' lowpkg.owner /usr/bin/apachectl
salt '*' lowpkg.owner /usr/bin/apachectl /etc/httpd/conf/httpd.conf
'''
if not paths:
return ''
ret = {}
cmd = 'rpm -qf --queryformat "%{{NAME}}" {0!r}'
for path in paths:
ret[path] = __salt__['cmd.run_stdout'](cmd.format(path),
output_loglevel='trace')
if 'not owned' in ret[path].lower():
ret[path] = ''
if len(ret) == 1:
return ret.values()[0]
return ret

View File

@ -1,77 +1,265 @@
# -*- coding: utf-8 -*-
'''
Module for notifications via Slack.
See https://slack.com for more info.
Module for sending messages to Slack
.. versionadded:: Lithium
:depends: - pyslack python module
:configuration: Configure this module by specifying the name of a configuration
profile in the minion config, minion pillar, or master config.
:configuration: This module can be used by either passing an api key and version
directly or by specifying both in a configuration profile in the salt
master/minion config.
For example:
.. code-block:: yaml
slack.api_token: <api token>
slack.username: salt-bot
slack:
api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15
'''
import requests
import logging
from salt.exceptions import CommandExecutionError
HAS_LIBS = False
try:
import slack
import slack.chat
from slack.exception import ChannelNotFoundError
from slack.exception import NotAuthedError
HAS_LIBS = True
except ImportError:
pass
from urlparse import urljoin as _urljoin
from requests.exceptions import ConnectionError
log = logging.getLogger(__name__)
__virtualname__ = 'slack'
def __virtual__():
'''
Only load this module if slack is installed on this minion.
Return virtual name of the module.
:return: The virtual name of the module.
'''
if HAS_LIBS:
return __virtualname__
return False
return __virtualname__
def _setup():
def _query(function, api_key=None, method='GET', data=None):
'''
Return the slack connection
Slack object method function to construct and execute on the API URL.
:param api_key: The Slack api key.
:param function: The Slack api function to perform.
:param method: The HTTP method, e.g. GET or POST.
:param data: The data to be sent for POST method.
:return: The json response from the API call or False.
'''
creds = {}
creds['api_token'] = __salt__['config.option']('slack.api_token')
creds['username'] = __salt__['config.option']('slack.username')
slack.api_token = creds.get('api_token')
return creds
headers = {}
query_params = {}
if data is None:
data = {}
ret = {'message': '',
'res': True}
slack_functions = {
'rooms': {
'request': 'channels.list',
'response': 'channels',
},
'users': {
'request': 'users.list',
'response': 'members',
},
'message': {
'request': 'chat.postMessage',
'response': 'channel',
},
}
if not api_key:
try:
options = __salt__['config.option']('slack')
if not api_key:
api_key = options.get('api_key')
except (NameError, KeyError, AttributeError):
log.error('No Slack api key found.')
ret['message'] = 'No Slack api key found.'
ret['res'] = False
return ret
api_url = 'https://slack.com'
base_url = _urljoin(api_url, '/api/')
path = slack_functions.get(function).get('request')
url = _urljoin(base_url, path, False)
query_params['token'] = api_key
try:
result = requests.request(
method=method,
url=url,
headers=headers,
params=query_params,
data=data,
verify=True,
)
except ConnectionError as e:
ret['message'] = e
ret['res'] = False
return ret
if result.status_code == 200:
result = result.json()
response = slack_functions.get(function).get('response')
if 'error' in result:
ret['message'] = result['error']
ret['res'] = False
return ret
ret['message'] = result.get(response)
return ret
elif result.status_code == 204:
return True
else:
log.debug(url)
log.debug(query_params)
log.debug(data)
log.debug(result)
if 'error' in result:
ret['message'] = result['error']
ret['res'] = False
return ret
ret['message'] = result
return ret
def post_message(message, channel='#general', username=None):
def list_rooms(api_key=None):
'''
Post a message to a channel
List all Slack rooms.
:param api_key: The Slack admin api key.
:return: The room list.
CLI Example:
.. code-block:: yaml
.. code-block:: bash
salt '*' slack.post_message 'Test message'
salt '*' slack.list_rooms
salt '*' slack.list_rooms api_key=peWcBiMOS9HrZG15peWcBiMOS9HrZG15
'''
ret = {}
creds = _setup()
if username is None:
username = creds['username']
try:
ret = slack.chat.post_message(channel, message, username=username)
except ChannelNotFoundError as exc:
raise CommandExecutionError('Channel "{0}" does not exist. {1}'.format(channel, exc))
except NotAuthedError as exc:
raise CommandExecutionError('Authentication Failed. {0}'.format(exc))
return ret
return _query(function='rooms', api_key=api_key)
def list_users(api_key=None):
'''
List all Slack users.
:param api_key: The Slack admin api key.
:return: The user list.
CLI Example:
.. code-block:: bash
salt '*' slack.list_users
salt '*' slack.list_users api_key=peWcBiMOS9HrZG15peWcBiMOS9HrZG15
'''
return _query(function='users', api_key=api_key)
def find_room(name, api_key=None):
'''
Find a room by name and return it.
:param name: The room name.
:param api_key: The Slack admin api key.
:return: The room object.
CLI Example:
.. code-block:: bash
salt '*' slack.find_room name="random"
salt '*' slack.find_room name="random" api_key=peWcBiMOS9HrZG15peWcBiMOS9HrZG15
'''
# search results don't include the name of the
# channel with a hash, if the passed channel name
# has a hash we remove it.
if name.startswith('#'):
name = name[1:]
ret = list_rooms(api_key)
if ret['res']:
rooms = ret['message']
if rooms:
for room in range(0, len(rooms)):
if rooms[room]['name'] == name:
return rooms[room]
return False
def find_user(name, api_key=None):
'''
Find a user by name and return it.
:param name: The user name.
:param api_key: The Slack admin api key.
:return: The user object.
CLI Example:
.. code-block:: bash
salt '*' slack.find_user name="ThomasHatch"
salt '*' slack.find_user name="ThomasHatch" api_key=peWcBiMOS9HrZG15peWcBiMOS9HrZG15
'''
ret = list_users(api_key)
if ret['res']:
users = ret['message']
if users:
for user in range(0, len(users)):
if users[user]['name'] == name:
return users[user]
return False
def post_message(channel,
message,
from_name,
api_key=None):
'''
Send a message to a Slack channel.
:param channel: The channel name, either will work.
:param message: The message to send to the HipChat room.
:param from_name: Specify who the message is from.
:param api_key: The Slack api key, if not specified in the configuration.
:return: Boolean if message was sent successfully.
CLI Example:
.. code-block:: bash
salt '*' slack.send_message channel="Development Room" message="Build is done" from_name="Build Server"
'''
if not channel:
log.error('channel is a required option.')
# channel must start with a hash
if not channel.startswith('#'):
channel = '#{0}'.format(channel)
if not from_name:
log.error('from_name is a required option.')
if not message:
log.error('message is a required option.')
if not from_name:
log.error('from_name is a required option.')
parameters = dict()
parameters['channel'] = channel
parameters['username'] = from_name
parameters['text'] = message
result = _query(function='message',
api_key=api_key,
method='POST',
data=parameters)
if result['res']:
return True
else:
return result

View File

@ -619,7 +619,7 @@ def fullversion():
continue
if ': ' in line:
comps = line.split(': ')
ret[comps[0]] = comps[1]
ret[comps[0]] = comps[1].lstrip()
return ret

View File

@ -98,8 +98,6 @@ def __get_conn():
- http://libvirt.org/uri.html#URI_config
'''
connection = __salt__['config.get']('libvirt:connection', 'esx')
if connection.startswith('esx://'):
return connection
return connection
def __esxi_auth():

View File

@ -1,6 +1,16 @@
# -*- coding: utf-8 -*-
'''
Support for YUM
.. note::
This module makes heavy use of the **repoquery** utility, from the
yum-utils_ package. This package will be installed as a dependency if salt
is installed via EPEL. However, if salt has been installed using pip, or a
host is being managed using salt-ssh, then as of version 2014.7.0
yum-utils_ will be installed automatically to satisfy this dependency.
.. _yum-utils: http://yum.baseurl.org/wiki/YumUtils
'''
# Import python libs
@ -102,10 +112,27 @@ def _repoquery_pkginfo(repoquery_args):
return ret
def _check_repoquery():
'''
Check for existence of repoquery and install yum-utils if it is not
present.
'''
if not salt.utils.which('repoquery'):
__salt__['cmd.run'](
['yum', '-y', 'install', 'yum-utils'],
python_shell=False,
output_loglevel='trace'
)
# Check again now that we've installed yum-utils
if not salt.utils.which('repoquery'):
raise CommandExecutionError('Unable to install yum-utils')
def _repoquery(repoquery_args, query_format=__QUERYFORMAT):
'''
Runs a repoquery command and returns a list of namedtuples
'''
_check_repoquery()
cmd = 'repoquery --plugins --queryformat="{0}" {1}'.format(
query_format, repoquery_args
)

View File

@ -5,6 +5,7 @@ Module for running ZFS zpool command
# Import Python libs
import os
import stat
import logging
# Import Salt libs
@ -150,15 +151,18 @@ def scrub(pool_name=None):
ret['Error'] = 'Storage pool {0} does not exist'.format(pool_name)
def create(pool_name, *vdevs):
def create(pool_name, *vdevs, **kwargs):
'''
Create a new storage pool
Create a simple zpool, a mirrored zpool, a zpool having nested VDEVs and a hybrid zpool with cache and log drives
CLI Example:
.. code-block:: bash
salt '*' zpool.create myzpool /path/to/vdev1 [/path/to/vdev2] [...]
salt '*' zpool.create myzpool /path/to/vdev1 [...] [force=True|False]
salt '*' zpool.create myzpool mirror /path/to/vdev1 /path/to/vdev2 [...] [force=True|False]
salt '*' zpool.create myzpool mirror /path/to/vdev1 [...] mirror /path/to/vdev2 /path/to/vdev3 [...] [force=True|False]
salt '*' zpool.create myhybridzpool mirror /tmp/file1 [...] log mirror /path/to/vdev1 [...] cache /path/to/vdev2 [...] [force=True|False]
'''
ret = {}
dlist = []
@ -170,26 +174,37 @@ def create(pool_name, *vdevs):
# make sure files are present on filesystem
for vdev in vdevs:
if not os.path.isfile(vdev):
# File is not there error and return
ret[vdev] = '{0} not present on filesystem'.format(vdev)
return ret
else:
dlist.append(vdev)
if vdev not in ['mirror', 'log', 'cache']:
if not os.path.exists(vdev):
# Path doesn't exist so error and return
ret[vdev] = '{0} not present on filesystem'.format(vdev)
return ret
mode = os.stat(vdev).st_mode
if not stat.S_ISBLK(mode) and not stat.S_ISREG(mode):
# Not a block device or file vdev so error and return
ret[vdev] = '{0} is not a block device or a file vdev'.format(vdev)
return ret
dlist.append(vdev)
devs = ' '.join(dlist)
zpool = _check_zpool()
cmd = '{0} create {1} {2}'.format(zpool, pool_name, devs)
force = kwargs.get('force', False)
if force is True:
cmd = '{0} create -f {1} {2}'.format(zpool, pool_name, devs)
else:
cmd = '{0} create {1} {2}'.format(zpool, pool_name, devs)
# Create storage pool
__salt__['cmd.run'](cmd)
res = __salt__['cmd.run'](cmd)
# Check and see if the pools is available
if exists(pool_name):
ret[pool_name] = 'created'
return ret
else:
ret['Error'] = 'Unable to create storage pool {0}'.format(pool_name)
ret['Error'] = {}
ret['Error']['Messsage'] = 'Unable to create storage pool {0}'.format(pool_name)
ret['Error']['Reason'] = res
return ret

View File

@ -7,6 +7,8 @@ Package support for openSUSE via the zypper package manager
import copy
import logging
import re
import os
from xml.dom import minidom as dom
from contextlib import contextmanager as _contextmanager
# Import salt libs
@ -18,6 +20,7 @@ from salt.exceptions import (
log = logging.getLogger(__name__)
HAS_ZYPP = False
LOCKS = "/etc/zypp/locks"
try:
import zypp
@ -847,3 +850,238 @@ def purge(name=None, pkgs=None, **kwargs):
salt '*' pkg.purge pkgs='["foo", "bar"]'
'''
return _uninstall(action='purge', name=name, pkgs=pkgs)
def list_locks():
'''
List current package locks.
Return a dict containing the locked package with attributes::
{'<package>': {'case_sensitive': '<case_sensitive>',
'match_type': '<match_type>'
'type': '<type>'}}
CLI Example:
.. code-block:: bash
salt '*' pkg.list_locks
'''
if not os.path.exists(LOCKS):
return False
locks = {}
for meta in map(lambda item: item.split("\n"),
open(LOCKS).read().split("\n\n")):
lock = {}
for element in [el for el in meta if el]:
if ":" in element:
lock.update(dict([tuple(map(lambda i: i.strip(),
element.split(":", 1))), ]))
if lock.get('solvable_name'):
locks[lock.pop('solvable_name')] = lock
return locks
def clean_locks():
'''
Remove unused locks that do not currently (with regard to repositories used) lock any package.
CLI Example:
.. code-block:: bash
salt '*' pkg.clean_locks
'''
if not os.path.exists(LOCKS):
return False
cmd = ('zypper --non-interactive cl')
__salt__['cmd.run'](cmd, output_loglevel='trace')
return True
def remove_lock(name=None, pkgs=None, **kwargs):
'''
Remove specified package lock.
CLI Example:
.. code-block:: bash
salt '*' pkg.remove_lock <package name>
salt '*' pkg.remove_lock <package1>,<package2>,<package3>
salt '*' pkg.remove_lock pkgs='["foo", "bar"]'
'''
locks = list_locks()
packages = []
try:
packages = __salt__['pkg_resource.parse_targets'](name, pkgs)[0].keys()
except MinionError as exc:
raise CommandExecutionError(exc)
removed = []
missing = []
for pkg in packages:
if locks.get(pkg):
removed.append(pkg)
else:
missing.append(pkg)
if removed:
__salt__['cmd.run'](('zypper --non-interactive rl {0}'.format(' '.join(removed))),
output_loglevel='trace')
return {'removed': len(removed), 'not_found': missing}
def add_lock(name=None, pkgs=None, **kwargs):
'''
Add a package lock. Specify packages to lock by exact name.
CLI Example:
.. code-block:: bash
salt '*' pkg.add_lock <package name>
salt '*' pkg.add_lock <package1>,<package2>,<package3>
salt '*' pkg.add_lock pkgs='["foo", "bar"]'
'''
locks = list_locks()
packages = []
added = []
try:
packages = __salt__['pkg_resource.parse_targets'](name, pkgs)[0].keys()
except MinionError as exc:
raise CommandExecutionError(exc)
for pkg in packages:
if not locks.get(pkg):
added.append(pkg)
if added:
__salt__['cmd.run'](('zypper --non-interactive al {0}'.format(' '.join(added))),
output_loglevel='trace')
return {'added': len(added), 'packages': added}
def verify(*names, **kwargs):
'''
Runs an rpm -Va on a system, and returns the results in a dict
Files with an attribute of config, doc, ghost, license or readme in the
package header can be ignored using the ``ignore_types`` keyword argument
CLI Example:
.. code-block:: bash
salt '*' pkg.verify
salt '*' pkg.verify httpd
salt '*' pkg.verify 'httpd postfix'
salt '*' pkg.verify 'httpd postfix' ignore_types=['config','doc']
'''
return __salt__['lowpkg.verify'](*names, **kwargs)
def file_list(*packages):
'''
List the files that belong to a package. Not specifying any packages will
return a list of *every* file on the system's rpm database (not generally
recommended).
CLI Examples:
.. code-block:: bash
salt '*' pkg.file_list httpd
salt '*' pkg.file_list httpd postfix
salt '*' pkg.file_list
'''
return __salt__['lowpkg.file_list'](*packages)
def file_dict(*packages):
'''
List the files that belong to a package, grouped by package. Not
specifying any packages will return a list of *every* file on the system's
rpm database (not generally recommended).
CLI Examples:
.. code-block:: bash
salt '*' pkg.file_list httpd
salt '*' pkg.file_list httpd postfix
salt '*' pkg.file_list
'''
return __salt__['lowpkg.file_dict'](*packages)
def owner(*paths):
'''
Return the name of the package that owns the file. Multiple file paths can
be passed. If a single path is passed, a string will be returned,
and if multiple paths are passed, a dictionary of file/package name
pairs will be returned.
If the file is not owned by a package, or is not present on the minion,
then an empty string will be returned for that path.
CLI Examples:
.. code-block:: bash
salt '*' pkg.owner /usr/bin/apachectl
salt '*' pkg.owner /usr/bin/apachectl /etc/httpd/conf/httpd.conf
'''
return __salt__['lowpkg.owner'](*paths)
def _get_patterns(installed_only=None):
'''
List all known patterns in repos.
'''
patterns = {}
doc = dom.parseString(__salt__['cmd.run'](('zypper --xmlout se -t pattern'),
output_loglevel='trace'))
for element in doc.getElementsByTagName("solvable"):
installed = element.getAttribute("status") == "installed"
if (installed_only and installed) or not installed_only:
patterns[element.getAttribute("name")] = {
'installed': installed,
'summary': element.getAttribute("summary"),
}
return patterns
def list_patterns():
'''
List all known patterns from available repos.
CLI Examples:
.. code-block:: bash
salt '*' pkg.list_patterns
'''
return _get_patterns()
def list_installed_patterns():
'''
List installed patterns on the system.
CLI Examples:
.. code-block:: bash
salt '*' pkg.list_installed_patterns
'''
return _get_patterns(installed_only=True)

View File

@ -232,8 +232,8 @@ def returner(ret):
total_sent_bytes += sent_bytes
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -74,9 +74,8 @@ def returner(ret):
ccf.insert(ret['jid'], columns)
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any work necessary to prepare the jid for storage,
including returning a custom jid
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -119,22 +119,28 @@ def _get_ttl():
#TODO: add to returner docs-- this is a new one
def prep_jid(nocache=False):
def prep_jid(nocache=False, passed_jid=None):
'''
Return a job id and prepare the job id directory
This is the function responsible for making sure jids don't collide (unless its passed a jid)
So do what you have to do to make sure that stays the case
'''
if passed_jid is None:
jid = salt.utils.gen_jid()
else:
jid = passed_jid
cb_ = _get_connection()
jid = salt.utils.gen_jid()
try:
cb_.add(str(jid),
{'nocache': nocache},
ttl=_get_ttl(),
)
except couchbase.exceptions.KeyExistsError:
return prep_jid(nocache=nocache)
# TODO: some sort of sleep or something? Spinning is generally bad practice
if passed_jid is None:
return prep_jid(nocache=nocache)
return jid

View File

@ -349,8 +349,8 @@ def set_salt_view():
return True
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any necessary pre-processing and return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -148,9 +148,8 @@ def returner(ret):
)
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Prepare the jid, including doing any pre-processing and
returning the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -168,8 +168,8 @@ def get_minions():
return ret
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Pre-process the JID and return the JID to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -97,13 +97,16 @@ def _format_jid_instance(jid, job):
#TODO: add to returner docs-- this is a new one
def prep_jid(nocache=False):
def prep_jid(nocache=False, passed_jid=None):
'''
Return a job id and prepare the job id directory
This is the function responsible for making sure jids don't collide (unless its passed a jid)
So do what you have to do to make sure that stays the case
'''
jid = salt.utils.gen_jid()
if passed_jid is None: # this can be a None of an empty string
jid = salt.utils.gen_jid()
else:
jid = passed_jid
jid_dir_ = _jid_dir(jid)
@ -113,7 +116,8 @@ def prep_jid(nocache=False):
os.makedirs(jid_dir_)
except OSError:
# TODO: some sort of sleep or something? Spinning is generally bad practice
return prep_jid(nocache=nocache)
if passed_jid is None:
return prep_jid(nocache=nocache)
with salt.utils.fopen(os.path.join(jid_dir_, 'jid'), 'w+') as fn_:
fn_.write(jid)

View File

@ -93,11 +93,11 @@ def _get_serv(ret):
# an integer weight value.
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Pre-process the jid and return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()
def returner(ret):

View File

@ -209,8 +209,8 @@ def get_jids():
return ret
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Pre-process the jid and return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -157,8 +157,8 @@ def get_fun(fun):
return ret
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Pre-process the jid and return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -30,7 +30,7 @@ def _mminion():
return MMINION
def prep_jid(nocache=False):
def prep_jid(nocache=False, passed_jid=None):
'''
Call both with prep_jid on all returners in multi_returner
@ -41,7 +41,7 @@ def prep_jid(nocache=False):
returners is non-trivial
'''
jid = None
jid = passed_jid
for returner in __opts__[CONFIG_KEY]:
if jid is None:
jid = _mminion().returners['{0}.prep_jid'.format(returner)](nocache=nocache)

View File

@ -85,6 +85,7 @@ import logging
# Import salt libs
import salt.returners
import salt.utils
# Import third party libs
try:
@ -148,7 +149,7 @@ def _get_serv(ret=None, commit=False):
try:
yield cursor
except MySQLdb.DatabaseError as err:
error, = err.args
error = err.args
sys.stderr.write(str(error))
cursor.execute("ROLLBACK")
raise err
@ -196,13 +197,11 @@ def get_load(jid):
'''
with _get_serv(ret=None, commit=True) as cur:
sql = '''SELECT load FROM `jids`
WHERE `jid` = '%s';'''
sql = '''SELECT `load` FROM `jids` WHERE `jid` = %s;'''
cur.execute(sql, (jid,))
data = cur.fetchone()
if data:
return json.loads(data)
return json.loads(data[0])
return {}
@ -280,3 +279,10 @@ def get_minions():
for minion in data:
ret.append(minion[0])
return ret
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any work necessary to prepare a JID, including sending a custom id
'''
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -300,8 +300,8 @@ def get_minions():
return ret
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any jid pre-processing and return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -272,8 +272,8 @@ def get_minions():
return ret
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any pre-processing necessary and return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -162,8 +162,8 @@ def get_minions():
return list(serv.smembers('minions'))
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any pre-processing necessary and return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -111,8 +111,8 @@ def returner(ret):
)
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any necessary pre-processing and then return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -0,0 +1,269 @@
# -*- coding: utf-8 -*-
'''
Return salt data via slack
.. versionadded:: Lithium
The following fields can be set in the minion conf file::
slack.channel (required)
slack.api_key (required)
slack.from_name (required)
slack.profile (optional)
Alternative configuration values can be used by prefacing the configuration.
Any values not found in the alternative configuration will be pulled from
the default location::
slack.channel
slack.api_key
slack.from_name
Hipchat settings may also be configured as::
slack:
channel: RoomName
api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
from_name: user@email.com
alternative.slack:
room_id: RoomName
api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
from_name: user@email.com
slack_profile:
api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
from_name: user@email.com
slack:
profile: slack_profile
channel: RoomName
alternative.slack:
profile: slack_profile
channel: RoomName
To use the HipChat returner, append '--return slack' to the salt command. ex:
.. code-block:: bash
salt '*' test.ping --return slack
To use the alternative configuration, append '--return_config alternative' to the salt command. ex:
salt '*' test.ping --return slack --return_config alternative
'''
import salt.returners
import pprint
import requests
import logging
from urlparse import urljoin as _urljoin
from requests.exceptions import ConnectionError
log = logging.getLogger(__name__)
__virtualname__ = 'slack'
def _get_options(ret=None):
'''
Get the slack options from salt.
'''
defaults = {'channel': '#general'}
attrs = {'slack_profile': 'profile',
'channel': 'channel',
'from_name': 'from_name',
'api_key': 'api_key',
}
profile_attr = 'slack_profile'
profile_attrs = {'from_jid': 'from_jid',
'api_key': 'api_key',
'api_version': 'api_key'
}
_options = salt.returners.get_returner_options(__virtualname__,
ret,
attrs,
profile_attr=profile_attr,
profile_attrs=profile_attrs,
__salt__=__salt__,
__opts__=__opts__,
defaults=defaults)
return _options
def __virtual__():
'''
Return virtual name of the module.
:return: The virtual name of the module.
'''
return __virtualname__
def _query(function, api_key=None, method='GET', data=None):
'''
Slack object method function to construct and execute on the API URL.
:param api_key: The Slack api key.
:param function: The Slack api function to perform.
:param method: The HTTP method, e.g. GET or POST.
:param data: The data to be sent for POST method.
:return: The json response from the API call or False.
'''
headers = {}
query_params = {}
if data is None:
data = {}
ret = {'message': '',
'res': True}
slack_functions = {
'rooms': {
'request': 'channels.list',
'response': 'channels',
},
'users': {
'request': 'users.list',
'response': 'members',
},
'message': {
'request': 'chat.postMessage',
'response': 'channel',
},
}
if not api_key:
try:
options = __salt__['config.option']('slack')
if not api_key:
api_key = options.get('api_key')
except (NameError, KeyError, AttributeError):
log.error('No Slack api key found.')
ret['message'] = 'No Slack api key found.'
ret['res'] = False
return ret
api_url = 'https://slack.com'
base_url = _urljoin(api_url, '/api/')
path = slack_functions.get(function).get('request')
url = _urljoin(base_url, path, False)
query_params['token'] = api_key
try:
result = requests.request(
method=method,
url=url,
headers=headers,
params=query_params,
data=data,
verify=True,
)
except ConnectionError as e:
ret['message'] = e
ret['res'] = False
return ret
if result.status_code == 200:
result = result.json()
response = slack_functions.get(function).get('response')
if 'error' in result:
ret['message'] = result['error']
ret['res'] = False
return ret
ret['message'] = result.get(response)
return ret
elif result.status_code == 204:
return True
else:
log.debug(url)
log.debug(query_params)
log.debug(data)
log.debug(result)
if 'error' in result:
ret['message'] = result['error']
ret['res'] = False
return ret
ret['message'] = result
return ret
def _post_message(channel,
message,
from_name,
api_key=None):
'''
Send a message to a HipChat room.
:param room_id: The room id or room name, either will work.
:param message: The message to send to the HipChat room.
:param from_name: Specify who the message is from.
:param api_key: The HipChat api key, if not specified in the configuration.
:param api_version: The HipChat api version, if not specified in the configuration.
:param color: The color for the message, default: yellow.
:param notify: Whether to notify the room, default: False.
:return: Boolean if message was sent successfully.
'''
parameters = dict()
parameters['channel'] = channel
parameters['from'] = from_name
parameters['text'] = message
result = _query(function='message',
api_key=api_key,
method='POST',
data=parameters)
log.debug('result {0}'.format(result))
if result:
return True
else:
return False
def returner(ret):
'''
Send an slack message with the data
'''
_options = _get_options(ret)
channel = _options.get('channel')
from_name = _options.get('from_name')
api_key = _options.get('api_key')
if not channel:
log.error('slack.channel not defined in salt config')
return
if not from_name:
log.error('slack.from_name not defined in salt config')
return
if not api_key:
log.error('slack.api_key not defined in salt config')
return
message = ('id: {0}\r\n'
'function: {1}\r\n'
'function args: {2}\r\n'
'jid: {3}\r\n'
'return: {4}\r\n').format(
ret.get('id'),
ret.get('fun'),
ret.get('fun_args'),
ret.get('jid'),
pprint.pformat(ret.get('return')))
slack = _post_message(channel,
message,
channel,
api_key)
return slack

View File

@ -183,8 +183,8 @@ def returner(ret):
server.quit()
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any necessary pre-processing and return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -271,8 +271,8 @@ def get_minions():
return ret
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any necessary pre-processing and then return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -41,8 +41,8 @@ def returner(ret):
syslog.syslog(syslog.LOG_INFO, 'salt-minion: {0}'.format(json.dumps(ret)))
def prep_jid(nocache): # pylint: disable=unused-argument
def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
'''
Do any necessary pre-preocessing and then return the jid to use
Do any work necessary to prepare a JID, including sending a custom id
'''
return salt.utils.gen_jid()
return passed_jid if passed_jid is not None else salt.utils.gen_jid()

View File

@ -74,7 +74,7 @@ def lookup_jid(jid, ext_source=None, missing=False, outputter=None):
try:
data = mminion.returners['{0}.get_jid'.format(returner)](jid)
except TypeError:
print 'Requested returner could not be loaded. No JIDs could be retreived.'
print 'Requested returner could not be loaded. No JIDs could be retrieved.'
return
for minion in data:
if u'return' in data[minion]:
@ -132,7 +132,7 @@ def list_jobs(ext_source=None,
try:
ret = mminion.returners['{0}.get_jids'.format(returner)]()
except TypeError:
print 'Error: Requested returner could not be loaded. No jobs could be retreived.'
print 'Error: Requested returner could not be loaded. No jobs could be retrieved.'
return
if search_metadata:
@ -200,8 +200,8 @@ def print_job(jid, ext_source=None, outputter=None):
job = mminion.returners['{0}.get_load'.format(returner)](jid)
ret[jid] = _format_jid_instance(jid, job)
except TypeError:
ret[jid]['Result'] = 'Requested returner {0} is not available. Jobs cannot be retreived. '
'Check master log for details.'.format(returner)
ret[jid]['Result'] = ('Requested returner {0} is not available. Jobs cannot be retrieved. '
'Check master log for details.'.format(returner))
return ret
ret[jid]['Result'] = mminion.returners['{0}.get_jid'.format(returner)](jid)
salt.output.display_output(ret, outputter, opts=__opts__)

View File

@ -20,7 +20,7 @@ def __virtual__():
return 'at.at' in __salt__
def present(name, timespec, tag=None, runas=None, user=None, job=None):
def present(name, timespec, tag=None, user=None, job=None):
'''
Add a job to queue.
@ -33,11 +33,6 @@ def present(name, timespec, tag=None, runas=None, user=None, job=None):
tag
Make a tag for the job.
runas
Users run the job.
.. deprecated:: 2014.1.4
user
The user to run the at job
@ -48,7 +43,7 @@ def present(name, timespec, tag=None, runas=None, user=None, job=None):
rose:
at.present:
- job: 'echo "I love saltstack" > love'
- timespec: '9:9 11/09/13'
- timespec: '9:09 11/09/13'
- tag: love
- user: jam
@ -61,30 +56,6 @@ def present(name, timespec, tag=None, runas=None, user=None, job=None):
'comment': 'job {0} is add and will run on {1}'.format(name,
timespec)}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 2014.1.4. Support will be removed in {version}.',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
binary = salt.utils.which('at')
if __opts__['test']:

View File

@ -202,49 +202,3 @@ def change(name, context=None, changes=None, lens=None, **kwargs):
ret['changes'] = changes
return ret
def setvalue(name, prefix=None, changes=None, **kwargs):
'''
.. deprecated:: 2014.7.0
Use :py:func:`~salt.states.augeas.change` instead.
Set a value for a specific augeas path
'''
ret = {'name': name, 'result': False, 'comment': '', 'changes': {}}
args = []
if not changes:
ret['comment'] = '\'changes\' must be specified'
return ret
else:
if not isinstance(changes, list):
ret['comment'] = '\'changes\' must be formatted as a list'
return ret
for change_ in changes:
if not isinstance(change_, dict) or len(change_) > 1:
ret['comment'] = 'Invalidly-formatted change'
return ret
key = next(iter(change_))
args.extend([key, change_[key]])
if prefix is not None:
args.insert(0, 'prefix={0}'.format(prefix))
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'Calling setvalue with {0}'.format(args)
return ret
call = __salt__['augeas.setvalue'](*args)
ret['result'] = call['retval']
if ret['result'] is False:
ret['comment'] = 'Error: {0}'.format(call['error'])
return ret
ret['comment'] = 'Success'
for change_ in changes:
ret['changes'].update(change_)
return ret

View File

@ -39,7 +39,6 @@ the location of composer in the state.
'''
# Import salt libs
import salt.utils
from salt.exceptions import CommandExecutionError, CommandNotFoundError
@ -53,7 +52,6 @@ def __virtual__():
def installed(name,
composer=None,
php=None,
runas=None,
user=None,
prefer_source=None,
prefer_dist=None,
@ -78,11 +76,6 @@ def installed(name,
Location of the php executable to use with composer.
(i.e. /usr/bin/php)
runas
Which system user to run composer as.
.. deprecated:: 2014.1.4
user
Which system user to run composer as.
@ -114,30 +107,6 @@ def installed(name,
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 2014.1.4.',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
try:
call = __salt__['composer.install'](
name,

View File

@ -2288,7 +2288,8 @@ def replace(name,
.. versionadded:: 0.17.0
Params are identical to :py:func:`~salt.modules.file.replace`.
Params are identical to the remote execution function :mod:`file.replace
<salt.modules.file.replace>`.
'''
name = os.path.expanduser(name)
@ -2484,138 +2485,6 @@ def blockreplace(
return ret
def sed(name,
before,
after,
limit='',
backup='.bak',
options='-r -e',
flags='g',
negate_match=False):
'''
.. deprecated:: 0.17.0
Use :py:func:`~salt.states.file.replace` instead.
Maintain a simple edit to a file
The file will be searched for the ``before`` pattern before making the
edit. In general the ``limit`` pattern should be as specific as possible
and ``before`` and ``after`` should contain the minimal text to be changed.
before
A pattern that should exist in the file before the edit.
after
A pattern that should exist in the file after the edit.
limit
An optional second pattern that can limit the scope of the before
pattern.
backup : '.bak'
The extension for the backed-up version of the file before the edit. If
no backups is desired, pass in the empty string: ''
options : ``-r -e``
Any options to pass to the ``sed`` command. ``-r`` uses extended
regular expression syntax and ``-e`` denotes that what follows is an
expression that sed will execute.
flags : ``g``
Any flags to append to the sed expression. ``g`` specifies the edit
should be made globally (and not stop after the first replacement).
negate_match : False
Negate the search command (``!``)
.. versionadded:: 0.17.0
Usage:
.. code-block:: yaml
# Disable the epel repo by default
/etc/yum.repos.d/epel.repo:
file.sed:
- before: 1
- after: 0
- limit: ^enabled=
# Remove ldap from nsswitch
/etc/nsswitch.conf:
file.sed:
- before: 'ldap'
- after: ''
- limit: '^passwd:'
.. versionadded:: 0.9.5
'''
name = os.path.expanduser(name)
ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''}
check_res, check_msg = _check_file(name)
if not check_res:
return _error(ret, check_msg)
# Mandate that before and after are strings
before = str(before)
after = str(after)
# Look for the pattern before attempting the edit
if not __salt__['file.sed_contains'](name,
before,
limit=limit,
flags=flags):
# Pattern not found; don't try to guess why, just tell the user there
# were no changes made, as the changes should only be made once anyway.
# This makes it so users can use backreferences without the state
# coming back as failed all the time.
ret['comment'] = '"before" pattern not found, no changes made'
ret['result'] = True
return ret
if __opts__['test']:
ret['comment'] = 'File {0} is set to be updated'.format(name)
ret['result'] = None
return ret
with salt.utils.fopen(name, 'rb') as fp_:
slines = fp_.readlines()
# should be ok now; perform the edit
retcode = __salt__['file.sed'](path=name,
before=before,
after=after,
limit=limit,
backup=backup,
options=options,
flags=flags,
negate_match=negate_match)['retcode']
if retcode != 0:
ret['result'] = False
ret['comment'] = ('There was an error running sed. '
'Return code {0}').format(retcode)
return ret
with salt.utils.fopen(name, 'rb') as fp_:
nlines = fp_.readlines()
if slines != nlines:
if not salt.utils.istextfile(name):
ret['changes']['diff'] = 'Replace binary file'
else:
# Changes happened, add them
ret['changes']['diff'] = ''.join(difflib.unified_diff(slines,
nlines))
# Don't check the result -- sed is not designed to be able to check
# the result, because of backreferences and so forth. Just report
# that sed was run, and assume it was successful (no error!)
ret['result'] = True
ret['comment'] = 'sed ran without error'
else:
ret['result'] = True
ret['comment'] = 'sed ran without error, but no changes were made'
return ret
def comment(name, regex, char='#', backup='.bak'):
'''
Comment out specified lines in a file.

View File

@ -15,9 +15,6 @@ you can specify what ruby version and gemset to target.
- ruby: jruby@jgemset
'''
# Import salt libs
import salt.utils
def __virtual__():
'''
@ -28,7 +25,6 @@ def __virtual__():
def installed(name, # pylint: disable=C0103
ruby=None,
runas=None,
user=None,
version=None,
rdoc=False,
@ -44,11 +40,6 @@ def installed(name, # pylint: disable=C0103
ruby: None
For RVM or rbenv installations: the ruby version and gemset to target.
runas: None
The user under which to run the ``gem`` command
.. deprecated:: 0.17.0
user: None
The user under which to run the ``gem`` command
@ -72,31 +63,6 @@ def installed(name, # pylint: disable=C0103
Format: http://hostname[:port]
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
gems = __salt__['gem.list'](name, ruby, runas=user)
if name in gems and version is not None and version in gems[name]:
ret['result'] = True
@ -128,7 +94,7 @@ def installed(name, # pylint: disable=C0103
return ret
def removed(name, ruby=None, runas=None, user=None):
def removed(name, ruby=None, user=None):
'''
Make sure that a gem is not installed.
@ -138,11 +104,6 @@ def removed(name, ruby=None, runas=None, user=None):
ruby: None
For RVM or rbenv installations: the ruby version and gemset to target.
runas: None
The user under which to run the ``gem`` command
.. deprecated:: 0.17.0
user: None
The user under which to run the ``gem`` command
@ -150,30 +111,6 @@ def removed(name, ruby=None, runas=None, user=None):
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if name not in __salt__['gem.list'](name, ruby, runas=user):
ret['result'] = True
ret['comment'] = 'Gem is not installed.'

View File

@ -22,7 +22,6 @@ import os.path
import shutil
# Import salt libs
import salt.utils
from salt.exceptions import CommandExecutionError
log = logging.getLogger(__name__)
@ -38,7 +37,6 @@ def __virtual__():
def latest(name,
rev=None,
target=None,
runas=None,
user=None,
force=None,
force_checkout=False,
@ -64,11 +62,6 @@ def latest(name,
target
Name of the target directory where repository is about to be cloned
runas
Name of the user performing repository management operations
.. deprecated:: 0.17.0
user
Name of the user performing repository management operations
@ -162,30 +155,6 @@ def latest(name,
return _fail(ret, '"target" option is required')
target = os.path.expanduser(target)
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
run_check_cmd_kwargs = {'runas': user}
if 'shell' in __grains__:
run_check_cmd_kwargs['shell'] = __grains__['shell']
@ -405,7 +374,7 @@ def latest(name,
return ret
def present(name, bare=True, runas=None, user=None, force=False):
def present(name, bare=True, user=None, force=False):
'''
Make sure the repository is present in the given directory
@ -415,11 +384,6 @@ def present(name, bare=True, runas=None, user=None, force=False):
bare
Create a bare repository (Default: True)
runas
Name of the user performing repository management operations
.. deprecated:: 0.17.0
user
Name of the user performing repository management operations
@ -432,30 +396,6 @@ def present(name, bare=True, runas=None, user=None, force=False):
name = os.path.expanduser(name)
ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
# If the named directory is a git repo return True
if os.path.isdir(name):
if bare and os.path.isfile(os.path.join(name, 'HEAD')):

View File

@ -42,7 +42,6 @@ def latest(name,
rev=None,
target=None,
clean=False,
runas=None,
user=None,
force=False,
opts=False):
@ -61,11 +60,6 @@ def latest(name,
clean
Force a clean update with -C (Default: False)
runas
Name of the user performing repository management operations
.. deprecated:: 0.17.0
user
Name of the user performing repository management operations
@ -79,30 +73,6 @@ def latest(name,
'''
ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if not target:
return _fail(ret, '"target option is required')

View File

@ -338,6 +338,14 @@ def append(name, family='ipv4', **kwargs):
name,
command.strip(),
family)
if kwargs['save']:
if kwargs['save'] is not True:
filename = kwargs['save']
else:
filename = None
__salt__['iptables.save'](filename, family=family)
ret['comment'] += ('\nSaved iptables rule for {0} to: '
'{1} for {2}'.format(name, command.strip(), family))
return ret
if __opts__['test']:
ret['comment'] = 'iptables rule for {0} needs to be set ({1}) for {2}'.format(
@ -409,6 +417,11 @@ def insert(name, family='ipv4', **kwargs):
name,
family,
command.strip())
if 'save' in kwargs:
if kwargs['save']:
__salt__['iptables.save'](filename=None, family=family)
ret['comment'] += ('\nSaved iptables rule for {0} to: '
'{1} for {2}').format(name, command.strip(), family)
return ret
if __opts__['test']:
ret['comment'] = 'iptables rule for {0} needs to be set for {1} ({2})'.format(

View File

@ -129,7 +129,6 @@ def run(name, **kwargs):
return ret
aspec = salt.utils.get_function_argspec(__salt__[name])
args = []
defaults = {}

View File

@ -20,7 +20,6 @@ for the package which provides npm (simply ``npm`` in most cases). Example:
'''
# Import salt libs
import salt.utils
from salt.exceptions import CommandExecutionError, CommandNotFoundError
@ -34,7 +33,6 @@ def __virtual__():
def installed(name,
pkgs=None,
dir=None,
runas=None,
user=None,
force_reinstall=False,
registry=None,
@ -67,11 +65,6 @@ def installed(name,
The target directory in which to install the package, or None for
global installation
runas
The user to run NPM with
.. deprecated:: 0.17.0
user
The user to run NPM with
@ -94,37 +87,13 @@ def installed(name,
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if pkgs is not None:
pkg_list = pkgs
else:
pkg_list = [name]
try:
installed_pkgs = __salt__['npm.list'](dir=dir, runas=runas, env=env)
installed_pkgs = __salt__['npm.list'](dir=dir, runas=user, env=env)
except (CommandNotFoundError, CommandExecutionError) as err:
ret['result'] = False
ret['comment'] = 'Error looking up {0!r}: {1}'.format(name, err)
@ -221,7 +190,6 @@ def installed(name,
def removed(name,
dir=None,
runas=None,
user=None):
'''
Verify that the given package is not installed.
@ -230,11 +198,6 @@ def removed(name,
The target directory in which to install the package, or None for
global installation
runas
The user to run NPM with
.. deprecated:: 0.17.0
user
The user to run NPM with
@ -242,30 +205,6 @@ def removed(name,
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
try:
installed_pkgs = __salt__['npm.list'](dir=dir)
except (CommandExecutionError, CommandNotFoundError) as err:
@ -295,50 +234,18 @@ def removed(name,
def bootstrap(name,
runas=None,
user=None):
'''
Bootstraps a node.js application.
will execute npm install --json on the specified directory
runas
The user to run NPM with
.. deprecated:: 0.17.0
Will execute 'npm install --json' on the specified directory.
user
The user to run NPM with
.. versionadded:: 0.17.0
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
try:
call = __salt__['npm.install'](dir=name, runas=user, pkg=None)

View File

@ -130,6 +130,7 @@ def installed(name,
allow_external=None,
allow_unverified=None,
process_dependency_links=False,
env_vars=None,
use_vt=False):
'''
Make sure the package is installed
@ -267,6 +268,11 @@ def installed(name,
a pip executable. The example below assumes a virtual environment
has been created at ``/foo/.virtualenvs/bar``.
env_vars
Add or modify environment variables. Useful for tweaking build steps,
such as specifying INCLUDE or LIBRARY paths in Makefiles, build scripts or
compiler calls.
use_vt
Use VT terminal emulation (see ouptut while installing)
@ -554,6 +560,7 @@ def installed(name,
allow_unverified=allow_unverified,
process_dependency_links=process_dependency_links,
saltenv=__env__,
env_vars=env_vars,
use_vt=use_vt
)

View File

@ -30,7 +30,6 @@ def present(name,
lc_ctype=None,
owner=None,
template=None,
runas=None,
user=None,
maintenance_db=None,
db_password=None,
@ -62,11 +61,6 @@ def present(name,
template
The template database from which to build this database
runas
System user all operations should be performed on behalf of
.. deprecated:: 0.17.0
user
System user all operations should be performed on behalf of
@ -95,23 +89,6 @@ def present(name,
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
db_args = {
'maintenance_db': maintenance_db,
@ -188,7 +165,6 @@ def present(name,
def absent(name,
runas=None,
user=None,
maintenance_db=None,
db_password=None,
@ -213,11 +189,6 @@ def absent(name,
db_port
Database port if different from config or default
runas
System user all operations should be performed on behalf of
.. deprecated:: 0.17.0
user
System user all operations should be performed on behalf of
@ -227,29 +198,6 @@ def absent(name,
'changes': {},
'result': True,
'comment': ''}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
db_args = {
'maintenance_db': maintenance_db,

View File

@ -14,7 +14,6 @@ The postgres_group module is used to create and manage Postgres groups.
# Import Python libs
# Import salt libs
import salt.utils
import logging
# Salt imports
@ -43,7 +42,6 @@ def present(name,
password=None,
refresh_password=None,
groups=None,
runas=None,
user=None,
maintenance_db=None,
db_password=None,
@ -109,11 +107,6 @@ def present(name,
groups
A string of comma separated groups the group should be in
runas
System user all operations should be performed on behalf of
.. deprecated:: 0.17.0
user
System user all operations should be performed on behalf of
@ -136,12 +129,6 @@ def present(name,
'result': True,
'comment': 'Group {0} is already present'.format(name)}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if createuser:
createroles = True
# default to encrypted passwords
@ -151,24 +138,6 @@ def present(name,
password = postgres._maybe_encrypt_password(name,
password,
encrypted=encrypted)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
db_args = {
'maintenance_db': maintenance_db,
'runas': user,
@ -250,7 +219,6 @@ def present(name,
def absent(name,
runas=None,
user=None,
maintenance_db=None,
db_password=None,
@ -263,11 +231,6 @@ def absent(name,
name
The groupname of the group to remove
runas
System user all operations should be performed on behalf of
.. deprecated:: 0.17.0
user
System user all operations should be performed on behalf of
@ -290,30 +253,6 @@ def absent(name,
'result': True,
'comment': ''}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
db_args = {
'maintenance_db': maintenance_db,
'runas': user,

View File

@ -14,7 +14,6 @@ The postgres_users module is used to create and manage Postgres users.
# Import Python libs
# Import salt libs
import salt.utils
import logging
# Salt imports
@ -43,7 +42,6 @@ def present(name,
password=None,
refresh_password=None,
groups=None,
runas=None,
user=None,
maintenance_db=None,
db_password=None,
@ -108,11 +106,6 @@ def present(name,
groups
A string of comma separated groups the user should be in
runas
System user all operations should be performed on behalf of
.. deprecated:: 0.17.0
user
System user all operations should be performed on behalf of
@ -135,12 +128,6 @@ def present(name,
'result': True,
'comment': 'User {0} is already present'.format(name)}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if createuser:
createroles = True
# default to encrypted passwords
@ -151,24 +138,6 @@ def present(name,
password,
encrypted=encrypted)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
db_args = {
'maintenance_db': maintenance_db,
'runas': user,
@ -254,7 +223,6 @@ def present(name,
def absent(name,
runas=None,
user=None,
maintenance_db=None,
db_password=None,
@ -267,11 +235,6 @@ def absent(name,
name
The username of the user to remove
runas
System user all operations should be performed on behalf of
.. deprecated:: 0.17.0
user
System user all operations should be performed on behalf of
@ -294,30 +257,6 @@ def absent(name,
'result': True,
'comment': ''}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
db_args = {
'maintenance_db': maintenance_db,
'runas': user,

View File

@ -48,9 +48,6 @@ This is how a state configuration could look like:
# Import python libs
import re
# Import salt libs
import salt.utils
def _check_pyenv(ret, user=None):
'''
@ -99,7 +96,7 @@ def _check_and_install_python(ret, python, default=False, user=None):
return ret
def installed(name, default=False, runas=None, user=None):
def installed(name, default=False, user=None):
'''
Verify that the specified python is installed with pyenv. pyenv is
installed if necessary.
@ -110,11 +107,6 @@ def installed(name, default=False, runas=None, user=None):
default : False
Whether to make this python the default.
runas: None
The user to run pyenv as.
.. deprecated:: 0.17.0
user: None
The user to run pyenv as.
@ -124,18 +116,6 @@ def installed(name, default=False, runas=None, user=None):
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if name.startswith('python-'):
name = re.sub(r'^python-', '', name)
@ -179,7 +159,7 @@ def _check_and_uninstall_python(ret, python, user=None):
return ret
def absent(name, runas=None, user=None):
def absent(name, user=None):
'''
Verify that the specified python is not installed with pyenv. pyenv
is installed if necessary.
@ -187,11 +167,6 @@ def absent(name, runas=None, user=None):
name
The version of python to uninstall
runas: None
The user to run pyenv as.
.. deprecated:: 0.17.0
user: None
The user to run pyenv as.
@ -201,30 +176,6 @@ def absent(name, runas=None, user=None):
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Hydrogen',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if name.startswith('python-'):
name = re.sub(r'^python-', '', name)

View File

@ -45,9 +45,6 @@ This is how a state configuration could look like:
import re
import copy
# Import salt libs
import salt.utils
def _check_rbenv(ret, user=None):
'''
@ -96,7 +93,7 @@ def _check_and_install_ruby(ret, ruby, default=False, user=None):
return ret
def installed(name, default=False, runas=None, user=None):
def installed(name, default=False, user=None):
'''
Verify that the specified ruby is installed with rbenv. Rbenv is
installed if necessary.
@ -107,11 +104,6 @@ def installed(name, default=False, runas=None, user=None):
default : False
Whether to make this ruby the default.
runas: None
The user to run rbenv as.
.. deprecated:: 0.17.0
user: None
The user to run rbenv as.
@ -122,30 +114,6 @@ def installed(name, default=False, runas=None, user=None):
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
rbenv_installed_ret = copy.deepcopy(ret)
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if name.startswith('ruby-'):
name = re.sub(r'^ruby-', '', name)
@ -187,7 +155,7 @@ def _check_and_uninstall_ruby(ret, ruby, user=None):
return ret
def absent(name, runas=None, user=None):
def absent(name, user=None):
'''
Verify that the specified ruby is not installed with rbenv. Rbenv
is installed if necessary.
@ -195,11 +163,6 @@ def absent(name, runas=None, user=None):
name
The version of ruby to uninstall
runas: None
The user to run rbenv as.
.. deprecated:: 0.17.0
user: None
The user to run rbenv as.
@ -209,30 +172,6 @@ def absent(name, runas=None, user=None):
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if name.startswith('ruby-'):
name = re.sub(r'^ruby-', '', name)

View File

@ -105,9 +105,6 @@ configuration could look like:
# Import python libs
import re
# Import salt libs
import salt.utils
def _check_rvm(ret, user=None):
'''
@ -169,7 +166,7 @@ def _check_ruby(ret, ruby, user=None):
return ret
def installed(name, default=False, runas=None, user=None):
def installed(name, default=False, user=None):
'''
Verify that the specified ruby is installed with RVM. RVM is
installed when necessary.
@ -180,11 +177,6 @@ def installed(name, default=False, runas=None, user=None):
default : False
Whether to make this ruby the default.
runas: None
The user to run rvm as.
.. deprecated:: 0.17.0
user: None
The user to run rvm as.
@ -192,30 +184,6 @@ def installed(name, default=False, runas=None, user=None):
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if __opts__['test']:
ret['comment'] = 'Ruby {0} is set to be installed'.format(name)
return ret
@ -231,7 +199,7 @@ def installed(name, default=False, runas=None, user=None):
return _check_and_install_ruby(ret, name, default, user=user)
def gemset_present(name, ruby='default', runas=None, user=None):
def gemset_present(name, ruby='default', user=None):
'''
Verify that the gemset is present.
@ -241,11 +209,6 @@ def gemset_present(name, ruby='default', runas=None, user=None):
ruby: default
The ruby version this gemset belongs to.
runas: None
The user to run rvm as.
.. deprecated:: 0.17.0
user: None
The user to run rvm as.
@ -253,30 +216,6 @@ def gemset_present(name, ruby='default', runas=None, user=None):
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
ret = _check_rvm(ret, user)
if ret['result'] is False:
return ret

108
salt/states/slack.py Normal file
View File

@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
'''
Send a message to Slack
=========================
This state is useful for sending messages to Slack during state runs.
.. versionadded:: Lithium
.. code-block:: yaml
slack-message:
slack.send_message:
- channel: '#general'
- from_name: SuperAdmin
- message: 'This state was executed successfully.'
- api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15
The api key can be specified in the master or minion configuration like below:
.. code-block:: yaml
slack:
api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15
'''
def __virtual__():
'''
Only load if the slack module is available in __salt__
'''
return 'slack' if 'slack.post_message' in __salt__ else False
def post_message(name,
channel,
from_name,
message,
api_key=None):
'''
Send a message to a Slack room.
.. code-block:: yaml
slack-message:
slack.send_message:
- channel: '#general'
- from_name: SuperAdmin
- message: 'This state was executed successfully.'
- api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15
The following parameters are required:
name
The unique name for this event.
channel
The room to send the message to. Can either be the ID or the name.
from_name
The name of that is to be shown in the "from" field.
If not specified, defaults to.
message
The message that is to be sent to the Hipchat room.
The following parameters are optional:
api_key
The api key for Slack to use for authentication,
if not specified in the configuration options of master or minion.
'''
ret = {'name': name,
'changes': {},
'result': False,
'comment': ''}
if __opts__['test']:
ret['comment'] = 'The following message is to be sent to Slack: {0}'.format(message)
ret['result'] = None
return ret
if not channel:
ret['comment'] = 'Slack channel is missing: {0}'.format(channel)
return ret
if not from_name:
ret['comment'] = 'Slack from name is missing: {0}'.format(from_name)
return ret
if not message:
ret['comment'] = 'Slack message is missing: {0}'.format(message)
return ret
result = __salt__['slack.post_message'](
channel=channel,
message=message,
from_name=from_name,
api_key=api_key,
)
if result:
ret['result'] = True
ret['comment'] = 'Sent message: {0}'.format(name)
else:
ret['comment'] = 'Failed to send message: {0}'.format(name)
return ret

View File

@ -17,8 +17,6 @@ Interaction with the Supervisor daemon
# Import python libs
import logging
# Import salt libs
import salt.utils
log = logging.getLogger(__name__)
@ -48,7 +46,6 @@ def running(name,
restart=False,
update=False,
user=None,
runas=None,
conf_file=None,
bin_env=None):
'''
@ -63,11 +60,6 @@ def running(name,
update
Whether to update the supervisor configuration.
runas
Name of the user to run the supervisorctl command
.. deprecated:: 0.17.0
user
Name of the user to run the supervisorctl command
@ -83,30 +75,6 @@ def running(name,
'''
ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if 'supervisord.status' not in __salt__:
ret['result'] = False
ret['comment'] = 'Supervisord module not activated. Do you need to install supervisord?'
@ -270,7 +238,7 @@ def running(name,
log.debug(comment)
result = __salt__['supervisord.start'](
name,
user=runas,
user=user,
conf_file=conf_file,
bin_env=bin_env
)
@ -285,7 +253,6 @@ def running(name,
def dead(name,
user=None,
runas=None,
conf_file=None,
bin_env=None):
'''
@ -294,11 +261,6 @@ def dead(name,
name
Service name as defined in the supervisor configuration file
runas
Name of the user to run the supervisorctl command
.. deprecated:: 0.17.0
user
Name of the user to run the supervisorctl command
@ -314,30 +276,6 @@ def dead(name,
'''
ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 0.17.0',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if __opts__['test']:
ret['result'] = None
ret['comment'] = (
@ -347,7 +285,7 @@ def dead(name,
log.debug(comment)
all_processes = __salt__['supervisord.status'](
user=runas,
user=user,
conf_file=conf_file,
bin_env=bin_env
)
@ -397,7 +335,6 @@ def mod_watch(name,
restart=True,
update=False,
user=None,
runas=None,
conf_file=None,
bin_env=None):
# Always restart on watch
@ -406,7 +343,6 @@ def mod_watch(name,
restart=restart,
update=update,
user=user,
runas=runas,
conf_file=conf_file,
bin_env=bin_env
)

View File

@ -35,7 +35,6 @@ def managed(name,
never_download=None,
prompt=None,
user=None,
runas=None,
no_chown=False,
cwd=None,
index_url=None,
@ -83,29 +82,6 @@ def managed(name,
ret['comment'] = 'Virtualenv was not detected on this system'
return ret
if runas:
# Warn users about the deprecation
salt.utils.warn_until(
'Lithium',
'The support for \'runas\' is being deprecated in favor of '
'\'user\' and will be removed in Salt Beryllium. Please update '
'your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
salt.utils.warn_until(
'Lithium',
'Passed both the \'runas\' and \'user\' arguments. \'runas\' is '
'being ignored in favor of \'user\' as the support for \'runas\' '
'is being deprecated in favor of \'user\' and will be removed in '
'Salt Beryllium. Please update your state files.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
if salt.utils.is_windows():
venv_py = os.path.join(name, 'Scripts', 'python.exe')
else:

View File

@ -40,7 +40,6 @@ Available Functions
import sys
# Import salt libs
import salt.utils
from salt._compat import string_types
# Define the module's virtual name
@ -120,7 +119,6 @@ def installed(name,
config='buildout.cfg',
quiet=False,
parts=None,
runas=None,
user=None,
env=(),
buildout_ver=None,
@ -154,11 +152,6 @@ def installed(name,
parts
specific buildout parts to run
runas
user used to run buildout as
.. deprecated:: 2014.1.4
user
user used to run buildout as
@ -209,30 +202,6 @@ def installed(name,
'''
ret = {}
salt.utils.warn_until(
'Lithium',
'Please remove \'runas\' support at this stage. \'user\' support was '
'added in 2014.1.4.',
_dont_call_warnings=True
)
if runas:
# Warn users about the deprecation
ret.setdefault('warnings', []).append(
'The \'runas\' argument is being deprecated in favor of \'user\', '
'please update your state files.'
)
if user is not None and runas is not None:
# user wins over runas but let warn about the deprecation.
ret.setdefault('warnings', []).append(
'Passed both the \'runas\' and \'user\' arguments. Please don\'t. '
'\'runas\' is being ignored in favor of \'user\'.'
)
runas = None
elif runas is not None:
# Support old runas usage
user = runas
runas = None
try:
test_release = int(test_release)
except ValueError:

View File

@ -526,15 +526,13 @@ def dns_check(addr, safe=False, ipv6=False):
if not addr:
error = True
except TypeError:
err = ('Attempt to resolve address failed. Invalid or unresolveable address')
err = ('Attempt to resolve address \'{0}\' failed. Invalid or unresolveable address').format(addr)
raise SaltSystemExit(code=42, msg=err)
except socket.error:
error = True
if error:
err = ('This master address: \'{0}\' was previously resolvable '
'but now fails to resolve! The previously resolved ip addr '
'will continue to be used').format(addr)
err = ('DNS lookup of \'{0}\' failed.').format(addr)
if safe:
if salt.log.is_console_configured():
# If logging is not configured it also means that either
@ -842,13 +840,6 @@ def build_whitespace_split_regex(text):
return r'(?m)^{0}$'.format(regex)
def build_whitepace_splited_regex(text):
warnings.warn('The build_whitepace_splited_regex function is deprecated,'
' please use build_whitespace_split_regex instead.',
DeprecationWarning)
build_whitespace_split_regex(text)
def format_call(fun,
data,
initial_ret=None,

View File

@ -367,6 +367,9 @@ def bootstrap(vm_, opts):
'known_hosts_file': salt.config.get_cloud_config_value(
'known_hosts_file', vm_, opts, default='/dev/null'
),
'file_map': salt.config.get_cloud_config_value(
'file_map', vm_, opts, default=None
),
}
# forward any info about possible ssh gateway to deploy script
# as some providers need also a 'gateway' configuration
@ -428,8 +431,10 @@ def bootstrap(vm_, opts):
else:
deployed = deploy_script(**deploy_kwargs)
if deployed:
ret['deployed'] = deployed
if deployed is not False:
ret['deployed'] = True
if deployed is not True:
ret.update(deployed)
log.info('Salt installed on {0}'.format(vm_['name']))
return ret
@ -938,6 +943,7 @@ def deploy_script(host,
deploy_command='/tmp/.saltcloud/deploy.sh',
opts=None,
tmp_dir='/tmp/.saltcloud',
file_map=None,
**kwargs):
'''
Copy a deploy script to a remote server, execute it, and remove it
@ -1021,6 +1027,34 @@ def deploy_script(host,
'Cant set {0} ownership on {1}'.format(
username, tmp_dir))
if not isinstance(file_map, dict):
file_map = {}
# Copy an arbitrary group of files to the target system
remote_dirs = []
file_map_success = []
file_map_fail = []
for map_item in file_map:
local_file = map_item
remote_file = file_map[map_item]
if not os.path.exists(map_item):
log.error(
'The local file "{0}" does not exist, and will not be '
'copied to "{1}" on the target system'.format(
local_file, remote_file
)
)
file_map_fail.append({local_file: remote_file})
continue
remote_dir = os.path.dirname(remote_file)
if remote_dir not in remote_dirs:
root_cmd('mkdir -p {0}'.format(remote_dir), tty, sudo, **ssh_kwargs)
remote_dirs.append(remote_dir)
sftp_file(
remote_file, kwargs=ssh_kwargs, local_file=local_file
)
file_map_success.append({local_file: remote_file})
# Minion configuration
if minion_pem:
sftp_file('{0}/minion.pem'.format(tmp_dir), minion_pem, ssh_kwargs)
@ -1316,6 +1350,11 @@ def deploy_script(host,
},
transport=opts.get('transport', 'zeromq')
)
if file_map_fail or file_map_success:
return {
'File Upload Success': file_map_success,
'File Upload Failure': file_map_fail,
}
return True
return False
@ -1500,13 +1539,17 @@ def smb_file(dest_path, contents, kwargs):
win_cmd(cmd)
def sftp_file(dest_path, contents, kwargs):
def sftp_file(dest_path, contents=None, kwargs=None, local_file=None):
'''
Use sftp to upload a file to a server
'''
tmpfh, tmppath = tempfile.mkstemp()
with salt.utils.fopen(tmppath, 'w') as tmpfile:
tmpfile.write(contents)
if contents is not None:
tmpfh, tmppath = tempfile.mkstemp()
with salt.utils.fopen(tmppath, 'w') as tmpfile:
tmpfile.write(contents)
if local_file is not None:
tmppath = local_file
log.debug('Uploading {0} to {1} (sfcp)'.format(dest_path, kwargs['hostname']))

View File

@ -183,15 +183,12 @@ class CkMinions(object):
if not greedy and id_ in minions:
minions.remove(id_)
continue
try:
with salt.utils.fopen(datap, 'rb') as fp_:
search_results = self.serial.load(fp_).get(search_type)
except (IOError, OSError):
continue
search_results = self.serial.load(
salt.utils.fopen(datap, 'rb')
).get(search_type)
if not salt.utils.subdict_match(search_results,
expr,
delimiter,
regex_match=regex_match):
regex_match=regex_match) and id_ in minions:
minions.remove(id_)
return list(minions)
@ -205,36 +202,11 @@ class CkMinions(object):
'''
Return the minions found by looking via grains with PCRE
'''
cache_enabled = self.opts.get('minion_data_cache', False)
if greedy:
minions = set(
os.listdir(os.path.join(self.opts['pki_dir'], self.acc))
)
elif cache_enabled:
minions = os.listdir(os.path.join(self.opts['cachedir'], 'minions'))
else:
return list()
if cache_enabled:
cdir = os.path.join(self.opts['cachedir'], 'minions')
if not os.path.isdir(cdir):
return list(minions)
for id_ in os.listdir(cdir):
if not greedy and id_ not in minions:
continue
datap = os.path.join(cdir, id_, 'data.p')
if not os.path.isfile(datap):
if not greedy and id_ in minions:
minions.remove(id_)
continue
grains = self.serial.load(
salt.utils.fopen(datap, 'rb')
).get('grains')
if not salt.utils.subdict_match(grains, expr,
delimiter=':', regex_match=True) and id_ in minions:
minions.remove(id_)
return list(minions)
return self._check_cache_minions(expr,
delimiter,
greedy,
'grains',
regex_match=True)
def _check_pillar_minions(self, expr, delimiter, greedy):
'''

23
salt/wheel/minions.py Normal file
View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
'''
Wheel system wrapper for connected minions
'''
from salt.utils.cache import CacheCli
import salt.config
import salt.utils.minion
def connected():
'''
List all connected minions on a salt-master
'''
opts = salt.config.master_config(__opts__['conf_file'])
minions = []
if opts.get('con_cache'):
cache_cli = CacheCli(opts)
minions = cache_cli.get_cached()
else:
minions = list(salt.utils.minions.CkMinions(opts).connected_ids())
return minions

View File

@ -651,6 +651,7 @@ SETUP_KWARGS = {'name': NAME,
'salt.utils',
'salt.utils.decorators',
'salt.utils.openstack',
'salt.utils.openstack.pyrax',
'salt.utils.validate',
'salt.utils.serializers',
'salt.wheel',

View File

@ -1,4 +1,4 @@
digitalocean-test:
provider: digitalocean-config
image: Ubuntu 14.04 x64
image: 14.04 x64
size: 2GB

View File

@ -518,40 +518,6 @@ class FileTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
finally:
os.remove(name)
def test_sed(self):
'''
file.sed
'''
name = os.path.join(integration.TMP, 'sed_test')
with salt.utils.fopen(name, 'w+') as fp_:
fp_.write('change_me')
ret = self.run_state(
'file.sed', name=name, before='change', after='salt'
)
try:
with salt.utils.fopen(name, 'r') as fp_:
self.assertIn('salt', fp_.read())
self.assertSaltTrueReturn(ret)
finally:
os.remove(name)
def test_test_sed(self):
'''
file.sed test integration
'''
name = os.path.join(integration.TMP, 'sed_test_test')
with salt.utils.fopen(name, 'w+') as fp_:
fp_.write('change_me')
ret = self.run_state(
'file.sed', test=True, name=name, before='change', after='salt'
)
try:
with salt.utils.fopen(name, 'r') as fp_:
self.assertIn('change', fp_.read())
self.assertSaltNoneReturn(ret)
finally:
os.remove(name)
def test_comment(self):
'''
file.comment

View File

@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
'''
:codeauthor: :email:`Nicole Thomas (nicole@saltstack.com)`
'''
# Import Pyhton Libs
from inspect import ArgSpec
# Import Salt Libs
from salt.states import module
# Import Salt Testing Libs
from salttesting import skipIf, TestCase
from salttesting.helpers import ensure_in_syspath
from salttesting.mock import (
NO_MOCK,
NO_MOCK_REASON,
MagicMock,
patch
)
ensure_in_syspath('../../')
CMD = 'foo.bar'
MOCK = MagicMock()
module.__salt__ = {CMD: MOCK}
module.__opts__ = {'test': False}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class ModuleStateTest(TestCase):
'''
Tests module state (salt/states/module.py)
'''
aspec = ArgSpec(args=['hello', 'world'],
varargs=None,
keywords=None,
defaults=False)
def test_module_run_module_not_available(self):
'''
Tests the return of module.run state when the module function
name isn't available
'''
with patch.dict(module.__salt__, {}):
cmd = 'hello.world'
ret = module.run(cmd)
comment = 'Module function {0} is not available'.format(cmd)
self.assertEqual(ret['comment'], comment)
self.assertFalse(ret['result'])
def test_module_run_test_true(self):
'''
Tests the return of module.run state when test=True is passed in
'''
with patch.dict(module.__opts__, {'test': True}):
ret = module.run(CMD)
comment = 'Module function {0} is set to execute'.format(CMD)
self.assertEqual(ret['comment'], comment)
@patch('salt.utils.get_function_argspec', MagicMock(return_value=aspec))
def test_module_run_missing_arg(self):
'''
Tests the return of module.run state when arguments are missing
'''
ret = module.run(CMD)
comment = 'The following arguments are missing: world hello'
self.assertEqual(ret['comment'], comment)
if __name__ == '__main__':
from integration import run_tests
run_tests(ModuleStateTest, needs_daemon=False)

View File

@ -108,13 +108,6 @@ class UtilsTestCase(TestCase):
ret = utils.build_whitespace_split_regex(' '.join(LORUM_IPSUM.split()[:5]))
self.assertEqual(ret, expected_regex)
@skipIf(NO_MOCK, NO_MOCK_REASON)
@patch('warnings.warn')
def test_build_whitepace_splited_regex(self, warnings_mock):
# noinspection PyDeprecation
utils.build_whitepace_splited_regex('foo')
self.assertTrue(warnings_mock.called)
def test_get_function_argspec(self):
def dummy_func(first, second, third, fourth='fifth'):
pass