diff --git a/doc/_templates/saltstack.html b/doc/_templates/saltstack.html
index c041da70e7..41ca11189d 100644
--- a/doc/_templates/saltstack.html
+++ b/doc/_templates/saltstack.html
@@ -8,7 +8,10 @@ Call for speakers now open. Early-bird and group discounts.
SaltStack training
+
-
+Now offering remote attendee training!
+{# #}
+
{% endif %}
diff --git a/doc/_templates/version.html b/doc/_templates/version.html
index 684771e861..2abd24dc30 100644
--- a/doc/_templates/version.html
+++ b/doc/_templates/version.html
@@ -10,5 +10,5 @@
Latest Salt release: {{ release }}
Try the shiny new release candidate of Salt,
- v2014.7.0rc3! More info
- here.
+ v2014.7.0rc6! More info
+ here.
diff --git a/doc/ref/states/aggregate.rst b/doc/ref/states/aggregate.rst
index 95b602afc5..37d1acac4c 100644
--- a/doc/ref/states/aggregate.rst
+++ b/doc/ref/states/aggregate.rst
@@ -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.
diff --git a/doc/ref/states/requisites.rst b/doc/ref/states/requisites.rst
index abaa229d1f..54765281d0 100644
--- a/doc/ref/states/requisites.rst
+++ b/doc/ref/states/requisites.rst
@@ -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
diff --git a/doc/ref/wheel/all/index.rst b/doc/ref/wheel/all/index.rst
index fd0a480fe5..c1067b1eca 100644
--- a/doc/ref/wheel/all/index.rst
+++ b/doc/ref/wheel/all/index.rst
@@ -15,3 +15,4 @@ Full list of builtin wheel modules
file_roots
key
pillar_roots
+ minions
diff --git a/doc/ref/wheel/all/salt.wheel.minions.rst b/doc/ref/wheel/all/salt.wheel.minions.rst
new file mode 100644
index 0000000000..47bd313ddf
--- /dev/null
+++ b/doc/ref/wheel/all/salt.wheel.minions.rst
@@ -0,0 +1,7 @@
+==================
+salt.wheel.minions
+==================
+
+.. automodule:: salt.wheel.minions
+ :members:
+
diff --git a/doc/topics/installation/osx.rst b/doc/topics/installation/osx.rst
index 9d83a14257..964cf3815f 100644
--- a/doc/topics/installation/osx.rst
+++ b/doc/topics/installation/osx.rst
@@ -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
=======================
diff --git a/doc/topics/installation/rhel.rst b/doc/topics/installation/rhel.rst
index 534c9d9e6f..2fea7bf4ed 100644
--- a/doc/topics/installation/rhel.rst
+++ b/doc/topics/installation/rhel.rst
@@ -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 ` 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
=======================
diff --git a/doc/topics/reactor/index.rst b/doc/topics/reactor/index.rst
index d215b088e9..6273cbed89 100644
--- a/doc/topics/reactor/index.rst
+++ b/doc/topics/reactor/index.rst
@@ -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 `.
+
+* :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:
diff --git a/doc/topics/releases/2014.7.0.rst b/doc/topics/releases/2014.7.0.rst
index f8cefd4e96..5736393904 100644
--- a/doc/topics/releases/2014.7.0.rst
+++ b/doc/topics/releases/2014.7.0.rst
@@ -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 `.
+:doc:`tutorial `.
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 ` 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 `.
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
diff --git a/doc/topics/ssh/index.rst b/doc/topics/ssh/index.rst
index a48c223f90..0b20fdfbb8 100644
--- a/doc/topics/ssh/index.rst
+++ b/doc/topics/ssh/index.rst
@@ -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
diff --git a/doc/topics/transports/raet/index.rst b/doc/topics/transports/raet/index.rst
index c49b752d3a..c5b97a10df 100644
--- a/doc/topics/transports/raet/index.rst
+++ b/doc/topics/transports/raet/index.rst
@@ -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/
diff --git a/doc/topics/tutorials/pillar.rst b/doc/topics/tutorials/pillar.rst
index f274fbd3eb..a10dd7487f 100644
--- a/doc/topics/tutorials/pillar.rst
+++ b/doc/topics/tutorials/pillar.rst
@@ -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
diff --git a/pkg/suse/salt.changes b/pkg/suse/salt.changes
index b06cb39c77..890bd5381d 100644
--- a/pkg/suse/salt.changes
+++ b/pkg/suse/salt.changes
@@ -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
diff --git a/pkg/suse/salt.spec b/pkg/suse/salt.spec
index 0ce10f472c..4b3ec6785e 100644
--- a/pkg/suse/salt.spec
+++ b/pkg/suse/salt.spec
@@ -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
diff --git a/pkg/suse/use-forking-daemon.patch b/pkg/suse/use-forking-daemon.patch
index 9fe63185dd..156e24975b 100644
--- a/pkg/suse/use-forking-daemon.patch
+++ b/pkg/suse/use-forking-daemon.patch
@@ -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
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
index 9d0682f4df..5dd8ac7f12 100644
--- a/salt/client/ssh/__init__.py
+++ b/salt/client/ssh/__init__.py
@@ -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)
diff --git a/salt/client/ssh/ssh_py_shim.py b/salt/client/ssh/ssh_py_shim.py
index d2819cdebf..2a0b92a124 100644
--- a/salt/client/ssh/ssh_py_shim.py
+++ b/salt/client/ssh/ssh_py_shim.py
@@ -93,6 +93,7 @@ def unpack_ext(ext_path):
'var',
'cache',
'salt',
+ 'minion',
'extmods')
tfile = tarfile.TarFile.gzopen(ext_path)
tfile.extractall(path=modcache)
diff --git a/salt/cloud/clouds/digital_ocean.py b/salt/cloud/clouds/digital_ocean.py
index 4f772faed5..4d19a9af16 100644
--- a/salt/cloud/clouds/digital_ocean.py
+++ b/salt/cloud/clouds/digital_ocean.py
@@ -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
diff --git a/salt/cloud/clouds/digital_ocean_v2.py b/salt/cloud/clouds/digital_ocean_v2.py
index 3e60ad848f..38fd695a48 100644
--- a/salt/cloud/clouds/digital_ocean_v2.py
+++ b/salt/cloud/clouds/digital_ocean_v2.py
@@ -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
diff --git a/salt/cloud/clouds/gce.py b/salt/cloud/clouds/gce.py
index 10fe24e8f7..2b97ca8468 100644
--- a/salt/cloud/clouds/gce.py
+++ b/salt/cloud/clouds/gce.py
@@ -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
diff --git a/salt/cloud/deploy/bootstrap-salt.sh b/salt/cloud/deploy/bootstrap-salt.sh
index 9c8ec0c868..0a4b730f47 100755
--- a/salt/cloud/deploy/bootstrap-salt.sh
+++ b/salt/cloud/deploy/bootstrap-salt.sh
@@ -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 \
diff --git a/salt/config.py b/salt/config.py
index b15d8a4f3b..594b8d12ad 100644
--- a/salt/config.py
+++ b/salt/config.py
@@ -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': [],
diff --git a/salt/fileclient.py b/salt/fileclient.py
index 2dd47c7853..211d1c4bc0 100644
--- a/salt/fileclient.py
+++ b/salt/fileclient.py
@@ -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
diff --git a/salt/master.py b/salt/master.py
index 6abf24c10f..e8439e1379 100644
--- a/salt/master.py
+++ b/salt/master.py
@@ -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 = {
diff --git a/salt/minion.py b/salt/minion.py
index 1e35def569..c9c0ba6ff4 100644
--- a/salt/minion.py
+++ b/salt/minion.py
@@ -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)
diff --git a/salt/modules/drac.py b/salt/modules/drac.py
new file mode 100644
index 0000000000..7d02db42b2
--- /dev/null
+++ b/salt/modules/drac.py
@@ -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
diff --git a/salt/modules/macports.py b/salt/modules/macports.py
index 2372df85df..ac41a97fee 100644
--- a/salt/modules/macports.py
+++ b/salt/modules/macports.py
@@ -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__:
diff --git a/salt/modules/pip.py b/salt/modules/pip.py
index 1d6799a774..612e6e07c4 100644
--- a/salt/modules/pip.py
+++ b/salt/modules/pip.py
@@ -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):
diff --git a/salt/modules/rpm.py b/salt/modules/rpm.py
index a6829c07a9..dba12a503f 100644
--- a/salt/modules/rpm.py
+++ b/salt/modules/rpm.py
@@ -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
diff --git a/salt/modules/slack_notify.py b/salt/modules/slack_notify.py
index b8ecf7bda5..b1f21a9cbe 100644
--- a/salt/modules/slack_notify.py
+++ b/salt/modules/slack_notify.py
@@ -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:
- 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
diff --git a/salt/modules/tomcat.py b/salt/modules/tomcat.py
index 1480691fda..37a914f413 100644
--- a/salt/modules/tomcat.py
+++ b/salt/modules/tomcat.py
@@ -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
diff --git a/salt/modules/virt.py b/salt/modules/virt.py
index 035ba09c49..fe78253552 100644
--- a/salt/modules/virt.py
+++ b/salt/modules/virt.py
@@ -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():
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
index 02e6a06b2d..918a53cdf3 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -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
)
diff --git a/salt/modules/zpool.py b/salt/modules/zpool.py
index 12376bb035..73a3a6834f 100644
--- a/salt/modules/zpool.py
+++ b/salt/modules/zpool.py
@@ -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
diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 883aec73f3..58300c1f1b 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -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::
+
+ {'': {'case_sensitive': '',
+ 'match_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
+ salt '*' pkg.remove_lock ,,
+ 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
+ salt '*' pkg.add_lock ,,
+ 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)
diff --git a/salt/returners/carbon_return.py b/salt/returners/carbon_return.py
index ddd99dc993..e8fd995d12 100644
--- a/salt/returners/carbon_return.py
+++ b/salt/returners/carbon_return.py
@@ -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()
diff --git a/salt/returners/cassandra_return.py b/salt/returners/cassandra_return.py
index 2928671336..13da2efd6b 100644
--- a/salt/returners/cassandra_return.py
+++ b/salt/returners/cassandra_return.py
@@ -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()
diff --git a/salt/returners/couchbase_return.py b/salt/returners/couchbase_return.py
index 19212f7c34..c4045d7900 100644
--- a/salt/returners/couchbase_return.py
+++ b/salt/returners/couchbase_return.py
@@ -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
diff --git a/salt/returners/couchdb_return.py b/salt/returners/couchdb_return.py
index a76ffaa23c..553284e9e8 100644
--- a/salt/returners/couchdb_return.py
+++ b/salt/returners/couchdb_return.py
@@ -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()
diff --git a/salt/returners/elasticsearch_return.py b/salt/returners/elasticsearch_return.py
index e2eb101b99..022c6b8c7f 100644
--- a/salt/returners/elasticsearch_return.py
+++ b/salt/returners/elasticsearch_return.py
@@ -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()
diff --git a/salt/returners/etcd_return.py b/salt/returners/etcd_return.py
index 25c5d5c61b..3f06445d48 100644
--- a/salt/returners/etcd_return.py
+++ b/salt/returners/etcd_return.py
@@ -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()
diff --git a/salt/returners/local_cache.py b/salt/returners/local_cache.py
index 8b3ec22421..d65a0c207b 100644
--- a/salt/returners/local_cache.py
+++ b/salt/returners/local_cache.py
@@ -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)
diff --git a/salt/returners/memcache_return.py b/salt/returners/memcache_return.py
index 6315577ab3..e42bc807f8 100644
--- a/salt/returners/memcache_return.py
+++ b/salt/returners/memcache_return.py
@@ -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):
diff --git a/salt/returners/mongo_future_return.py b/salt/returners/mongo_future_return.py
index d46f540559..f030bfbc53 100644
--- a/salt/returners/mongo_future_return.py
+++ b/salt/returners/mongo_future_return.py
@@ -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()
diff --git a/salt/returners/mongo_return.py b/salt/returners/mongo_return.py
index 30d04dd744..67dffa7f75 100644
--- a/salt/returners/mongo_return.py
+++ b/salt/returners/mongo_return.py
@@ -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()
diff --git a/salt/returners/multi_returner.py b/salt/returners/multi_returner.py
index 87434827e3..bcf0bba936 100644
--- a/salt/returners/multi_returner.py
+++ b/salt/returners/multi_returner.py
@@ -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)
diff --git a/salt/returners/mysql.py b/salt/returners/mysql.py
index 12439147b6..c94f2248a7 100644
--- a/salt/returners/mysql.py
+++ b/salt/returners/mysql.py
@@ -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()
diff --git a/salt/returners/odbc.py b/salt/returners/odbc.py
index 80296b8b26..8fbe897999 100644
--- a/salt/returners/odbc.py
+++ b/salt/returners/odbc.py
@@ -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()
diff --git a/salt/returners/postgres.py b/salt/returners/postgres.py
index c14feae1e9..82c31c4925 100644
--- a/salt/returners/postgres.py
+++ b/salt/returners/postgres.py
@@ -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()
diff --git a/salt/returners/redis_return.py b/salt/returners/redis_return.py
index 4824537760..3661e9d0f2 100644
--- a/salt/returners/redis_return.py
+++ b/salt/returners/redis_return.py
@@ -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()
diff --git a/salt/returners/sentry_return.py b/salt/returners/sentry_return.py
index 7018f916f8..e406ba799b 100644
--- a/salt/returners/sentry_return.py
+++ b/salt/returners/sentry_return.py
@@ -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()
diff --git a/salt/returners/slack_returner.py b/salt/returners/slack_returner.py
new file mode 100644
index 0000000000..794c55fc5f
--- /dev/null
+++ b/salt/returners/slack_returner.py
@@ -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
diff --git a/salt/returners/smtp_return.py b/salt/returners/smtp_return.py
index bf299bac07..26da0c26e4 100644
--- a/salt/returners/smtp_return.py
+++ b/salt/returners/smtp_return.py
@@ -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()
diff --git a/salt/returners/sqlite3_return.py b/salt/returners/sqlite3_return.py
index c1ea8f37bf..227222d1d0 100644
--- a/salt/returners/sqlite3_return.py
+++ b/salt/returners/sqlite3_return.py
@@ -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()
diff --git a/salt/returners/syslog_return.py b/salt/returners/syslog_return.py
index a46f5b598d..43918c95c4 100644
--- a/salt/returners/syslog_return.py
+++ b/salt/returners/syslog_return.py
@@ -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()
diff --git a/salt/runners/jobs.py b/salt/runners/jobs.py
index 6c8a3986ed..b91b65c044 100644
--- a/salt/runners/jobs.py
+++ b/salt/runners/jobs.py
@@ -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__)
diff --git a/salt/states/at.py b/salt/states/at.py
index 60f7a3960e..365e8a63f4 100644
--- a/salt/states/at.py
+++ b/salt/states/at.py
@@ -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']:
diff --git a/salt/states/augeas.py b/salt/states/augeas.py
index 94ce2e5454..d754a64e53 100644
--- a/salt/states/augeas.py
+++ b/salt/states/augeas.py
@@ -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
diff --git a/salt/states/composer.py b/salt/states/composer.py
index c21f98e32d..25489a64b4 100644
--- a/salt/states/composer.py
+++ b/salt/states/composer.py
@@ -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,
diff --git a/salt/states/file.py b/salt/states/file.py
index 9f9bee8f16..7c1086f3d7 100644
--- a/salt/states/file.py
+++ b/salt/states/file.py
@@ -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
+ `.
'''
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.
diff --git a/salt/states/gem.py b/salt/states/gem.py
index 7d3f61d3ca..2be56ac907 100644
--- a/salt/states/gem.py
+++ b/salt/states/gem.py
@@ -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.'
diff --git a/salt/states/git.py b/salt/states/git.py
index 703d24e062..e0479761fb 100644
--- a/salt/states/git.py
+++ b/salt/states/git.py
@@ -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')):
diff --git a/salt/states/hg.py b/salt/states/hg.py
index 95403f1fb9..73739acbc3 100644
--- a/salt/states/hg.py
+++ b/salt/states/hg.py
@@ -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')
diff --git a/salt/states/iptables.py b/salt/states/iptables.py
index 8677bdd6d3..678dd17349 100644
--- a/salt/states/iptables.py
+++ b/salt/states/iptables.py
@@ -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(
diff --git a/salt/states/module.py b/salt/states/module.py
index 47d3a72f9c..68473f2d99 100644
--- a/salt/states/module.py
+++ b/salt/states/module.py
@@ -129,7 +129,6 @@ def run(name, **kwargs):
return ret
aspec = salt.utils.get_function_argspec(__salt__[name])
-
args = []
defaults = {}
diff --git a/salt/states/npm.py b/salt/states/npm.py
index de7c1d67b7..656ea70c05 100644
--- a/salt/states/npm.py
+++ b/salt/states/npm.py
@@ -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)
diff --git a/salt/states/pip_state.py b/salt/states/pip_state.py
index d1eff0c982..33a10bd812 100644
--- a/salt/states/pip_state.py
+++ b/salt/states/pip_state.py
@@ -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
)
diff --git a/salt/states/postgres_database.py b/salt/states/postgres_database.py
index d260dab0ab..39f5503a20 100644
--- a/salt/states/postgres_database.py
+++ b/salt/states/postgres_database.py
@@ -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,
diff --git a/salt/states/postgres_group.py b/salt/states/postgres_group.py
index 7b5763199c..a2f15ccff0 100644
--- a/salt/states/postgres_group.py
+++ b/salt/states/postgres_group.py
@@ -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,
diff --git a/salt/states/postgres_user.py b/salt/states/postgres_user.py
index 86cd5d2351..b86de9c20b 100644
--- a/salt/states/postgres_user.py
+++ b/salt/states/postgres_user.py
@@ -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,
diff --git a/salt/states/pyenv.py b/salt/states/pyenv.py
index ce99ffa40a..19006587bc 100644
--- a/salt/states/pyenv.py
+++ b/salt/states/pyenv.py
@@ -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)
diff --git a/salt/states/rbenv.py b/salt/states/rbenv.py
index 70cbca2695..572a2df199 100644
--- a/salt/states/rbenv.py
+++ b/salt/states/rbenv.py
@@ -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)
diff --git a/salt/states/rvm.py b/salt/states/rvm.py
index e3c226e924..9d0541f01a 100644
--- a/salt/states/rvm.py
+++ b/salt/states/rvm.py
@@ -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
diff --git a/salt/states/slack.py b/salt/states/slack.py
new file mode 100644
index 0000000000..d95a9ab069
--- /dev/null
+++ b/salt/states/slack.py
@@ -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
diff --git a/salt/states/supervisord.py b/salt/states/supervisord.py
index b204a38628..0f0d1d1682 100644
--- a/salt/states/supervisord.py
+++ b/salt/states/supervisord.py
@@ -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
)
diff --git a/salt/states/virtualenv_mod.py b/salt/states/virtualenv_mod.py
index 8dbbf10d59..cc1129a233 100644
--- a/salt/states/virtualenv_mod.py
+++ b/salt/states/virtualenv_mod.py
@@ -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:
diff --git a/salt/states/zcbuildout.py b/salt/states/zcbuildout.py
index 0d38fdc259..cc1715b09a 100644
--- a/salt/states/zcbuildout.py
+++ b/salt/states/zcbuildout.py
@@ -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:
diff --git a/salt/utils/__init__.py b/salt/utils/__init__.py
index de477d6a15..68499789d2 100644
--- a/salt/utils/__init__.py
+++ b/salt/utils/__init__.py
@@ -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,
diff --git a/salt/utils/cloud.py b/salt/utils/cloud.py
index 93385a1550..cfa1eed395 100644
--- a/salt/utils/cloud.py
+++ b/salt/utils/cloud.py
@@ -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']))
diff --git a/salt/utils/minions.py b/salt/utils/minions.py
index 1b2206bae4..44cf11d6fd 100644
--- a/salt/utils/minions.py
+++ b/salt/utils/minions.py
@@ -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):
'''
diff --git a/salt/wheel/minions.py b/salt/wheel/minions.py
new file mode 100644
index 0000000000..dc30ffa6bc
--- /dev/null
+++ b/salt/wheel/minions.py
@@ -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
diff --git a/setup.py b/setup.py
index 88768d636b..51649e4765 100755
--- a/setup.py
+++ b/setup.py
@@ -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',
diff --git a/tests/integration/files/conf/cloud.profiles.d/digital_ocean.conf b/tests/integration/files/conf/cloud.profiles.d/digital_ocean.conf
index dc9d084d42..8270f2120a 100644
--- a/tests/integration/files/conf/cloud.profiles.d/digital_ocean.conf
+++ b/tests/integration/files/conf/cloud.profiles.d/digital_ocean.conf
@@ -1,4 +1,4 @@
digitalocean-test:
provider: digitalocean-config
- image: Ubuntu 14.04 x64
+ image: 14.04 x64
size: 2GB
diff --git a/tests/integration/states/file.py b/tests/integration/states/file.py
index ce77c15783..c4081237c2 100644
--- a/tests/integration/states/file.py
+++ b/tests/integration/states/file.py
@@ -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
diff --git a/tests/unit/states/module_test.py b/tests/unit/states/module_test.py
new file mode 100644
index 0000000000..0a9edf07e0
--- /dev/null
+++ b/tests/unit/states/module_test.py
@@ -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)
diff --git a/tests/unit/utils/utils_test.py b/tests/unit/utils/utils_test.py
index 8db9db15e5..305dcbce8a 100644
--- a/tests/unit/utils/utils_test.py
+++ b/tests/unit/utils/utils_test.py
@@ -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