Merge branch 'develop' into accept-minions-from-grains

This commit is contained in:
Mike Place 2017-11-13 11:13:50 -07:00 committed by GitHub
commit f2aa3539ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
169 changed files with 4360 additions and 857 deletions

4
.github/stale.yml vendored
View File

@ -1,8 +1,8 @@
# Probot Stale configuration file
# Number of days of inactivity before an issue becomes stale
# 910 is approximately 2 years and 6 months
daysUntilStale: 910
# 890 is approximately 2 years and 5 months
daysUntilStale: 890
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7

5
.gitignore vendored
View File

@ -91,3 +91,8 @@ tests/integration/cloud/providers/pki/minions
# Ignore tox virtualenvs
/.tox/
# Kitchen tests files
.kitchen/
.bundle/
Gemfile.lock

187
.kitchen.yml Normal file
View File

@ -0,0 +1,187 @@
---
<% vagrant = system('which vagrant 2>/dev/null >/dev/null') %>
<% version = '2017.7.2' %>
<% platformsfile = ENV['SALT_KITCHEN_PLATFORMS'] || '.kitchen/platforms.yml' %>
<% driverfile = ENV['SALT_KITCHEN_DRIVER'] || '.kitchen/driver.yml' %>
<% if File.exists?(driverfile) %>
<%= ERB.new(File.read(driverfile)).result %>
<% else %>
driver:
name: docker
use_sudo: false
privileged: true
username: root
volume:
- /var/run/docker.sock:/docker.sock
cap_add:
- sys_admin
disable_upstart: false
provision_command:
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
<% end %>
sudo: false
provisioner:
name: salt_solo
salt_install: bootstrap
salt_version: latest
salt_bootstrap_url: https://bootstrap.saltstack.com
salt_bootstrap_options: -X stable <%= version %>
log_level: info
require_chef: false
remote_states:
name: git://github.com/gtmanfred/salt-jenkins.git
branch: master
repo: git
testingdir: /testing
salt_copy_filter:
- .bundle
- .git
- .gitignore
- .kitchen
- .kitchen.yml
- Gemfile
- Gemfile.lock
- README.rst
- .travis.yml
state_top:
base:
"*":
- git.salt
- kitchen
<% if File.exists?(platformsfile) %>
<%= ERB.new(File.read(platformsfile)).result %>
<% else %>
platforms:
- name: fedora
driver_config:
image: fedora:latest
run_command: /usr/lib/systemd/systemd
provisioner:
salt_bootstrap_options: -X git v<%= version %> >/dev/null
- name: centos-7
driver_config:
run_command: /usr/lib/systemd/systemd
- name: centos-6
driver_config:
run_command: /sbin/init
provision_command:
- yum install -y upstart
provisioner:
salt_bootstrap_options: -P -y -x python2.7 -X git v<%= version %> >/dev/null
- name: ubuntu-rolling
driver_config:
image: ubuntu:rolling
run_command: /lib/systemd/systemd
provisioner:
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.sh
- name: ubuntu-16.04
driver_config:
run_command: /lib/systemd/systemd
- name: ubuntu-14.04
driver_config:
run_command: /sbin/init
provision_command:
- rm -f /sbin/initctl
- dpkg-divert --local --rename --remove /sbin/initctl
- name: debian-8
driver_config:
run_command: /lib/systemd/systemd
provision_command:
- apt-get install -y dbus
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
- name: debian-9
driver_config:
run_command: /lib/systemd/systemd
- name: arch
driver_config:
image: base/archlinux
run_command: /usr/lib/systemd/systemd
provision_command:
- pacman -Syu --noconfirm systemd
- systemctl enable sshd
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
provisioner:
salt_bootstrap_options: -X git v<%= version %> >/dev/null
- name: opensuse
driver_config:
run_command: /usr/lib/systemd/systemd
provision_command:
- systemctl enable sshd.service
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
provisioner:
salt_bootstrap_options: -X git v<%= version %> >/dev/null
<% if vagrant != false %>
- name: windows-2012r2
driver:
box: mwrock/Windows2012R2
communicator: winrm
name: vagrant
gui: true
username: administrator
password: Pass@word1
provisioner:
init_environment: |
Clear-Host
$AddedLocation ="c:\salt"
$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path
$NewPath= $OldPath + ; + $AddedLocation
Set-ItemProperty -Path "$Reg" -Name PATH Value $NewPath
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.ps1
salt_bootstrap_options: ''
- name: windows-2016
driver:
box: mwrock/Windows2016
communicator: winrm
name: vagrant
username: Vagrant
password: vagrant
gui: true
provisioner:
init_environment: |
Clear-Host
$AddedLocation ="c:\salt;c:\salt\bin\Scripts"
$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path
$NewPath= $OldPath + ; + $AddedLocation
Set-ItemProperty -Path "$Reg" -Name PATH Value $NewPath
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.ps1
salt_bootstrap_options: ''
<% end %>
<% end %>
suites:
- name: py2
provisioner:
pillars:
top.sls:
base:
"*":
- jenkins
jenkins.sls:
testing_dir: /tmp/kitchen/testing
clone_repo: false
salttesting_namespec: salttesting==2017.6.1
- name: py3
provisioner:
pillars:
top.sls:
base:
"*":
- jenkins
jenkins.sls:
testing_dir: /tmp/kitchen/testing
clone_repo: false
py3: true
salttesting_namespec: salttesting==2017.6.1
verifier:
name: shell
remote_exec: true
sudo: false
live_stream: {}
<% if ENV['TESTOPTS'].nil? %>
command: '$(kitchen) /tmp/kitchen/testing/tests/runtests.py --run-destructive --sysinfo --transport=zeromq --output-columns=80 --ssh --coverage-xml=/tmp/coverage.xml --xml=/tmp/xml-unittests-output'
<% else %>
command: '$(kitchen) /tmp/kitchen/testing/tests/runtests.py --run-destructive --output-columns 80 <%= ENV["TESTOPTS"] %>'
<% end %>

23
Gemfile Normal file
View File

@ -0,0 +1,23 @@
# This file is only used for running the test suite with kitchen-salt.
source "https://rubygems.org"
gem "test-kitchen"
gem "kitchen-salt", :git => 'https://github.com/saltstack/kitchen-salt.git'
gem 'git'
group :docker do
gem 'kitchen-docker', :git => 'https://github.com/test-kitchen/kitchen-docker.git'
end
group :opennebula do
gem 'kitchen-opennebula', :git => 'https://github.com/gtmanfred/kitchen-opennebula.git'
gem 'xmlrpc'
end
group :windows do
gem 'vagrant-wrapper'
gem 'kitchen-vagrant'
gem 'winrm', '~>2.0'
gem 'winrm-fs', '~>1.0'
end

View File

@ -44,6 +44,11 @@ may take a few moments for someone to reply.
`<http://webchat.freenode.net/?channels=salt&uio=Mj10cnVlJjk9dHJ1ZSYxMD10cnVl83>`_
**SaltStack Slack** - Alongside IRC is our SaltStack Community Slack for the
SaltStack Working groups. Use the following link to request an invitation.
`<https://saltstackcommunity.herokuapp.com/>`_
**Mailing List** - The SaltStack community users mailing list is hosted by
Google groups. Anyone can post to ask questions about SaltStack products and
anyone can help answer. Join the conversation!

View File

@ -719,7 +719,7 @@ Note that ping_on_rotate may cause high load on the master immediately after
the key rotation event as minions reconnect. Consider this carefully if this
salt master is managing a large number of minions.
.. code-black:: yaml
.. code-block:: yaml
ping_on_rotate: False
@ -905,7 +905,7 @@ is set to ``tcp`` by default on Windows.
ipc_mode: ipc
.. conf_master::
.. conf_master:: tcp_master_pub_port
``tcp_master_pub_port``
-----------------------
@ -4264,6 +4264,7 @@ Default: ``10``
The number of workers for the runner/wheel in the reactor.
.. code-block:: yaml
reactor_worker_threads: 10
.. conf_master:: reactor_worker_hwm

View File

@ -2408,6 +2408,7 @@ Default: ``10``
The number of workers for the runner/wheel in the reactor.
.. code-block:: yaml
reactor_worker_threads: 10
.. conf_minion:: reactor_worker_hwm

View File

@ -46,5 +46,6 @@ returner modules
splunk
sqlite3_return
syslog_return
telegram_return
xmpp_return
zabbix_return

View File

@ -51,7 +51,7 @@ actually speed things up.
To run the above state much faster make sure that the ``sleep 5`` is evaluated
before the ``nginx`` state
.. code_block:: yaml
.. code-block:: yaml
sleep 10:
cmd.run:

View File

@ -99,7 +99,8 @@ Profile configuration example:
# vagrant_up_timeout: 300 # (seconds) timeout for cmd.run of the "vagrant up" command
# vagrant_provider: '' # option for "vagrant up" like: "--provider vmware_fusion"
# ssh_host: None # "None" means try to find the routable IP address from "ifconfig"
# target_network: None # Expected CIDR address of your bridged network
# ssh_username: '' # also required when ssh_host is used.
# target_network: None # Expected CIDR address range of your bridged network
# force_minion_config: false # Set "true" to re-purpose an existing VM
The machine can now be created and configured with the following command:

View File

@ -68,8 +68,8 @@ Each salt minion establishes a connection to the master Publisher.
EventPublisher
--------------
The EventPublisher publishes events onto the event bus. It is bound to the
following:
The EventPublisher publishes master events out to any event listeners. It is
bound to the following:
* IPC: master_event_pull.ipc
* IPC: master_event_pub.ipc
@ -110,48 +110,37 @@ The typical lifecycle of a salt job from the perspective of the master
might be as follows:
1) A command is issued on the CLI. For example, 'salt my_minion test.ping'.
2) The 'salt' command uses LocalClient to generate a request to the salt master
by connecting to the ReqServer on TCP:4506 and issuing the job.
3) The salt-master ReqServer sees the request and passes it to an available
MWorker over workers.ipc.
4) A worker picks up the request and handles it. First, it checks to ensure
that the requested user has permissions to issue the command. Then, it sends
the publish command to all connected minions. For the curious, this happens
in ClearFuncs.publish().
5) The worker announces on the master event bus that it is about to publish
a job to connected minions. This happens by placing the event on the master
event bus (master_event_pull.ipc) where the EventPublisher picks it up and
distributes it to all connected event listeners on master_event_pub.ipc.
6) The message to the minions is encrypted and sent to the Publisher via IPC
on publish_pull.ipc.
7) Connected minions have a TCP session established with the Publisher on TCP
port 4505 where they await commands. When the Publisher receives the job over
publish_pull, it sends the jobs across the wire to the minions for processing.
8) After the minions receive the request, they decrypt it and perform any
requested work, if they determine that they are targeted to do so.
9) When the minion is ready to respond, it publishes the result of its job back
to the master by sending the encrypted result back to the master on TCP 4506
where it is again picked up by the ReqServer and forwarded to an available
MWorker for processing. (Again, this happens by passing this message across
workers.ipc to an available worker.)
10) When the MWorker receives the job it decrypts it and fires an event onto
the master event bus (master_event_pull.ipc). (Again for the curious, this
happens in AESFuncs._return().
11) The EventPublisher sees this event and re-publishes it on the bus to all
connected listeners of the master event bus (on master_event_pub.ipc). This
is where the LocalClient has been waiting, listening to the event bus for
minion replies. It gathers the job and stores the result.
12) When all targeted minions have replied or the timeout has been exceeded,
the salt client displays the results of the job to the user on the CLI.
@ -167,8 +156,8 @@ Salt. It can either operate as a stand-alone daemon which accepts commands
locally via 'salt-call' or it can connect back to a master and receive commands
remotely.
When starting up, salt minions connect _back_ to a master defined in the minion
config file. The connect to two ports on the master:
When starting up, salt minions connect *back* to a master defined in the minion
config file. They connect to two ports on the master:
* TCP: 4505
This is the connection to the master Publisher. It is on this port that
@ -196,8 +185,8 @@ permissions can read or write to the bus as a common interface with the salt
minion.
Job Flow
--------
Minion Job Flow
---------------
When a salt minion starts up, it attempts to connect to the Publisher and the
ReqServer on the salt master. It then attempts to authenticate and once the
@ -206,28 +195,22 @@ minion has successfully authenticated, it simply listens for jobs.
Jobs normally come either come from the 'salt-call' script run by a local user
on the salt minion or they can come directly from a master.
Master Job Flow
---------------
The job flow on a minion, coming from the master via a 'salt' command is as
follows:
1) A master publishes a job that is received by a minion as outlined by the
master's job flow above.
2) The minion is polling its receive socket that's connected to the master
Publisher (TCP 4505 on master). When it detects an incoming message, it picks it
up from the socket and decrypts it.
3) A new minion process or thread is created and provided with the contents of the
decrypted message. The _thread_return() method is provided with the contents of
the received message.
4) The new minion thread is created. The _thread_return() function starts up
and actually calls out to the requested function contained in the job.
5) The requested function runs and returns a result. [Still in thread.]
6) The result of the function that's run is encrypted and returned to the
master's ReqServer (TCP 4506 on master). [Still in thread.]
7) Thread exits. Because the main thread was only blocked for the time that it
took to initialize the worker thread, many other requests could have been
received and processed during this time.
@ -241,6 +224,5 @@ clear and when they are passed using encryption. There are two rules governing
this behaviour:
1) ClearFuncs is used for intra-master communication and during the initial
authentication handshake between a minion and master during the key exhange.
authentication handshake between a minion and master during the key exchange.
2) AESFuncs is used everywhere else.

View File

@ -95,19 +95,19 @@ globally available or passed in through function arguments, file data, etc.
Mocking Loader Modules
----------------------
Salt loader modules use a series of globally available dunder variables,
``__salt__``, ``__opts__``, ``__pillar__``, etc. To facilitate testing these
modules a mixin class was created, ``LoaderModuleMockMixin`` which can be found
in ``tests/support/mixins.py``. The reason for the exitance of this class is
because, historycally, and because it was easier, one would add these dunder
variables directly on the imported module. This however, introduces unexpected
behavior when running the full test suite since those attributes would not be
removed once we were done testing the module and would therefor leak to other
modules being tested with unpredictable results. This is the kind of work that
should be defered to mock, and that's exactly what this mixin class does.
Salt loader modules use a series of globally available dunder variables,
``__salt__``, ``__opts__``, ``__pillar__``, etc. To facilitate testing these
modules a mixin class was created, ``LoaderModuleMockMixin`` which can be found
in ``tests/support/mixins.py``. The reason for the existance of this class is
because historiclly and because it was easier, one would add these dunder
variables directly on the imported module. This however, introduces unexpected
behavior when running the full test suite since those attributes would not be
removed once we were done testing the module and would therefore leak to other
modules being tested with unpredictable results. This is the kind of work that
should be deferred to mock, and that's exactly what this mixin class does.
As an example, if one needs to specify some options which should be available
to the module being tests one should do:
As an example, if one needs to specify some options which should be available
to the module being tested one should do:
.. code-block:: python
@ -122,7 +122,7 @@ to the module being tests one should do:
}
}
Consider this more extensive example from
Consider this more extensive example from
``tests/unit/modules/test_libcloud_dns.py``:
.. code-block:: python
@ -173,10 +173,10 @@ Consider this more extensive example from
return {libcloud_dns: module_globals}
What happens on the above example is that, we mock a call to
`__salt__['config.option']` to return the configuration needed for the
execution of the tests. Additionally, if the ``libcloud`` library is not
available, since that's not actually part of whats being tested, we mocked that
What happens in the above example is we mock a call to
`__salt__['config.option']` to return the configuration needed for the
execution of the tests. Additionally, if the ``libcloud`` library is not
available, since that's not actually part of what's being tested, we mocked that
import by patching ``sys.modules`` when tests are running.
@ -245,7 +245,7 @@ To understand how one might integrate Mock into writing a unit test for Salt,
let's imagine a scenario in which we're testing an execution module that's
designed to operate on a database. Furthermore, let's imagine two separate
methods, here presented in pseduo-code in an imaginary execution module called
'db.py.
'db.py'.
.. code-block:: python

View File

@ -4,12 +4,25 @@ Event System
The Salt Event System is used to fire off events enabling third party
applications or external processes to react to behavior within Salt.
The event system uses a publish-subscribe pattern, otherwise know as pub/sub.
The event system is comprised of a two primary components:
Event Bus
=========
The event system is comprised of a two primary components, which make up the
concept of an Event Bus:
* The event sockets which publishes events.
* The event library which can listen to events and send events into the salt system.
Events are published onto the event bus and event bus subscribers listen for the
published events.
The event bus is used for both inter-process communication as well as network transport
in Salt. Inter-process communication is provided through UNIX domain sockets (UDX).
The Salt Master and each Salt Minion has their own event bus.
Event types
===========
@ -21,7 +34,7 @@ Event types
Listening for Events
====================
Salt's Event Bus is used heavily within Salt and it is also written to
Salt's event system is used heavily within Salt and it is also written to
integrate heavily with existing tooling and scripts. There is a variety of
ways to consume it.

View File

@ -174,11 +174,13 @@ to create it.
The generated grain information will appear similar to:
.. code-block:: yaml
grains:
salt-cloud:
driver: ec2
provider: my_ec2:ec2
profile: ec2-web
The generation of salt-cloud grains can be surpressed by the
option ``enable_cloud_grains: 'False'`` in the cloud configuration file.
@ -411,7 +413,7 @@ signed certificates. :ref:`Here<new-pywinrm>` for more information.
DigitalOcean
------------
The DigitalOcean driver has been renamed to conform to the companies name. The
The DigitalOcean driver has been renamed to conform to the company name. The
new driver name is ``digitalocean``. The old name ``digital_ocean`` and a
short one ``do`` will still be supported through virtual aliases, this is mostly
cosmetic.

View File

@ -29,6 +29,7 @@ the name of the repository, and the link to the repository:
For HTTP/HTTPS Basic authorization you can define credentials:
.. code-block:: yaml
my_repo:
url: https://spm.example.com/
username: user

View File

@ -164,7 +164,7 @@ states are evaluated before ``tgt`` states.
Each of these sections needs to be evaluated as text, rather than as YAML.
Consider the following block:
.. code-block::
.. code-block:: text
pre_local_state: >
echo test > /tmp/spmtest:
@ -187,7 +187,7 @@ a minion.
the ``>`` marker to denote that the state is evaluated as text, not a data
structure.
.. code-block::
.. code-block:: text
pre_local_state: >
echo test > /tmp/spmtest:
@ -203,7 +203,7 @@ the ``spm`` command is running on is a master.
Because ``tgt`` states require that a target be specified, their code blocks
are a little different. Consider the following state:
.. code-block::
.. code-block:: text
pre_tgt_state:
tgt: '*'
@ -229,7 +229,7 @@ This means that you can use Jinja or any other supported renderer inside of
Salt. All formula variables are available to the renderer, so you can reference
``FORMULA`` data inside your state if you need to:
.. code-block::
.. code-block:: text
pre_tgt_state:
tgt: '*'

View File

@ -34,7 +34,7 @@ passing on a single socket.
TLS Support
===========
.. version_added:: 2016.11.1
.. versionadded:: 2016.11.1
The TCP transport allows for the master/minion communication to be optionally
wrapped in a TLS connection. Enabling this is simple, the master and minion need

View File

@ -260,14 +260,11 @@ the retention time defined by
250 jobs/day * 2000 minions returns = 500,000 files a day
If no job history is needed, the job cache can be disabled:
Use and External Job Cache
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: yaml
job_cache: False
If the job cache is necessary there are (currently) 2 options:
An external job cache allows for job storage to be placed on an external
system, such as a database.
- ext_job_cache: this will have the minions store their return data directly
into a returner (not sent through the Master)
@ -287,3 +284,20 @@ for up to sixty seconds by default.
To enable the master key cache, set `key_cache: 'sched'` in the master
configuration file.
Disable The Job Cache
~~~~~~~~~~~~~~~~~~~~~
The job cache is a central component of the Salt Master and many aspects of
the Salt Master will not function correctly without a running job cache.
Disabling the job cache is **STRONGLY DISCOURAGED** and should not be done
unless the master is being used to execute routines that require no history
or reliable feedback!
The job cache can be disabled:
.. code-block:: yaml
job_cache: False

View File

@ -9,3 +9,4 @@ SaltPyLint>=v2017.3.6
pytest
git+https://github.com/eisensheng/pytest-catchlog.git@develop#egg=Pytest-catchlog
git+https://github.com/saltstack/pytest-salt.git@master#egg=pytest-salt
testinfra>=1.7.0

View File

@ -13,3 +13,5 @@ httpretty
SaltPyLint>=v2017.2.29
pytest
git+https://github.com/saltstack/pytest-salt.git@master#egg=pytest-salt
git+https://github.com/eisensheng/pytest-catchlog.git@develop#egg=Pytest-catchlog
testinfra>=1.7.0

View File

@ -29,7 +29,6 @@ import salt.transport.client
import salt.utils.args
import salt.utils.dictupdate
import salt.utils.files
import salt.utils.master
import salt.utils.minions
import salt.utils.user
import salt.utils.versions
@ -444,6 +443,8 @@ class LoadAuth(object):
auth_ret = True
if auth_ret is not True:
# Avoid a circular import
import salt.utils.master
auth_list = salt.utils.master.get_values_of_matching_keys(
self.opts['publisher_acl'], auth_ret)
if not auth_list:

View File

@ -13,10 +13,12 @@ import salt.utils.stringutils
from salt.utils.args import yamlify_arg
from salt.utils.verify import verify_log
from salt.exceptions import (
SaltClientError,
SaltInvocationError,
EauthAuthenticationError
)
EauthAuthenticationError,
LoaderError,
SaltClientError,
SaltInvocationError,
SaltSystemExit
)
# Import 3rd-party libs
from salt.ext import six
@ -167,8 +169,8 @@ class SaltCMD(salt.utils.parsers.SaltCMDOptionParser):
out = 'progress'
try:
self._progress_ret(progress, out)
except salt.exceptions.LoaderError as exc:
raise salt.exceptions.SaltSystemExit(exc)
except LoaderError as exc:
raise SaltSystemExit(exc)
if 'return_count' not in progress:
ret.update(progress)
self._progress_end(out)
@ -251,7 +253,7 @@ class SaltCMD(salt.utils.parsers.SaltCMDOptionParser):
try:
batch = salt.cli.batch.Batch(self.config, eauth=eauth, quiet=True)
except salt.exceptions.SaltClientError as exc:
except SaltClientError:
sys.exit(2)
ret = {}
@ -265,7 +267,7 @@ class SaltCMD(salt.utils.parsers.SaltCMDOptionParser):
try:
self.config['batch'] = self.options.batch
batch = salt.cli.batch.Batch(self.config, eauth=eauth, parser=self.options)
except salt.exceptions.SaltClientError as exc:
except SaltClientError:
# We will print errors to the console further down the stack
sys.exit(1)
# Printing the output is already taken care of in run() itself
@ -345,9 +347,9 @@ class SaltCMD(salt.utils.parsers.SaltCMDOptionParser):
if not hasattr(self, 'progress_bar'):
try:
self.progress_bar = salt.output.get_progress(self.config, out, progress)
except Exception as exc:
raise salt.exceptions.LoaderError('\nWARNING: Install the `progressbar` python package. '
'Requested job was still run but output cannot be displayed.\n')
except Exception:
raise LoaderError('\nWARNING: Install the `progressbar` python package. '
'Requested job was still run but output cannot be displayed.\n')
salt.output.update_progress(self.config, progress, self.progress_bar, out)
def _output_ret(self, ret, out):

View File

@ -258,19 +258,30 @@ def create(vm_):
wol_host = config.get_cloud_config_value(
'wol_sender_node', vm_, __opts__, default='')
if wol_mac and wol_host:
log.info('sending wake-on-lan to %s using node %s',
wol_mac, wol_host)
local = salt.client.LocalClient()
if isinstance(wol_mac, six.string_types):
wol_mac = [wol_mac] # a smart user may have passed more params
ret = local.cmd(wol_host, 'network.wol', wol_mac)
log.info('network.wol returned value %s', ret)
if ret and ret[wol_host]:
sleep_time = config.get_cloud_config_value(
'wol_boot_wait', vm_, __opts__, default=30)
if sleep_time > 0.0:
log.info('delaying %d seconds for boot', sleep_time)
time.sleep(sleep_time)
good_ping = False
ssh_host = config.get_cloud_config_value(
'ssh_host', vm_, __opts__, default='')
if ssh_host:
log.info('trying to ping %s', ssh_host)
count = 'n' if salt.utils.platform.is_windows() else 'c'
cmd = 'ping -{} 1 {}'.format(count, ssh_host)
good_ping = __salt__['cmd.retcode'](cmd) == 0
if good_ping:
log.info('successful ping.')
else:
log.info('sending wake-on-lan to %s using node %s',
wol_mac, wol_host)
local = salt.client.LocalClient()
if isinstance(wol_mac, six.string_types):
wol_mac = [wol_mac] # a smart user may have passed more params
ret = local.cmd(wol_host, 'network.wol', wol_mac)
log.info('network.wol returned value %s', ret)
if ret and ret[wol_host]:
sleep_time = config.get_cloud_config_value(
'wol_boot_wait', vm_, __opts__, default=30)
if sleep_time > 0.0:
log.info('delaying %d seconds for boot', sleep_time)
time.sleep(sleep_time)
log.info('Provisioning existing machine %s', vm_['name'])
ret = __utils__['cloud.bootstrap'](vm_, __opts__)
else:

View File

@ -30,7 +30,8 @@ if six.PY3:
import ipaddress
else:
import salt.ext.ipaddress as ipaddress
from salt.exceptions import SaltCloudException, SaltCloudSystemExit
from salt.exceptions import SaltCloudException, SaltCloudSystemExit, \
SaltInvocationError
# Get logging started
log = logging.getLogger(__name__)
@ -194,6 +195,7 @@ def create(vm_):
CLI Example:
.. code-block:: bash
salt-cloud -p my_profile new_node_1
'''
@ -228,18 +230,22 @@ def create(vm_):
kwarg={'network_mask': network_mask,
'get_private_key': True})[host]
with tempfile.NamedTemporaryFile() as pks:
if 'private_key' not in vm_ and ret.get('private_key', False):
if 'private_key' not in vm_ and ret and ret.get('private_key', False):
pks.write(ret['private_key'])
pks.flush()
log.debug('wrote private key to %s', pks.name)
vm_['key_filename'] = pks.name
if 'ssh_host' not in vm_:
vm_.setdefault('ssh_username', ret['ssh_username'])
if ret.get('ip_address'):
vm_['ssh_host'] = ret['ip_address']
else: # if probe failed or not used, use Vagrant's reported ssh info
vm_['ssh_host'] = ret['ssh_host']
vm_.setdefault('ssh_port', ret['ssh_port'])
try:
vm_.setdefault('ssh_username', ret['ssh_username'])
if ret.get('ip_address'):
vm_['ssh_host'] = ret['ip_address']
else: # if probe failed or not used, use Vagrant's reported ssh info
vm_['ssh_host'] = ret['ssh_host']
vm_.setdefault('ssh_port', ret['ssh_port'])
except (KeyError, TypeError):
raise SaltInvocationError(
'Insufficient SSH addressing information for {}'.format(name))
log.info('Provisioning machine %s as node %s using ssh %s',
machine, name, vm_['ssh_host'])
@ -287,29 +293,32 @@ def destroy(name, call=None):
transport=opts['transport']
)
my_info = _get_my_info(name)
profile_name = my_info[name]['profile']
profile = opts['profiles'][profile_name]
host = profile['host']
local = salt.client.LocalClient()
ret = local.cmd(host, 'vagrant.destroy', [name])
if my_info:
profile_name = my_info[name]['profile']
profile = opts['profiles'][profile_name]
host = profile['host']
local = salt.client.LocalClient()
ret = local.cmd(host, 'vagrant.destroy', [name])
if ret[host]:
__utils__['cloud.fire_event'](
'event',
'destroyed instance',
'salt/cloud/{0}/destroyed'.format(name),
args={'name': name},
sock_dir=opts['sock_dir'],
transport=opts['transport']
)
if ret[host]:
__utils__['cloud.fire_event'](
'event',
'destroyed instance',
'salt/cloud/{0}/destroyed'.format(name),
args={'name': name},
sock_dir=opts['sock_dir'],
transport=opts['transport']
)
if opts.get('update_cachedir', False) is True:
__utils__['cloud.delete_minion_cachedir'](
name, __active_provider_name__.split(':')[0], opts)
if opts.get('update_cachedir', False) is True:
__utils__['cloud.delete_minion_cachedir'](
name, __active_provider_name__.split(':')[0], opts)
return {'Destroyed': '{0} was destroyed.'.format(name)}
return {'Destroyed': '{0} was destroyed.'.format(name)}
else:
return {'Error': 'Error destroying {}'.format(name)}
else:
return {'Error': 'Error destroying {}'.format(name)}
return {'Error': 'No response from {}. Cannot destroy.'.format(name)}
# noinspection PyTypeChecker

View File

@ -198,7 +198,9 @@ def list_nodes_full(kwargs=None, call=None):
This is because some functions both within Salt and 3rd party will break if an expected field is not present.
This function is normally called with the -F option:
.. code-block:: bash
salt-cloud -F
@ -244,6 +246,7 @@ def list_nodes(kwargs=None, call=None):
This function is normally called with the -Q option:
.. code-block:: bash
salt-cloud -Q

View File

@ -9,7 +9,7 @@
Common salt configuration schemas
'''
# Import Pythosn libs
# Import Python libs
from __future__ import absolute_import
# Import salt libs

View File

@ -6,6 +6,14 @@ HTTP Logstash engine
An engine that reads messages from the salt event bus and pushes
them onto a logstash endpoint via HTTP requests.
.. versionchanged:: Oxygen
.. note::
By default, this engine take everything from the Salt bus and exports into
Logstash.
For a better selection of the events that you want to publish, you can use
the ``tags`` and ``funs`` options.
:configuration: Example configuration
.. code-block:: yaml
@ -47,11 +55,9 @@ _HEADERS = {'Content-Type': 'application/json'}
def _logstash(url, data):
'''
Issues HTTP queries to the logstash server.
'''
result = salt.utils.http.query(
url,
'POST',
@ -69,11 +75,25 @@ def _logstash(url, data):
def start(url, funs=None, tags=None):
'''
Listen to salt events and forward them to logstash via HTTP.
'''
Listen to salt events and forward them to logstash.
url
The Logstash endpoint.
funs: ``None``
A list of functions to be compared against, looking into the ``fun``
field from the event data. This option helps to select the events
generated by one or more functions.
If an event does not have the ``fun`` field in the data section, it
will be published. For a better selection, consider using the ``tags``
option.
By default, this option accepts any event to be submitted to Logstash.
tags: ``None``
A list of pattern to compare the event tag against.
By default, this option accepts any event to be submitted to Logstash.
'''
if __opts__.get('id').endswith('_master'):
instance = 'master'
else:
@ -82,9 +102,8 @@ def start(url, funs=None, tags=None):
sock_dir=__opts__['sock_dir'],
transport=__opts__['transport'],
opts=__opts__)
while True:
event = event_bus.get_event(tag='salt/job', full=True)
event = event_bus.get_event(full=True)
if event:
publish = True
if isinstance(tags, list) and len(tags) > 0:
@ -93,7 +112,7 @@ def start(url, funs=None, tags=None):
if fnmatch.fnmatch(event['tag'], tag):
found_match = True
publish = found_match
if funs:
if funs and 'fun' in event['data']:
if not event['data']['fun'] in funs:
publish = False
if publish:

View File

@ -40,7 +40,7 @@ event <tag> [<extra>, <data>]
Example of usage
.. code:: txt
.. code-block:: txt
08:33:57 @gtmanfred > !ping
08:33:57 gtmanbot > gtmanfred: pong
@ -49,7 +49,7 @@ Example of usage
08:34:17 @gtmanfred > !event test/tag/ircbot irc is usefull
08:34:17 gtmanbot > gtmanfred: TaDa!
.. code:: txt
.. code-block:: txt
[DEBUG ] Sending event: tag = salt/engines/ircbot/test/tag/ircbot; data = {'_stamp': '2016-11-28T14:34:16.633623', 'data': [u'irc', u'is', u'usefull']}

View File

@ -13,7 +13,6 @@ as those returned here
# Import python libs
from __future__ import absolute_import
import os
import json
import socket
import sys
import glob
@ -449,10 +448,15 @@ def _bsd_memdata(osdata):
sysctl = salt.utils.path.which('sysctl')
if sysctl:
mem = __salt__['cmd.run']('{0} -n hw.physmem'.format(sysctl))
swap_total = __salt__['cmd.run']('{0} -n vm.swap_total'.format(sysctl))
if osdata['kernel'] == 'NetBSD' and mem.startswith('-'):
mem = __salt__['cmd.run']('{0} -n hw.physmem64'.format(sysctl))
grains['mem_total'] = int(mem) // 1024 // 1024
if osdata['kernel'] == 'OpenBSD':
swapctl = salt.utils.path.which('swapctl')
swap_total = __salt__['cmd.run']('{0} -sk'.format(swapctl)).split(' ')[1]
else:
swap_total = __salt__['cmd.run']('{0} -n vm.swap_total'.format(sysctl))
grains['swap_total'] = int(swap_total) // 1024 // 1024
return grains
@ -936,8 +940,6 @@ def _virtual(osdata):
zone = __salt__['cmd.run']('{0}'.format(zonename))
if zone != 'global':
grains['virtual'] = 'zone'
if salt.utils.platform.is_smartos_zone():
grains.update(_smartos_zone_data())
# Check if it's a branded zone (i.e. Solaris 8/9 zone)
if isdir('/.SUNWnative'):
grains['virtual'] = 'zone'
@ -1671,8 +1673,6 @@ def os_data():
])
# store a untouched copy of the timestamp in osrelease_stamp
grains['osrelease_stamp'] = uname_v
if salt.utils.platform.is_smartos_globalzone():
grains.update(_smartos_computenode_data())
elif os.path.isfile('/etc/release'):
with salt.utils.files.fopen('/etc/release', 'r') as fp_:
rel_data = fp_.read()
@ -1777,9 +1777,6 @@ def os_data():
# Get the hardware and bios data
grains.update(_hw_data(grains))
# Get zpool data
grains.update(_zpool_data(grains))
# Load the virtual machine info
grains.update(_virtual(grains))
grains.update(_ps(grains))
@ -2371,123 +2368,6 @@ def _hw_data(osdata):
return grains
def _smartos_computenode_data():
'''
Return useful information from a SmartOS compute node
'''
# Provides:
# vms_total
# vms_running
# vms_stopped
# sdc_version
# vm_capable
# vm_hw_virt
if salt.utils.platform.is_proxy():
return {}
grains = {}
# *_vms grains
grains['computenode_vms_total'] = len(__salt__['cmd.run']('vmadm list -p').split("\n"))
grains['computenode_vms_running'] = len(__salt__['cmd.run']('vmadm list -p state=running').split("\n"))
grains['computenode_vms_stopped'] = len(__salt__['cmd.run']('vmadm list -p state=stopped').split("\n"))
# sysinfo derived grains
sysinfo = json.loads(__salt__['cmd.run']('sysinfo'))
grains['computenode_sdc_version'] = sysinfo['SDC Version']
grains['computenode_vm_capable'] = sysinfo['VM Capable']
if sysinfo['VM Capable']:
grains['computenode_vm_hw_virt'] = sysinfo['CPU Virtualization']
# sysinfo derived smbios grains
grains['manufacturer'] = sysinfo['Manufacturer']
grains['productname'] = sysinfo['Product']
grains['uuid'] = sysinfo['UUID']
return grains
def _smartos_zone_data():
'''
Return useful information from a SmartOS zone
'''
# Provides:
# pkgsrcversion
# imageversion
# pkgsrcpath
# zonename
# zoneid
# hypervisor_uuid
# datacenter
if salt.utils.platform.is_proxy():
return {}
grains = {}
pkgsrcversion = re.compile('^release:\\s(.+)')
imageversion = re.compile('Image:\\s(.+)')
pkgsrcpath = re.compile('PKG_PATH=(.+)')
if os.path.isfile('/etc/pkgsrc_version'):
with salt.utils.files.fopen('/etc/pkgsrc_version', 'r') as fp_:
for line in fp_:
match = pkgsrcversion.match(line)
if match:
grains['pkgsrcversion'] = match.group(1)
if os.path.isfile('/etc/product'):
with salt.utils.files.fopen('/etc/product', 'r') as fp_:
for line in fp_:
match = imageversion.match(line)
if match:
grains['imageversion'] = match.group(1)
if os.path.isfile('/opt/local/etc/pkg_install.conf'):
with salt.utils.files.fopen('/opt/local/etc/pkg_install.conf', 'r') as fp_:
for line in fp_:
match = pkgsrcpath.match(line)
if match:
grains['pkgsrcpath'] = match.group(1)
if 'pkgsrcversion' not in grains:
grains['pkgsrcversion'] = 'Unknown'
if 'imageversion' not in grains:
grains['imageversion'] = 'Unknown'
if 'pkgsrcpath' not in grains:
grains['pkgsrcpath'] = 'Unknown'
grains['zonename'] = __salt__['cmd.run']('zonename')
grains['zoneid'] = __salt__['cmd.run']('zoneadm list -p | awk -F: \'{ print $1 }\'', python_shell=True)
return grains
def _zpool_data(grains):
'''
Provide grains about zpools
'''
# quickly return if windows or proxy
if salt.utils.platform.is_windows() or 'proxyminion' in __opts__:
return {}
# quickly return if NetBSD (ZFS still under development)
if salt.utils.platform.is_netbsd():
return {}
# quickly return if no zpool and zfs command
if not salt.utils.path.which('zpool'):
return {}
# collect zpool data
zpool_grains = {}
for zpool in __salt__['cmd.run']('zpool list -H -o name,size').splitlines():
zpool = zpool.split()
zpool_grains[zpool[0]] = zpool[1]
# return grain data
if len(zpool_grains.keys()) < 1:
return {}
return {'zpool': zpool_grains}
def get_server_id():
'''
Provides an integer based on the FQDN of a machine.

196
salt/grains/smartos.py Normal file
View File

@ -0,0 +1,196 @@
# -*- coding: utf-8 -*-
'''
SmartOS grain provider
:maintainer: Jorge Schrauwen <sjorge@blackdot.be>
:maturity: new
:depends: salt.utils, salt.ext.six, salt.module.cmdmod
:platform: SmartOS
.. versionadded:: nitrogen
'''
from __future__ import absolute_import
# Import python libs
import os
import re
import json
import logging
# Import salt libs
import salt.utils.dictupdate
import salt.utils.path
import salt.utils.platform
from salt.ext.six.moves import zip
# Solve the Chicken and egg problem where grains need to run before any
# of the modules are loaded and are generally available for any usage.
import salt.modules.cmdmod
__virtualname__ = 'smartos'
__salt__ = {
'cmd.run': salt.modules.cmdmod.run,
}
log = logging.getLogger(__name__)
def __virtual__():
'''
Only load when we are on SmartOS
'''
if salt.utils.platform.is_smartos():
return __virtualname__
return False
def _smartos_computenode_data():
'''
Return useful information from a SmartOS compute node
'''
# Provides:
# vms_total
# vms_running
# vms_stopped
# vms_type
# sdc_version
# vm_capable
# vm_hw_virt
grains = {}
# collect vm data
vms = {}
for vm in __salt__['cmd.run']('vmadm list -p -o uuid,alias,state,type').split("\n"):
vm = dict(list(zip(['uuid', 'alias', 'state', 'type'], vm.split(':'))))
vms[vm['uuid']] = vm
del vms[vm['uuid']]['uuid']
# set vm grains
grains['computenode_vms_total'] = len(vms)
grains['computenode_vms_running'] = 0
grains['computenode_vms_stopped'] = 0
grains['computenode_vms_type'] = {'KVM': 0, 'LX': 0, 'OS': 0}
for vm in vms:
if vms[vm]['state'].lower() == 'running':
grains['computenode_vms_running'] += 1
elif vms[vm]['state'].lower() == 'stopped':
grains['computenode_vms_stopped'] += 1
if vms[vm]['type'] not in grains['computenode_vms_type']:
# NOTE: be prepared for when bhyve gets its own type
grains['computenode_vms_type'][vms[vm]['type']] = 0
grains['computenode_vms_type'][vms[vm]['type']] += 1
# sysinfo derived grains
sysinfo = json.loads(__salt__['cmd.run']('sysinfo'))
grains['computenode_sdc_version'] = sysinfo['SDC Version']
grains['computenode_vm_capable'] = sysinfo['VM Capable']
if sysinfo['VM Capable']:
grains['computenode_vm_hw_virt'] = sysinfo['CPU Virtualization']
# sysinfo derived smbios grains
grains['manufacturer'] = sysinfo['Manufacturer']
grains['productname'] = sysinfo['Product']
grains['uuid'] = sysinfo['UUID']
return grains
def _smartos_zone_data():
'''
Return useful information from a SmartOS zone
'''
# Provides:
# zoneid
# zonename
# imageversion
grains = {
'zoneid': __salt__['cmd.run']('zoneadm list -p | awk -F: \'{ print $1 }\'', python_shell=True),
'zonename': __salt__['cmd.run']('zonename'),
'imageversion': 'Unknown',
}
imageversion = re.compile('Image:\\s(.+)')
if os.path.isfile('/etc/product'):
with salt.utils.files.fopen('/etc/product', 'r') as fp_:
for line in fp_:
match = imageversion.match(line)
if match:
grains['imageversion'] = match.group(1)
return grains
def _smartos_zone_pkgsrc_data():
'''
SmartOS zone pkgsrc information
'''
# Provides:
# pkgsrcversion
# pkgsrcpath
grains = {
'pkgsrcversion': 'Unknown',
'pkgsrcpath': 'Unknown',
}
pkgsrcversion = re.compile('^release:\\s(.+)')
if os.path.isfile('/etc/pkgsrc_version'):
with salt.utils.files.fopen('/etc/pkgsrc_version', 'r') as fp_:
for line in fp_:
match = pkgsrcversion.match(line)
if match:
grains['pkgsrcversion'] = match.group(1)
pkgsrcpath = re.compile('PKG_PATH=(.+)')
if os.path.isfile('/opt/local/etc/pkg_install.conf'):
with salt.utils.files.fopen('/opt/local/etc/pkg_install.conf', 'r') as fp_:
for line in fp_:
match = pkgsrcpath.match(line)
if match:
grains['pkgsrcpath'] = match.group(1)
return grains
def _smartos_zone_pkgin_data():
'''
SmartOS zone pkgsrc information
'''
# Provides:
# pkgin_repositories
grains = {
'pkgin_repositories': [],
}
pkginrepo = re.compile('^(?:https|http|ftp|file)://.*$')
if os.path.isfile('/opt/local/etc/pkgin/repositories.conf'):
with salt.utils.files.fopen('/opt/local/etc/pkgin/repositories.conf', 'r') as fp_:
for line in fp_:
if pkginrepo.match(line):
grains['pkgin_repositories'].append(line)
return grains
def smartos():
'''
Provide grains for SmartOS
'''
grains = {}
if salt.utils.platform.is_smartos_zone():
grains = salt.utils.dictupdate.update(grains, _smartos_zone_data(), merge_lists=True)
grains = salt.utils.dictupdate.update(grains, _smartos_zone_pkgsrc_data(), merge_lists=True)
grains = salt.utils.dictupdate.update(grains, _smartos_zone_pkgin_data(), merge_lists=True)
elif salt.utils.platform.is_smartos_globalzone():
grains = salt.utils.dictupdate.update(grains, _smartos_computenode_data(), merge_lists=True)
return grains
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

113
salt/grains/zfs.py Normal file
View File

@ -0,0 +1,113 @@
# -*- coding: utf-8 -*-
'''
ZFS grain provider
:maintainer: Jorge Schrauwen <sjorge@blackdot.be>
:maturity: new
:depends: salt.utils, salt.module.cmdmod
:platform: illumos,freebsd,linux
.. versionadded:: Oxygen
'''
from __future__ import absolute_import
# Import python libs
import logging
# Import salt libs
import salt.utils.dictupdate
import salt.utils.path
import salt.utils.platform
# Solve the Chicken and egg problem where grains need to run before any
# of the modules are loaded and are generally available for any usage.
import salt.modules.cmdmod
__virtualname__ = 'zfs'
__salt__ = {
'cmd.run': salt.modules.cmdmod.run,
}
log = logging.getLogger(__name__)
def __virtual__():
'''
Load zfs grains
'''
# NOTE: we always load this grain so we can properly export
# atleast the zfs_support grain
return __virtualname__
def _check_retcode(cmd):
'''
Simple internal wrapper for cmdmod.retcode
'''
return salt.modules.cmdmod.retcode(cmd, output_loglevel='quiet', ignore_retcode=True) == 0
def _zfs_support():
'''
Provide information about zfs kernel module
'''
grains = {'zfs_support': False}
# Check for zfs support
# NOTE: ZFS on Windows is in development
# NOTE: ZFS on NetBSD is in development
on_supported_platform = False
if salt.utils.platform.is_sunos() and salt.utils.path.which('zfs'):
on_supported_platform = True
elif salt.utils.platform.is_freebsd() and _check_retcode('kldstat -q -m zfs'):
on_supported_platform = True
elif salt.utils.platform.is_linux():
modinfo = salt.utils.path.which('modinfo')
if modinfo:
on_supported_platform = _check_retcode('{0} zfs'.format(modinfo))
else:
on_supported_platform = _check_retcode('ls /sys/module/zfs')
# NOTE: fallback to zfs-fuse if needed
if not on_supported_platform and salt.utils.path.which('zfs-fuse'):
on_supported_platform = True
# Additional check for the zpool command
if on_supported_platform and salt.utils.path.which('zpool'):
grains['zfs_support'] = True
return grains
def _zfs_pool_data():
'''
Provide grains about zpools
'''
grains = {}
# collect zpool data
zpool_cmd = salt.utils.path.which('zpool')
for zpool in __salt__['cmd.run']('{zpool} list -H -o name,size'.format(zpool=zpool_cmd)).splitlines():
if 'zpool' not in grains:
grains['zpool'] = {}
zpool = zpool.split()
grains['zpool'][zpool[0]] = zpool[1]
# return grain data
return grains
def zfs():
'''
Provide grains for zfs/zpool
'''
grains = {}
grains = salt.utils.dictupdate.update(grains, _zfs_support(), merge_lists=True)
if grains['zfs_support']:
grains = salt.utils.dictupdate.update(grains, _zfs_pool_data(), merge_lists=True)
return grains
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

View File

@ -1037,7 +1037,7 @@ class Minion(MinionBase):
u'may result in loss of contact with minions. Please '
u'upgrade your ZMQ!'
)
# Late setup the of the opts grains, so we can log from the grains
# Late setup of the opts grains, so we can log from the grains
# module. If this is a proxy, however, we need to init the proxymodule
# before we can get the grains. We do this for proxies in the
# post_master_init
@ -1244,7 +1244,7 @@ class Minion(MinionBase):
)
modules_max_memory = True
old_mem_limit = resource.getrlimit(resource.RLIMIT_AS)
rss, vms = psutil.Process(os.getpid()).memory_info()
rss, vms = psutil.Process(os.getpid()).memory_info()[:2]
mem_limit = rss + vms + self.opts[u'modules_max_memory']
resource.setrlimit(resource.RLIMIT_AS, (mem_limit, mem_limit))
elif self.opts.get(u'modules_max_memory', -1) > 0:

View File

@ -1392,7 +1392,7 @@ def list_pkgs(versions_as_list=False,
version_num)
# Check for virtual packages. We need dctrl-tools for this.
if not removed:
if not removed and not HAS_APT:
try:
virtpkgs_all = _get_virtual()
except CommandExecutionError as cee:

View File

@ -513,16 +513,16 @@ def tar(options, tarfile, sources=None, dest=None,
.. code-block:: bash
salt '*' archive.tar -cjvf /tmp/salt.tar.bz2 {{grains.saltpath}} template=jinja
salt '*' archive.tar cjvf /tmp/salt.tar.bz2 {{grains.saltpath}} template=jinja
CLI Examples:
.. code-block:: bash
# Create a tarfile
salt '*' archive.tar -cjvf /tmp/tarfile.tar.bz2 /tmp/file_1,/tmp/file_2
salt '*' archive.tar cjvf /tmp/tarfile.tar.bz2 /tmp/file_1,/tmp/file_2
# Create a tarfile using globbing (2017.7.0 and later)
salt '*' archive.tar -cjvf /tmp/tarfile.tar.bz2 '/tmp/file_*'
salt '*' archive.tar cjvf /tmp/tarfile.tar.bz2 '/tmp/file_*'
# Unpack a tarfile
salt '*' archive.tar xf foo.tar dest=/target/directory
'''

View File

@ -2,7 +2,7 @@
'''
Connection module for Amazon APIGateway
.. versionadded::
.. versionadded:: 2016.11.0
:configuration: This module accepts explicit Lambda credentials but can also
utilize IAM roles assigned to the instance trough Instance Profiles.

View File

@ -1747,6 +1747,7 @@ def set_volumes_tags(tag_maps, authoritative=False, dry_run=False,
YAML example fragment:
.. code-block:: yaml
- filters:
attachment.instance_id: i-abcdef12
tags:

View File

@ -156,7 +156,7 @@ def create_file_system(name,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.create_file_system efs-name generalPurpose
'''
@ -222,7 +222,7 @@ def create_mount_target(filesystemid,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.create_mount_target filesystemid subnetid
'''
@ -269,7 +269,7 @@ def create_tags(filesystemid,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.create_tags
'''
@ -301,7 +301,7 @@ def delete_file_system(filesystemid,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.delete_file_system filesystemid
'''
@ -335,7 +335,7 @@ def delete_mount_target(mounttargetid,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.delete_mount_target mounttargetid
'''
@ -363,7 +363,7 @@ def delete_tags(filesystemid,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.delete_tags
'''
@ -398,7 +398,7 @@ def get_file_systems(filesystemid=None,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.get_file_systems efs-id
'''
@ -454,7 +454,7 @@ def get_mount_targets(filesystemid=None,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.get_mount_targets
'''
@ -493,7 +493,7 @@ def get_tags(filesystemid,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.get_tags efs-id
'''
@ -527,7 +527,7 @@ def set_security_groups(mounttargetid,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' boto_efs.set_security_groups my-mount-target-id my-sec-group
'''

View File

@ -1703,7 +1703,6 @@ def build_interface(iface, iface_type, enabled, **settings):
salt '*' ip.build_interface eth0 eth <settings>
'''
iface = iface.lower()
iface_type = iface_type.lower()
if iface_type not in _IFACE_TYPES:
@ -1773,7 +1772,6 @@ def build_routes(iface, **settings):
salt '*' ip.build_routes eth0 <settings>
'''
iface = iface.lower()
opts = _parse_routes(iface, settings)
try:
template = JINJA.get_template('route_eth.jinja')

View File

@ -1,4 +1,9 @@
# -*- coding: utf-8 -*-
'''
Module to work with salt formula defaults files
'''
from __future__ import absolute_import
import json
import logging

View File

@ -1645,12 +1645,12 @@ def _mkstemp_copy(path,
def _starts_till(src, probe, strip_comments=True):
'''
Returns True if src and probe at least begins till some point.
Returns True if src and probe at least matches at the beginning till some point.
'''
def _strip_comments(txt):
'''
Strip possible comments.
Usually commends are one or two symbols
Usually comments are one or two symbols at the beginning of the line, separated with space
'''
buff = txt.split(" ", 1)
return len(buff) == 2 and len(buff[0]) < 2 and buff[1] or txt
@ -1714,6 +1714,8 @@ def _assert_occurrence(src, probe, target, amount=1):
if msg:
raise CommandExecutionError('Found {0} expected occurrences in "{1}" expression'.format(msg, target))
return occ
def _get_line_indent(src, line, indent):
'''
@ -1849,10 +1851,10 @@ def line(path, content=None, match=None, mode=None, location=None,
# We've set the content to be empty in the function params but we want to make sure
# it gets passed when needed. Feature #37092
modeswithemptycontent = ['delete']
if mode not in modeswithemptycontent and content is None:
raise CommandExecutionError('Content can only be empty if mode is {0}'.format(modeswithemptycontent))
del modeswithemptycontent
empty_content_modes = ['delete']
if mode not in empty_content_modes and content is None:
raise CommandExecutionError('Content can only be empty if mode is "{0}"'.format(', '.join(empty_content_modes)))
del empty_content_modes
# Before/after has privilege. If nothing defined, match is used by content.
if before is None and after is None and not match:
@ -1884,13 +1886,13 @@ def line(path, content=None, match=None, mode=None, location=None,
_assert_occurrence(body, after, 'after')
out = []
lines = body.split(os.linesep)
for idx in range(len(lines)):
_line = lines[idx]
if _line.find(before) > -1 and idx <= len(lines) and lines[idx - 1].find(after) > -1:
out.append(_get_line_indent(_line, content, indent))
out.append(_line)
else:
out.append(_line)
in_range = False
for line in lines:
if line.find(after) > -1:
in_range = True
elif line.find(before) > -1 and in_range:
out.append(_get_line_indent(line, content, indent))
out.append(line)
body = os.linesep.join(out)
if before and not after:
@ -1910,21 +1912,21 @@ def line(path, content=None, match=None, mode=None, location=None,
_assert_occurrence(body, after, 'after')
out = []
lines = body.split(os.linesep)
for idx in range(len(lines)):
_line = lines[idx]
for idx, _line in enumerate(lines):
out.append(_line)
cnd = _get_line_indent(_line, content, indent)
if _line.find(after) > -1:
# No dupes or append, if "after" is the last line
if (idx < len(lines) and _starts_till(lines[idx + 1], cnd) < 0) or idx + 1 == len(lines):
out.append(cnd)
# No duplicates or append, if "after" is the last line
if (_line.find(after) > -1 and
(lines[((idx + 1) < len(lines)) and idx + 1 or idx].strip() != cnd or
idx + 1 == len(lines))):
out.append(cnd)
body = os.linesep.join(out)
else:
if location == 'start':
body = ''.join([content, body])
body = os.linesep.join((content, body))
elif location == 'end':
body = ''.join([body, _get_line_indent(body[-1], content, indent) if body else content])
body = os.linesep.join((body, _get_line_indent(body[-1], content, indent) if body else content))
elif mode == 'ensure':
after = after and after.strip()
@ -1934,25 +1936,21 @@ def line(path, content=None, match=None, mode=None, location=None,
_assert_occurrence(body, before, 'before')
_assert_occurrence(body, after, 'after')
a_idx = b_idx = -1
idx = 0
body = body.split(os.linesep)
for _line in body:
idx += 1
if _line.find(before) > -1 and b_idx < 0:
b_idx = idx
if _line.find(after) > -1 and a_idx < 0:
a_idx = idx
# Add
if not b_idx - a_idx - 1:
body = body[:a_idx] + [content] + body[b_idx - 1:]
elif b_idx - a_idx - 1 == 1:
if _starts_till(body[a_idx:b_idx - 1][0], content) > -1:
body[a_idx] = _get_line_indent(body[a_idx - 1], content, indent)
else:
raise CommandExecutionError('Found more than one line between boundaries "before" and "after".')
body = os.linesep.join(body)
is_there = bool(body.count(content))
if not is_there:
out = []
body = body.split(os.linesep)
for idx, line in enumerate(body):
out.append(line)
if line.find(content) > -1:
is_there = True
if not is_there:
if idx < (len(body) - 1) and line.find(after) > -1 and body[idx + 1].find(before) > -1:
out.append(content)
elif line.find(after) > -1:
raise CommandExecutionError('Found more than one line between '
'boundaries "before" and "after".')
body = os.linesep.join(out)
elif before and not after:
_assert_occurrence(body, before, 'before')
@ -1961,7 +1959,7 @@ def line(path, content=None, match=None, mode=None, location=None,
for idx in range(len(body)):
if body[idx].find(before) > -1:
prev = (idx > 0 and idx or 1) - 1
out.append(_get_line_indent(body[prev], content, indent))
out.append(_get_line_indent(body[idx], content, indent))
if _starts_till(out[prev], content) > -1:
del out[prev]
out.append(body[idx])

View File

@ -413,6 +413,7 @@ def delkey(key):
CLI Example:
.. code-block:: bash
salt '*' grains.delkey key
'''
setval(key, None, destructive=True)

View File

@ -585,7 +585,8 @@ def _parse_members(settype, members):
def _parse_member(settype, member, strict=False):
subtypes = settype.split(':')[1].split(',')
parts = member.split(' ')
all_parts = member.split(' ', 1)
parts = all_parts[0].split(',')
parsed_member = []
for i in range(len(subtypes)):
@ -610,8 +611,8 @@ def _parse_member(settype, member, strict=False):
parsed_member.append(part)
if len(parts) > len(subtypes):
parsed_member.append(' '.join(parts[len(subtypes):]))
if len(all_parts) > 1:
parsed_member.append(all_parts[1])
return parsed_member

View File

@ -112,7 +112,7 @@ def run(script):
CLI Example:
.. code-block::
.. code-block:: bash
salt '*' jenkins.run 'Jenkins.instance.doSafeRestart()'

View File

@ -28,6 +28,7 @@ For an item only one field should be provided. Either a `data` or a `file` entry
In case both are provided the `file` entry is prefered.
.. code-block:: bash
salt '*' kubernetes.nodes api_url=http://k8s-api-server:port api_user=myuser api_password=pass
.. versionadded: 2017.7.0
@ -35,6 +36,7 @@ In case both are provided the `file` entry is prefered.
# Import Python Futures
from __future__ import absolute_import
import sys
import os.path
import base64
import logging
@ -164,13 +166,16 @@ def _setup_conn(**kwargs):
if client_key_file:
kubernetes.client.configuration.key_file = client_key_file
if client_key:
elif client_key:
with tempfile.NamedTemporaryFile(prefix='salt-kube-', delete=False) as k:
k.write(base64.b64decode(client_key))
kubernetes.client.configuration.key_file = k.name
else:
kubernetes.client.configuration.key_file = None
# The return makes unit testing easier
return vars(kubernetes.client.configuration)
def _cleanup(**kwargs):
ca = kubernetes.client.configuration.ssl_ca_cert
@ -269,7 +274,7 @@ def node_labels(name, **kwargs):
match = node(name, **kwargs)
if match is not None:
return match.metadata.labels
return match['metadata']['labels']
return {}
@ -1050,14 +1055,22 @@ def create_service(
def create_secret(
name,
namespace,
data,
source,
template,
saltenv,
namespace='default',
data=None,
source=None,
template=None,
saltenv='base',
**kwargs):
'''
Creates the kubernetes secret as defined by the user.
CLI Examples::
salt 'minion1' kubernetes.create_secret \
passwords default '{"db": "letmein"}'
salt 'minion2' kubernetes.create_secret \
name=passwords namespace=default data='{"db": "letmein"}'
'''
if source:
data = __read_and_render_yaml_file(source, template, saltenv)
@ -1099,12 +1112,20 @@ def create_configmap(
name,
namespace,
data,
source,
template,
saltenv,
source=None,
template=None,
saltenv='base',
**kwargs):
'''
Creates the kubernetes configmap as defined by the user.
CLI Examples::
salt 'minion1' kubernetes.create_configmap \
settings default '{"example.conf": "# example file"}'
salt 'minion2' kubernetes.create_configmap \
name=settings namespace=default data='{"example.conf": "# example file"}'
'''
if source:
data = __read_and_render_yaml_file(source, template, saltenv)
@ -1273,14 +1294,22 @@ def replace_service(name,
def replace_secret(name,
data,
source,
template,
saltenv,
source=None,
template=None,
saltenv='base',
namespace='default',
**kwargs):
'''
Replaces an existing secret with a new one defined by name and namespace,
having the specificed data.
CLI Examples::
salt 'minion1' kubernetes.replace_secret \
name=passwords data='{"db": "letmein"}'
salt 'minion2' kubernetes.replace_secret \
name=passwords namespace=saltstack data='{"db": "passw0rd"}'
'''
if source:
data = __read_and_render_yaml_file(source, template, saltenv)
@ -1320,14 +1349,22 @@ def replace_secret(name,
def replace_configmap(name,
data,
source,
template,
saltenv,
source=None,
template=None,
saltenv='base',
namespace='default',
**kwargs):
'''
Replaces an existing configmap with a new one defined by name and
namespace, having the specificed data.
namespace with the specified data.
CLI Examples::
salt 'minion1' kubernetes.replace_configmap \
settings default '{"example.conf": "# example file"}'
salt 'minion2' kubernetes.replace_configmap \
name=settings namespace=default data='{"example.conf": "# example file"}'
'''
if source:
data = __read_and_render_yaml_file(source, template, saltenv)
@ -1444,6 +1481,13 @@ def __dict_to_object_meta(name, namespace, metadata):
'''
meta_obj = kubernetes.client.V1ObjectMeta()
meta_obj.namespace = namespace
# Replicate `kubectl [create|replace|apply] --record`
if 'annotations' not in metadata:
metadata['annotations'] = {}
if 'kubernetes.io/change-cause' not in metadata['annotations']:
metadata['annotations']['kubernetes.io/change-cause'] = ' '.join(sys.argv)
for key, value in iteritems(metadata):
if hasattr(meta_obj, key):
setattr(meta_obj, key, value)

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
'''
.. versionadded:: 2016.3.0
Manage macOS local directory passwords and policies
Manage macOS local directory passwords and policies.
.. versionadded:: 2016.3.0
Note that it is usually better to apply password policies through the creation
of a configuration profile.

View File

@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
'''
.. versionadded:: 2016.3.0
System module for sleeping, restarting, and shutting down the system on Mac OS X
System module for sleeping, restarting, and shutting down the system on Mac OS
X.
.. versionadded:: 2016.3.0
.. warning::
Using this module will enable ``atrun`` on the system if it is disabled.

View File

@ -85,6 +85,7 @@ without extra parameters:
salt-run nacl.dec 'tqXzeIJnTAM9Xf0mdLcpEdklMbfBGPj2oTKmlgrm3S1DTVVHNnh9h8mU1GKllGq/+cYsk6m5WhGdk58='
.. code-block:: yam
# a salt developers minion could have pillar data that includes a nacl public key
nacl.config:
pk: '/kfGX7PbWeu099702PBbKWLpG/9p06IQRswkdWHCDk0='

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
'''
Namecheap management
Namecheap dns management
.. versionadded:: 2017.7.0
@ -17,6 +17,7 @@
the namecheap API:
* ``requests``
.. code-block:: bash
pip install requests

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
'''
Namecheap management
Namecheap domains management
.. versionadded:: 2017.7.0
@ -73,7 +73,7 @@ def reactivate(domain_name):
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' namecheap_domains.reactivate my-domain-name

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
'''
Namecheap management
Namecheap nameservers management
.. versionadded:: 2017.7.0
@ -17,6 +17,7 @@
the namecheap API:
* ``requests``
.. code-block:: bash
pip install requests

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
'''
Namecheap management
Namecheap ssl management
.. versionadded:: 2017.7.0
@ -110,7 +110,7 @@ def reissue(csr_file,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' namecheap_ssl.reissue my-csr-file my-cert-id apachessl
'''
@ -164,7 +164,7 @@ def activate(csr_file,
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' namecheap_ssl.activate my-csr-file my-cert-id apachessl
'''
@ -298,7 +298,7 @@ def renew(years, certificate_id, certificate_type, promotion_code=None):
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' namecheap_ssl.renew 1 my-cert-id RapidSSL
'''
@ -460,7 +460,7 @@ Symantec Secure Site 1 25 24
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' namecheap_ssl.create 2 RapidSSL
'''
@ -557,7 +557,7 @@ def parse_csr(csr_file, certificate_type, http_dc_validation=False):
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' namecheap_ssl.parse_csr my-csr-file PremiumSSL
'''
@ -644,7 +644,7 @@ def get_list(**kwargs):
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' namecheap_ssl.get_list Processing
'''
@ -688,7 +688,7 @@ def get_info(certificate_id, returncertificate=False, returntype=None):
CLI Example:
.. code-block::
.. code-block:: bash
salt 'my-minion' namecheap_ssl.get_info my-cert-id
'''

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
'''
Namecheap management
Namecheap users management
.. versionadded:: 2017.7.0

View File

@ -500,7 +500,7 @@ def cli(*commands, **kwargs): # pylint: disable=unused-argument
CLI Example with TextFSM template:
.. code-block::
.. code-block:: bash
salt '*' net.cli textfsm_parse=True textfsm_path=salt://textfsm/
@ -1238,6 +1238,7 @@ def load_config(filename=None,
Example output:
.. code-block:: python
{
'comment': 'Configuration discarded.',
'already_configured': False,

View File

@ -1,4 +1,9 @@
# -*- coding: utf-8 -*-
'''
Module for OpenSCAP Management
'''
from __future__ import absolute_import
import tempfile
import shlex

View File

@ -10,7 +10,7 @@ What has not been implemented yet can be accessed through ``parallels.prlctl``
and ``parallels.prlsrvctl`` (note the preceding double dash ``--`` as
necessary):
.. code-block::
.. code-block:: bash
salt '*' parallels.prlctl installtools macvm runas=macdev
salt -- '*' parallels.prlctl capture 'macvm --file macvm.display.png' runas=macdev

View File

@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
'''
===========================
Manage the Windows registry
===========================
-----
Hives

View File

@ -1079,7 +1079,6 @@ def build_routes(iface, **settings):
pass
log.debug('Template name: ' + template)
iface = iface.lower()
opts = _parse_routes(iface, settings)
log.debug("Opts: \n {0}".format(opts))
try:

View File

@ -58,11 +58,16 @@ def renderer(path=None, string=None, default_renderer='jinja|yaml', **kwargs):
'''
Parse a string or file through Salt's renderer system
.. versionchanged:: Oxygen
Add support for Salt fileserver URIs.
This is an open-ended function and can be used for a variety of tasks. It
makes use of Salt's "renderer pipes" system to run a string or file through
a pipe of any of the loaded renderer modules.
:param path: The path to a file on the filesystem.
:param path: The path to a file on Salt's fileserver (any URIs supported by
:py:func:`cp.get_url <salt.modules.cp.get_url>`) or on the local file
system.
:param string: An inline string to be used as the file to send through the
renderer system. Note, not all renderer modules can work with strings;
the 'py' renderer requires a file, for example.
@ -113,6 +118,7 @@ def renderer(path=None, string=None, default_renderer='jinja|yaml', **kwargs):
.. code-block:: bash
salt '*' slsutil.renderer salt://path/to/file
salt '*' slsutil.renderer /path/to/file
salt '*' slsutil.renderer /path/to/file.jinja 'jinja'
salt '*' slsutil.renderer /path/to/file.sls 'jinja|yaml'
@ -126,7 +132,7 @@ def renderer(path=None, string=None, default_renderer='jinja|yaml', **kwargs):
renderers = salt.loader.render(__opts__, __salt__)
if path:
path_or_string = path
path_or_string = __salt__['cp.get_url'](path)
elif string:
path_or_string = ':string:'
kwargs['input_data'] = string

View File

@ -229,6 +229,7 @@ def set_config(name='root', **kwargs):
snapper convention. The above example is equivalent to:
.. code-block:: bash
salt '*' snapper.set_config sync_acl=True
'''
try:

View File

@ -551,19 +551,19 @@ def _check_onlyif_unless(onlyif, unless):
if onlyif is not None:
if not isinstance(onlyif, six.string_types):
if not onlyif:
ret = {'comment': 'onlyif execution failed', 'result': True}
ret = {'comment': 'onlyif condition is false', 'result': True}
elif isinstance(onlyif, six.string_types):
if retcode(onlyif) != 0:
ret = {'comment': 'onlyif execution failed', 'result': True}
log.debug('onlyif execution failed')
ret = {'comment': 'onlyif condition is false', 'result': True}
log.debug('onlyif condition is false')
if unless is not None:
if not isinstance(unless, six.string_types):
if unless:
ret = {'comment': 'unless execution succeeded', 'result': True}
ret = {'comment': 'unless condition is true', 'result': True}
elif isinstance(unless, six.string_types):
if retcode(unless) == 0:
ret = {'comment': 'unless execution succeeded', 'result': True}
log.debug('unless execution succeeded')
ret = {'comment': 'unless condition is true', 'result': True}
log.debug('unless condition is true')
return ret

View File

@ -186,7 +186,7 @@ def extract_war_version(war):
Examples:
.. code-block::
.. code-block:: text
/path/salt-2015.8.6.war -> 2015.8.6
/path/V6R2013xD5.war -> None

View File

@ -170,6 +170,7 @@ def exportdb():
CLI Example:
.. code-block:: bash
salt '*' udev.exportdb
'''

View File

@ -1,13 +1,16 @@
# -*- coding: utf-8 -*-
'''
Functions to interact with Hashicorp Vault.
:maintainer: SaltStack
:maturity: new
:platform: all
Functions to interact with Hashicorp Vault.
:note: If you see the following error, you'll need to upgrade ``requests`` to atleast 2.4.2
.. code-block:: shell
.. code-block:: text
<timestamp> [salt.pillar][CRITICAL][14337] Pillar render error: Failed to load ext_pillar vault: {'error': "request() got an unexpected keyword argument 'json'"}
@ -151,6 +154,7 @@ def write_secret(path, **kwargs):
CLI Example:
.. code-block:: bash
salt '*' vault.write_secret "secret/my/secret" user="foo" password="bar"
'''
log.debug(
@ -176,6 +180,7 @@ def delete_secret(path):
CLI Example:
.. code-block:: bash
salt '*' vault.delete_secret "secret/my/secret"
'''
log.debug('Deleting vault secrets for {0} in {1}'
@ -199,6 +204,7 @@ def list_secrets(path):
CLI Example:
.. code-block:: bash
salt '*' vault.list_secrets "secret/my/"
'''
log.debug('Listing vault secret keys for {0} in {1}'

View File

@ -4211,6 +4211,7 @@ def list_dvportgroups(dvs=None, portgroup_names=None, service_instance=None):
Default is None.
.. code-block:: bash
salt '*' vsphere.list_dvporgroups
salt '*' vsphere.list_dvportgroups dvs=dvs1
@ -4662,6 +4663,7 @@ def list_storage_policies(policy_names=None, service_instance=None):
Default is None.
.. code-block:: bash
salt '*' vsphere.list_storage_policies
salt '*' vsphere.list_storage_policy policy_names=[policy_name]
@ -4688,6 +4690,7 @@ def list_default_vsan_policy(service_instance=None):
Default is None.
.. code-block:: bash
salt '*' vsphere.list_storage_policies
salt '*' vsphere.list_storage_policy policy_names=[policy_name]
@ -4726,6 +4729,7 @@ def list_capability_definitions(service_instance=None):
Default is None.
.. code-block:: bash
salt '*' vsphere.list_capabilities
'''
profile_manager = salt.utils.pbm.get_profile_manager(service_instance)
@ -4806,6 +4810,7 @@ def create_storage_policy(policy_name, policy_dict, service_instance=None):
Default is None.
.. code-block:: bash
salt '*' vsphere.create_storage_policy policy_name='policy name'
policy_dict="$policy_dict"
'''
@ -4845,6 +4850,7 @@ def update_storage_policy(policy, policy_dict, service_instance=None):
Default is None.
.. code-block:: bash
salt '*' vsphere.update_storage_policy policy='policy name'
policy_dict="$policy_dict"
'''
@ -4882,6 +4888,7 @@ def list_default_storage_policy_of_datastore(datastore, service_instance=None):
Default is None.
.. code-block:: bash
salt '*' vsphere.list_default_storage_policy_of_datastore datastore=ds1
'''
log.trace('Listing the default storage policy of datastore \'{0}\''
@ -4920,6 +4927,7 @@ def assign_default_storage_policy_to_datastore(policy, datastore,
Default is None.
.. code-block:: bash
salt '*' vsphere.assign_storage_policy_to_datastore
policy='policy name' datastore=ds1
'''
@ -4964,6 +4972,7 @@ def list_datacenters_via_proxy(datacenter_names=None, service_instance=None):
Default is None.
.. code-block:: bash
salt '*' vsphere.list_datacenters_via_proxy
salt '*' vsphere.list_datacenters_via_proxy dc1

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
'''
This module is Alpha
Module for working with Windows PowerShell DSC (Desired State Configuration)
This module is Alpha
This module applies DSC Configurations in the form of PowerShell scripts or
MOF (Managed Object Format) schema files.

View File

@ -39,6 +39,7 @@ Current known limitations
'''
# Import Python libs
from __future__ import absolute_import
from __future__ import unicode_literals
import io
import os
import logging
@ -48,10 +49,11 @@ import ctypes
import time
# Import Salt libs
from salt.exceptions import CommandExecutionError, SaltInvocationError
import salt.utils.dictupdate as dictupdate
import salt.utils.files
import salt.utils.platform
import salt.utils.dictupdate as dictupdate
from salt.exceptions import CommandExecutionError, SaltInvocationError
import salt.utils.stringutils
# Import 3rd-party libs
from salt.ext import six
@ -4081,7 +4083,7 @@ def _write_regpol_data(data_to_write,
gpt_ini_data = ''
if os.path.exists(gpt_ini_path):
with salt.utils.files.fopen(gpt_ini_path, 'rb') as gpt_file:
gpt_ini_data = gpt_file.read()
gpt_ini_data = salt.utils.stringutils.to_str(gpt_file.read())
if not _regexSearchRegPolData(r'\[General\]\r\n', gpt_ini_data):
gpt_ini_data = '[General]\r\n' + gpt_ini_data
if _regexSearchRegPolData(r'{0}='.format(re.escape(gpt_extension)), gpt_ini_data):
@ -4136,7 +4138,7 @@ def _write_regpol_data(data_to_write,
gpt_ini_data[general_location.end():])
if gpt_ini_data:
with salt.utils.files.fopen(gpt_ini_path, 'wb') as gpt_file:
gpt_file.write(gpt_ini_data)
gpt_file.write(salt.utils.stringutils.to_bytes(gpt_ini_data))
except Exception as e:
msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format(
gpt_ini_path, e)
@ -5374,7 +5376,7 @@ def set_(computer_policy=None, user_policy=None,
_regedits[regedit]['policy']['Registry']['Type'])
else:
_ret = __salt__['reg.delete_value'](
_regedits[regedit]['polic']['Registry']['Hive'],
_regedits[regedit]['policy']['Registry']['Hive'],
_regedits[regedit]['policy']['Registry']['Path'],
_regedits[regedit]['policy']['Registry']['Value'])
if not _ret:

View File

@ -448,8 +448,9 @@ def stop(name):
try:
win32serviceutil.StopService(name)
except pywintypes.error as exc:
raise CommandExecutionError(
'Failed To Stop {0}: {1}'.format(name, exc[2]))
if exc[0] != 1062:
raise CommandExecutionError(
'Failed To Stop {0}: {1}'.format(name, exc[2]))
attempts = 0
while info(name)['Status'] in ['Running', 'Stop Pending'] \

225
salt/modules/wordpress.py Normal file
View File

@ -0,0 +1,225 @@
# -*- coding: utf-8 -*-
'''
This module is used to manage Wordpress installations
:depends: wp binary from http://wp-cli.org/
'''
# Import Python Modules
from __future__ import absolute_import
import collections
# Import Salt Modules
import salt.utils.path
from salt.ext.six.moves import map
Plugin = collections.namedtuple('Plugin', 'name status update versino')
def __virtual__():
if salt.utils.path.which('wp'):
return True
return False
def _get_plugins(stuff):
return Plugin(stuff)
def list_plugins(path, user):
'''
List plugins in an installed wordpress path
path
path to wordpress install location
user
user to run the command as
CLI Example:
.. code-block:: bash
salt '*' wordpress.list_plugins /var/www/html apache
'''
ret = []
resp = __salt__['cmd.shell']((
'wp --path={0} plugin list'
).format(path), runas=user)
for line in resp.split('\n')[1:]:
ret.append(line.split('\t'))
return [plugin.__dict__ for plugin in map(_get_plugins, ret)]
def show_plugin(name, path, user):
'''
Show a plugin in a wordpress install and check if it is installed
name
Wordpress plugin name
path
path to wordpress install location
user
user to run the command as
CLI Example:
.. code-block:: bash
salt '*' wordpress.show_plugin HyperDB /var/www/html apache
'''
ret = {'name': name}
resp = __salt__['cmd.shell']((
'wp --path={0} plugin status {1}'
).format(path, name), runas=user).split('\n')
for line in resp:
if 'Status' in line:
ret['status'] = line.split(' ')[-1].lower()
elif 'Version' in line:
ret['version'] = line.split(' ')[-1].lower()
return ret
def activate(name, path, user):
'''
Activate a wordpress plugin
name
Wordpress plugin name
path
path to wordpress install location
user
user to run the command as
CLI Example:
.. code-block:: bash
salt '*' wordpress.activate HyperDB /var/www/html apache
'''
check = show_plugin(name, path, user)
if check['status'] == 'active':
# already active
return None
resp = __salt__['cmd.shell']((
'wp --path={0} plugin activate {1}'
).format(path, name), runas=user)
if 'Success' in resp:
return True
elif show_plugin(name, path, user)['status'] == 'active':
return True
return False
def deactivate(name, path, user):
'''
Deactivate a wordpress plugin
name
Wordpress plugin name
path
path to wordpress install location
user
user to run the command as
CLI Example:
.. code-block:: bash
salt '*' wordpress.deactivate HyperDB /var/www/html apache
'''
check = show_plugin(name, path, user)
if check['status'] == 'inactive':
# already inactive
return None
resp = __salt__['cmd.shell']((
'wp --path={0} plugin deactivate {1}'
).format(path, name), runas=user)
if 'Success' in resp:
return True
elif show_plugin(name, path, user)['status'] == 'inactive':
return True
return False
def is_installed(path, user=None):
'''
Check if wordpress is installed and setup
path
path to wordpress install location
user
user to run the command as
CLI Example:
.. code-block:: bash
salt '*' wordpress.is_installed /var/www/html apache
'''
retcode = __salt__['cmd.retcode']((
'wp --path={0} core is-installed'
).format(path), runas=user)
if retcode == 0:
return True
return False
def install(path, user, admin_user, admin_password, admin_email, title, url):
'''
Run the initial setup functions for a wordpress install
path
path to wordpress install location
user
user to run the command as
admin_user
Username for the Administrative user for the wordpress install
admin_password
Initial Password for the Administrative user for the wordpress install
admin_email
Email for the Administrative user for the wordpress install
title
Title of the wordpress website for the wordpress install
url
Url for the wordpress install
CLI Example:
.. code-block:: bash
salt '*' wordpress.install /var/www/html apache dwallace password123 \
dwallace@example.com "Daniel's Awesome Blog" https://blog.dwallace.com
'''
retcode = __salt__['cmd.retcode']((
'wp --path={0} core install '
'--title="{1}" '
'--admin_user={2} '
"--admin_password='{3}' "
'--admin_email={4} '
'--url={5}'
).format(
path,
title,
admin_user,
admin_password,
admin_email,
url
), runas=user)
if retcode == 0:
return True
return False

View File

@ -1031,17 +1031,17 @@ def _check_onlyif_unless(onlyif, unless, directory, runas=None, env=()):
if onlyif is not None:
if not isinstance(onlyif, six.string_types):
if not onlyif:
_valid(status, 'onlyif execution failed')
_valid(status, 'onlyif condition is false')
elif isinstance(onlyif, six.string_types):
if retcode(onlyif, cwd=directory, runas=runas, env=env) != 0:
_valid(status, 'onlyif execution failed')
_valid(status, 'onlyif condition is false')
if unless is not None:
if not isinstance(unless, six.string_types):
if unless:
_valid(status, 'unless execution succeeded')
_valid(status, 'unless condition is true')
elif isinstance(unless, six.string_types):
if retcode(unless, cwd=directory, runas=runas, env=env, python_shell=False) == 0:
_valid(status, 'unless execution succeeded')
_valid(status, 'unless condition is true')
if status['status']:
ret = status
return ret

View File

@ -17,6 +17,7 @@ import salt.modules.cmdmod
import salt.utils.decorators as decorators
from salt.utils.odict import OrderedDict
__virtualname__ = 'zfs'
log = logging.getLogger(__name__)
# Function alias to set mapping.
@ -25,6 +26,16 @@ __func_alias__ = {
}
def __virtual__():
'''
Only load when the platform has zfs support
'''
if __grains__['zfs_support']:
return __virtualname__
else:
return (False, "The zfs module cannot be loaded: zfs not supported")
@decorators.memoize
def _check_zfs():
'''
@ -51,42 +62,6 @@ def _check_features():
return res['retcode'] == 0
def __virtual__():
'''
Makes sure that ZFS kernel module is loaded.
'''
on_freebsd = __grains__['kernel'] == 'FreeBSD'
on_linux = __grains__['kernel'] == 'Linux'
on_solaris = __grains__['kernel'] == 'SunOS' and __grains__['kernelrelease'] == '5.11'
cmd = ''
if on_freebsd:
cmd = 'kldstat -q -m zfs'
elif on_linux:
modinfo = salt.utils.path.which('modinfo')
if modinfo:
cmd = '{0} zfs'.format(modinfo)
else:
cmd = 'ls /sys/module/zfs'
elif on_solaris:
# not using salt.utils.path.which('zfs') to keep compatible with others
cmd = 'which zfs'
if cmd and salt.modules.cmdmod.retcode(
cmd, output_loglevel='quiet', ignore_retcode=True
) == 0:
return 'zfs'
if __grains__['kernel'] == 'OpenBSD':
return False
_zfs_fuse = lambda f: __salt__['service.' + f]('zfs-fuse')
if _zfs_fuse('available') and (_zfs_fuse('status') or _zfs_fuse('start')):
return 'zfs'
return (False, "The zfs module cannot be loaded: zfs not found")
def exists(name, **kwargs):
'''
.. versionadded:: 2015.5.0

View File

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
'''
:depends: kazoo
:configuration: See :py:mod:`salt.modules.zookeeper` for setup instructions.
Concurrency controls in zookeeper
=========================================================================
:depends: kazoo
:configuration: See :py:mod:`salt.modules.zookeeper` for setup instructions.
This module allows you to acquire and release a slot. This is primarily useful
for ensureing that no more than N hosts take a specific action at once. This can
also be used to coordinate between masters.

View File

@ -34,6 +34,7 @@ Configuration
be set up as different configuration profiles. For example:
.. code-block:: yaml
zookeeper:
prod:
hosts: zoo1,zoo2,zoo3

View File

@ -19,12 +19,23 @@ from salt.utils.odict import OrderedDict
log = logging.getLogger(__name__)
__virtualname__ = 'zpool'
__func_alias__ = {
'import_': 'import',
'list_': 'list',
}
def __virtual__():
'''
Only load when the platform has zfs support
'''
if __grains__['zfs_support']:
return __virtualname__
else:
return (False, "The zpool module cannot be loaded: zfs not supported")
@salt.utils.decorators.memoize
def _check_zpool():
'''
@ -58,15 +69,6 @@ def _check_mkfile():
return salt.utils.path.which('mkfile')
def __virtual__():
'''
Provides zpool.
'''
if _check_zpool():
return 'zpool'
return (False, "Module zpool: zpool not found")
def healthy():
'''
.. versionadded:: 2016.3.0

View File

@ -71,12 +71,12 @@ A REST API for Salt
log_access_file
Path to a file to write HTTP access logs.
.. versionaddedd:: 2016.11.0
.. versionadded:: 2016.11.0
log_error_file
Path to a file to write HTTP error logs.
.. versionaddedd:: 2016.11.0
.. versionadded:: 2016.11.0
ssl_crt
The path to a SSL certificate. (See below)

View File

@ -221,6 +221,8 @@ def _format_host(host, data):
tcolor = colors['GREEN']
orchestration = ret.get('__orchestration__', False)
schanged, ctext = _format_changes(ret['changes'], orchestration)
if not ctext and 'pchanges' in ret:
schanged, ctext = _format_changes(ret['pchanges'], orchestration)
nchanges += 1 if schanged else 0
# Skip this state if it was successful & diff output was requested

View File

@ -23,7 +23,14 @@ def output(ret, bar, **kwargs): # pylint: disable=unused-argument
Update the progress bar
'''
if 'return_count' in ret:
bar.update(ret['return_count'])
val = ret['return_count']
# Avoid to fail if targets are behind a syndic. In this case actual return count will be
# higher than targeted by MoM itself.
# TODO: implement a way to get the proper target minions count and remove this workaround.
# Details are in #44239.
if val > bar.maxval:
bar.maxval = val
bar.update(val)
return ''

View File

@ -2,7 +2,7 @@
'''
Store key/value pairs in a CSV file
.. versionaddedd:: 2016.11.0
.. versionadded:: 2016.11.0
Example configuration:

View File

@ -16,6 +16,7 @@ Command Line
------------
.. code-block:: bash
salt-call pillar.get nodegroups
local:
- class_infra

View File

@ -9,6 +9,9 @@ import os
import logging
import pickle
# Import Salt libs
import salt.utils.files
# This must be present or the Salt loader won't load this module
__proxyenabled__ = ['dummy']
@ -35,16 +38,14 @@ def __virtual__():
def _save_state(details):
pck = open(FILENAME, 'wb') # pylint: disable=W8470
pickle.dump(details, pck)
pck.close()
with salt.utils.files.fopen(FILENAME, 'wb') as pck:
pickle.dump(details, pck)
def _load_state():
try:
pck = open(FILENAME, 'r') # pylint: disable=W8470
DETAILS = pickle.load(pck)
pck.close()
with salt.utils.files.fopen(FILENAME, 'r') as pck:
DETAILS = pickle.load(pck)
except IOError:
DETAILS = {}
DETAILS['initialized'] = False

View File

@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
'''
Return salt data via Telegram.
The following fields can be set in the minion conf file::
telegram.chat_id (required)
telegram.token (required)
Telegram settings may also be configured as:
.. code-block:: yaml
telegram:
chat_id: 000000000
token: 000000000:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
To use the Telegram return, append '--return telegram' to the salt command.
.. code-block:: bash
salt '*' test.ping --return telegram
'''
from __future__ import absolute_import
# Import Python libs
import logging
# Import 3rd-party libs
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
# Import Salt Libs
import salt.returners
log = logging.getLogger(__name__)
__virtualname__ = 'telegram'
def __virtual__():
'''
Return virtual name of the module.
:return: The virtual name of the module.
'''
if not HAS_REQUESTS:
return False
return __virtualname__
def _get_options(ret=None):
'''
Get the Telegram options from salt.
:param ret: The data to be sent.
:return: Dictionary containing the data and options needed to send
them to telegram.
'''
attrs = {'chat_id': 'chat_id',
'token': 'token'}
_options = salt.returners.get_returner_options(__virtualname__,
ret,
attrs,
__salt__=__salt__,
__opts__=__opts__)
log.debug('Options: {0}'.format(_options))
return _options
def returner(ret):
'''
Send a Telegram message with the data.
:param ret: The data to be sent.
:return: Boolean if message was sent successfully.
'''
_options = _get_options(ret)
chat_id = _options.get('chat_id')
token = _options.get('token')
if not chat_id:
log.error('telegram.chat_id not defined in salt config')
if not token:
log.error('telegram.token not defined in salt config')
returns = ret.get('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'),
returns)
telegram = _post_message(chat_id,
message,
token)
return telegram
def _post_message(chat_id, message, token):
'''
Send a message to a Telegram chat.
:param chat_id: The chat id.
:param message: The message to send to the telegram chat.
:param token: The Telegram API token.
:return: Boolean if message was sent successfully.
'''
url = 'https://api.telegram.org/bot{0}/sendMessage'.format(token)
parameters = dict()
if chat_id:
parameters['chat_id'] = chat_id
if message:
parameters['text'] = message
try:
response = requests.post(
url,
data=parameters
)
result = response.json()
log.debug(
'Raw response of the telegram request is {0}'.format(response))
except Exception:
log.exception(
'Sending telegram api request failed'
)
result = False
if response and 'message_id' in result:
success = True
else:
success = False
log.debug('result {0}'.format(success))
return bool(success)

View File

@ -466,7 +466,9 @@ def exit_success(jid, ext_source=None):
The external job cache to use. Default: `None`.
CLI Example:
.. code-block:: bash
salt-run jobs.exit_success 20160520145827701627
'''
ret = dict()

View File

@ -85,6 +85,7 @@ without extra parameters:
salt-run nacl.dec 'tqXzeIJnTAM9Xf0mdLcpEdklMbfBGPj2oTKmlgrm3S1DTVVHNnh9h8mU1GKllGq/+cYsk6m5WhGdk58='
.. code-block:: yam
# a salt developers minion could have pillar data that includes a nacl public key
nacl.config:
pk: '/kfGX7PbWeu099702PBbKWLpG/9p06IQRswkdWHCDk0='

View File

@ -85,7 +85,7 @@ def get_opts():
CLI Example:
.. code-block::
.. code-block:: bash
salt-run test.get_opts
'''

View File

@ -13,6 +13,7 @@ be configured in either the minion or master configuration file. This profile
requires very little. For example:
.. code-block:: yaml
myconsul:
driver: consul
host: 127.0.0.1

View File

@ -826,12 +826,12 @@ class State(object):
entry, ignore_retcode=True, python_shell=True, **cmd_opts)
log.debug(u'Last command return code: %s', cmd)
if cmd != 0 and ret[u'result'] is False:
ret.update({u'comment': u'onlyif execution failed',
ret.update({u'comment': u'onlyif condition is false',
u'skip_watch': True,
u'result': True})
return ret
elif cmd == 0:
ret.update({u'comment': u'onlyif execution succeeded', u'result': False})
ret.update({u'comment': u'onlyif condition is true', u'result': False})
return ret
if u'unless' in low_data:
@ -841,17 +841,17 @@ class State(object):
low_data_unless = low_data[u'unless']
for entry in low_data_unless:
if not isinstance(entry, six.string_types):
ret.update({u'comment': u'unless execution failed, bad type passed', u'result': False})
ret.update({u'comment': u'unless condition is false, bad type passed', u'result': False})
return ret
cmd = self.functions[u'cmd.retcode'](
entry, ignore_retcode=True, python_shell=True, **cmd_opts)
log.debug(u'Last command return code: %s', cmd)
if cmd == 0 and ret[u'result'] is False:
ret.update({u'comment': u'unless execution succeeded',
ret.update({u'comment': u'unless condition is true',
u'skip_watch': True,
u'result': True})
elif cmd != 0:
ret.update({u'comment': u'unless execution failed', u'result': False})
ret.update({u'comment': u'unless condition is false', u'result': False})
return ret
# No reason to stop, return ret

View File

@ -124,7 +124,9 @@ def present(name, api_name, swagger_file, stage_name, api_key_required,
with the following schema. The lambda functions should throw exceptions for any non successful responses.
An optional pattern field can be specified in errorMessage field to aid the response mapping from Lambda
to the proper error return status codes.
.. code-block:: yaml
Error:
type: object
properties:

View File

@ -984,7 +984,7 @@ def instance_absent(name, instance_name=None, instance_id=None,
'''
Ensure an EC2 instance does not exist (is stopped and removed).
.. versionupdated:: 2016.11.0
.. versionchanged:: 2016.11.0
name
(string) - The name of the state definition.
@ -1010,6 +1010,7 @@ def instance_absent(name, instance_name=None, instance_id=None,
YAML example fragment:
.. code-block:: yaml
- filters:
vpc-id: vpc-abcdef12
@ -1230,6 +1231,7 @@ def volumes_tagged(name, tag_maps, authoritative=False, region=None, key=None,
YAML example fragment:
.. code-block:: yaml
- filters:
attachment.instance_id: i-abcdef12
tags:

View File

@ -1636,7 +1636,7 @@ def policy_absent(name,
def saml_provider_present(name, saml_metadata_document, region=None, key=None, keyid=None, profile=None):
'''
.. versionadded::
.. versionadded:: 2016.11.0
Ensure the SAML provider with the specified name is present.
@ -1694,7 +1694,7 @@ def saml_provider_present(name, saml_metadata_document, region=None, key=None, k
def saml_provider_absent(name, region=None, key=None, keyid=None, profile=None):
'''
.. versionadded::
.. versionadded:: 2016.11.0
Ensure the SAML provider with the specified name is absent.

View File

@ -153,6 +153,7 @@ def function_present(name, FunctionName, Runtime, Role, Handler, ZipFile=None,
to the same VPC. This is a dict of the form:
.. code-block:: yaml
VpcConfig:
SecurityGroupNames:
- mysecgroup1

View File

@ -100,17 +100,17 @@ def present(name, cloud_provider, onlyif=None, unless=None, opts=None, **kwargs)
if onlyif is not None:
if not isinstance(onlyif, six.string_types):
if not onlyif:
return _valid(name, comment='onlyif execution failed')
return _valid(name, comment='onlyif condition is false')
elif isinstance(onlyif, six.string_types):
if retcode(onlyif, python_shell=True) != 0:
return _valid(name, comment='onlyif execution failed')
return _valid(name, comment='onlyif condition is false')
if unless is not None:
if not isinstance(unless, six.string_types):
if unless:
return _valid(name, comment='unless execution succeeded')
return _valid(name, comment='unless condition is true')
elif isinstance(unless, six.string_types):
if retcode(unless, python_shell=True) == 0:
return _valid(name, comment='unless execution succeeded')
return _valid(name, comment='unless condition is true')
# provider=None not cloud_provider because
# need to ensure ALL providers don't have the instance
@ -177,17 +177,17 @@ def absent(name, onlyif=None, unless=None):
if onlyif is not None:
if not isinstance(onlyif, six.string_types):
if not onlyif:
return _valid(name, comment='onlyif execution failed')
return _valid(name, comment='onlyif condition is false')
elif isinstance(onlyif, six.string_types):
if retcode(onlyif, python_shell=True) != 0:
return _valid(name, comment='onlyif execution failed')
return _valid(name, comment='onlyif condition is false')
if unless is not None:
if not isinstance(unless, six.string_types):
if unless:
return _valid(name, comment='unless execution succeeded')
return _valid(name, comment='unless condition is true')
elif isinstance(unless, six.string_types):
if retcode(unless, python_shell=True) == 0:
return _valid(name, comment='unless execution succeeded')
return _valid(name, comment='unless condition is true')
if not __salt__['cloud.has_instance'](name=name, provider=None):
ret['result'] = True
@ -253,17 +253,17 @@ def profile(name, profile, onlyif=None, unless=None, opts=None, **kwargs):
if onlyif is not None:
if not isinstance(onlyif, six.string_types):
if not onlyif:
return _valid(name, comment='onlyif execution failed')
return _valid(name, comment='onlyif condition is false')
elif isinstance(onlyif, six.string_types):
if retcode(onlyif, python_shell=True) != 0:
return _valid(name, comment='onlyif execution failed')
return _valid(name, comment='onlyif condition is false')
if unless is not None:
if not isinstance(unless, six.string_types):
if unless:
return _valid(name, comment='unless execution succeeded')
return _valid(name, comment='unless condition is true')
elif isinstance(unless, six.string_types):
if retcode(unless, python_shell=True) == 0:
return _valid(name, comment='unless execution succeeded')
return _valid(name, comment='unless condition is true')
instance = _get_instance([name])
if instance and not any('Not Actioned' in key for key in instance):
ret['result'] = True

View File

@ -343,7 +343,7 @@ def mod_run_check(cmd_kwargs, onlyif, unless, creates):
cmd = __salt__['cmd.retcode'](onlyif, ignore_retcode=True, python_shell=True, **cmd_kwargs)
log.debug('Last command return code: {0}'.format(cmd))
if cmd != 0:
return {'comment': 'onlyif execution failed',
return {'comment': 'onlyif condition is false',
'skip_watch': True,
'result': True}
elif isinstance(onlyif, list):
@ -351,13 +351,13 @@ def mod_run_check(cmd_kwargs, onlyif, unless, creates):
cmd = __salt__['cmd.retcode'](entry, ignore_retcode=True, python_shell=True, **cmd_kwargs)
log.debug('Last command \'{0}\' return code: {1}'.format(entry, cmd))
if cmd != 0:
return {'comment': 'onlyif execution failed: {0}'.format(entry),
return {'comment': 'onlyif condition is false: {0}'.format(entry),
'skip_watch': True,
'result': True}
elif not isinstance(onlyif, string_types):
if not onlyif:
log.debug('Command not run: onlyif did not evaluate to string_type')
return {'comment': 'onlyif execution failed',
return {'comment': 'onlyif condition is false',
'skip_watch': True,
'result': True}
@ -366,7 +366,7 @@ def mod_run_check(cmd_kwargs, onlyif, unless, creates):
cmd = __salt__['cmd.retcode'](unless, ignore_retcode=True, python_shell=True, **cmd_kwargs)
log.debug('Last command return code: {0}'.format(cmd))
if cmd == 0:
return {'comment': 'unless execution succeeded',
return {'comment': 'unless condition is true',
'skip_watch': True,
'result': True}
elif isinstance(unless, list):
@ -375,13 +375,13 @@ def mod_run_check(cmd_kwargs, onlyif, unless, creates):
cmd.append(__salt__['cmd.retcode'](entry, ignore_retcode=True, python_shell=True, **cmd_kwargs))
log.debug('Last command return code: {0}'.format(cmd))
if all([c == 0 for c in cmd]):
return {'comment': 'unless execution succeeded',
return {'comment': 'unless condition is true',
'skip_watch': True,
'result': True}
elif not isinstance(unless, string_types):
if unless:
log.debug('Command not run: unless did not evaluate to string_type')
return {'comment': 'unless execution succeeded',
return {'comment': 'unless condition is true',
'skip_watch': True,
'result': True}

View File

@ -1,7 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from salt.ext.six.moves import map
'''
CSF Ip tables management
========================
@ -18,6 +15,9 @@ CSF Ip tables management
method: allow
''' # pylint: disable=W0105
from __future__ import absolute_import
from salt.ext.six.moves import map
def __virtual__():
return 'csf'

View File

@ -300,7 +300,7 @@ def running(name,
Additionally, the specified selinux context will be set within the
container.
``<read_only>`` can be either ``ro`` for read-write access, or ``ro``
``<read_only>`` can be either ``rw`` for read-write access, or ``ro``
for read-only access. When omitted, it is assumed to be read-write.
``<selinux_context>`` can be ``z`` if the volume is shared between
@ -1235,6 +1235,7 @@ def running(name,
If ``True``, runs the exec process with extended privileges
.. code-block:: yaml
foo:
docker_container.running:
- image: bar/baz:lates

View File

@ -65,6 +65,7 @@ def present(name, definition=None):
**Example:**
.. code-block:: yaml
# Default settings
mytestindex:
elasticsearch_index.present

View File

@ -65,6 +65,7 @@ def present(name, definition):
**Example:**
.. code-block:: yaml
mytestindex2_template:
elasticsearch_index_template.present:
- definition:

View File

@ -45,6 +45,7 @@ Etcd profile configuration can be overriden using following arguments: ``host``,
``port``, ``username``, ``password``, ``ca``, ``client_key`` and ``client_cert``.
.. code-block:: yaml
my-value:
etcd.set:
- name: /path/to/key

View File

@ -2364,10 +2364,8 @@ def managed(name,
elif ret['pchanges']:
ret['result'] = None
ret['comment'] = u'The file {0} is set to be changed'.format(name)
if show_changes and 'diff' in ret['pchanges']:
ret['changes']['diff'] = ret['pchanges']['diff']
if not show_changes:
ret['changes']['diff'] = '<show_changes=False>'
if 'diff' in ret['pchanges'] and not show_changes:
ret['pchanges']['diff'] = '<show_changes=False>'
else:
ret['result'] = True
ret['comment'] = u'The file {0} is in the correct state'.format(name)
@ -2886,6 +2884,7 @@ def directory(name,
if __opts__['test']:
ret['result'] = presult
ret['comment'] = pcomment
ret['changes'] = ret['pchanges']
return ret
if not os.path.isdir(name):
@ -3674,20 +3673,20 @@ def line(name, content=None, match=None, mode=None, location=None,
.. versionadded:: 2015.8.0
name
:param name:
Filesystem path to the file to be edited.
content
:param content:
Content of the line. Allowed to be empty if mode=delete.
match
:param match:
Match the target line for an action by
a fragment of a string or regular expression.
If neither ``before`` nor ``after`` are provided, and ``match``
is also ``None``, match becomes the ``content`` value.
mode
:param mode:
Defines how to edit a line. One of the following options is
required:
@ -3707,7 +3706,7 @@ def line(name, content=None, match=None, mode=None, location=None,
``after``. If ``location`` is used, it takes precedence
over the other two options.
location
:param location:
Defines where to place content in the line. Note this option is only
used when ``mode=insert`` is specified. If a location is passed in, it
takes precedence over both the ``before`` and ``after`` kwargs. Valid
@ -3718,17 +3717,17 @@ def line(name, content=None, match=None, mode=None, location=None,
- end
Place the content at the end of the file.
before
:param before:
Regular expression or an exact case-sensitive fragment of the string.
This option is only used when either the ``ensure`` or ``insert`` mode
is defined.
after
:param after:
Regular expression or an exact case-sensitive fragment of the string.
This option is only used when either the ``ensure`` or ``insert`` mode
is defined.
show_changes
:param show_changes:
Output a unified diff of the old file and the new file.
If ``False`` return a boolean if any changes were made.
Default is ``True``
@ -3737,15 +3736,15 @@ def line(name, content=None, match=None, mode=None, location=None,
Using this option will store two copies of the file in-memory
(the original version and the edited version) in order to generate the diff.
backup
:param backup:
Create a backup of the original file with the extension:
"Year-Month-Day-Hour-Minutes-Seconds".
quiet
:param quiet:
Do not raise any exceptions. E.g. ignore the fact that the file that is
tried to be edited does not exist and nothing really happened.
indent
:param indent:
Keep indentation with the previous line. This option is not considered when
the ``delete`` mode is specified.

View File

@ -3002,13 +3002,13 @@ def mod_run_check(cmd_kwargs, onlyif, unless):
cmd_kwargs['python_shell'] = True
if onlyif:
if __salt__['cmd.retcode'](onlyif, **cmd_kwargs) != 0:
return {'comment': 'onlyif execution failed',
return {'comment': 'onlyif condition is false',
'skip_watch': True,
'result': True}
if unless:
if __salt__['cmd.retcode'](unless, **cmd_kwargs) == 0:
return {'comment': 'unless execution succeeded',
return {'comment': 'unless condition is true',
'skip_watch': True,
'result': True}

View File

@ -432,7 +432,7 @@ def namespace_present(name, **kwargs):
Ensures that the named namespace is present.
name
The name of the deployment.
The name of the namespace.
'''
ret = {'name': name,
@ -449,6 +449,7 @@ def namespace_present(name, **kwargs):
return ret
res = __salt__['kubernetes.create_namespace'](name, **kwargs)
ret['result'] = True
ret['changes']['namespace'] = {
'old': {},
'new': res}
@ -504,8 +505,8 @@ def secret_present(
name,
namespace='default',
data=None,
source='',
template='',
source=None,
template=None,
**kwargs):
'''
Ensures that the named secret is present inside of the specified namespace
@ -562,6 +563,7 @@ def secret_present(
else:
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'The secret is going to be replaced'
return ret
# TODO: improve checks # pylint: disable=fixme
@ -579,7 +581,7 @@ def secret_present(
ret['changes'] = {
# Omit values from the return. They are unencrypted
# and can contain sensitive data.
'data': res['data'].keys()
'data': list(res['data'])
}
ret['result'] = True
@ -594,7 +596,8 @@ def configmap_absent(name, namespace='default', **kwargs):
The name of the configmap
namespace
The name of the namespace
The namespace holding the configmap. The 'default' one is going to be
used unless a different one is specified.
'''
ret = {'name': name,
@ -631,8 +634,8 @@ def configmap_present(
name,
namespace='default',
data=None,
source='',
template='',
source=None,
template=None,
**kwargs):
'''
Ensures that the named configmap is present inside of the specified namespace
@ -665,6 +668,8 @@ def configmap_present(
ret,
'\'source\' cannot be used in combination with \'data\''
)
elif data is None:
data = {}
configmap = __salt__['kubernetes.show_configmap'](name, namespace, **kwargs)
@ -686,6 +691,7 @@ def configmap_present(
else:
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'The configmap is going to be replaced'
return ret
# TODO: improve checks # pylint: disable=fixme
@ -927,7 +933,10 @@ def node_label_folder_absent(name, node, **kwargs):
ret['result'] = True
ret['changes'] = {
'kubernetes.node_label_folder_absent': {
'new': new_labels, 'old': labels.keys()}}
'old': list(labels),
'new': new_labels,
}
}
ret['comment'] = 'Label folder removed from node'
return ret
@ -975,6 +984,7 @@ def node_label_present(
else:
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'The label is going to be updated'
return ret
ret['comment'] = 'The label is already set, changing the value'

View File

@ -34,6 +34,7 @@ Example:
Using States to deploy a load balancer with extended arguments to specify region
.. code-block:: yaml
lb_test:
libcloud_loadbalancer.balancer_present:
- name: example

Some files were not shown because too many files have changed in this diff Show More