mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 00:55:19 +00:00
Merge branch 'develop' into accept-minions-from-grains
This commit is contained in:
commit
f2aa3539ef
4
.github/stale.yml
vendored
4
.github/stale.yml
vendored
@ -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
5
.gitignore
vendored
@ -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
187
.kitchen.yml
Normal 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
23
Gemfile
Normal 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
|
@ -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!
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -46,5 +46,6 @@ returner modules
|
||||
splunk
|
||||
sqlite3_return
|
||||
syslog_return
|
||||
telegram_return
|
||||
xmpp_return
|
||||
zabbix_return
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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: '*'
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
Common salt configuration schemas
|
||||
'''
|
||||
|
||||
# Import Pythosn libs
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import salt libs
|
||||
|
@ -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:
|
||||
|
@ -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']}
|
||||
|
||||
|
@ -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
196
salt/grains/smartos.py
Normal 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
113
salt/grains/zfs.py
Normal 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
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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')
|
||||
|
@ -1,4 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Module to work with salt formula defaults files
|
||||
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import
|
||||
import json
|
||||
import logging
|
||||
|
@ -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])
|
||||
|
@ -413,6 +413,7 @@ def delkey(key):
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' grains.delkey key
|
||||
'''
|
||||
setval(key, None, destructive=True)
|
||||
|
@ -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
|
||||
|
||||
|
@ -112,7 +112,7 @@ def run(script):
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block::
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' jenkins.run 'Jenkins.instance.doSafeRestart()'
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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='
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Namecheap management
|
||||
Namecheap users management
|
||||
|
||||
.. versionadded:: 2017.7.0
|
||||
|
||||
|
@ -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,
|
||||
|
@ -1,4 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Module for OpenSCAP Management
|
||||
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import
|
||||
import tempfile
|
||||
import shlex
|
||||
|
@ -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
|
||||
|
@ -1,8 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
===========================
|
||||
Manage the Windows registry
|
||||
===========================
|
||||
|
||||
-----
|
||||
Hives
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -170,6 +170,7 @@ def exportdb():
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' udev.exportdb
|
||||
'''
|
||||
|
||||
|
@ -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}'
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
225
salt/modules/wordpress.py
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -34,6 +34,7 @@ Configuration
|
||||
be set up as different configuration profiles. For example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
zookeeper:
|
||||
prod:
|
||||
hosts: zoo1,zoo2,zoo3
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 ''
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
'''
|
||||
Store key/value pairs in a CSV file
|
||||
|
||||
.. versionaddedd:: 2016.11.0
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
Example configuration:
|
||||
|
||||
|
@ -16,6 +16,7 @@ Command Line
|
||||
------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-call pillar.get nodegroups
|
||||
local:
|
||||
- class_infra
|
||||
|
@ -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
|
||||
|
155
salt/returners/telegram_return.py
Normal file
155
salt/returners/telegram_return.py
Normal 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)
|
@ -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()
|
||||
|
@ -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='
|
||||
|
@ -85,7 +85,7 @@ def get_opts():
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block::
|
||||
.. code-block:: bash
|
||||
|
||||
salt-run test.get_opts
|
||||
'''
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -65,6 +65,7 @@ def present(name, definition=None):
|
||||
**Example:**
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# Default settings
|
||||
mytestindex:
|
||||
elasticsearch_index.present
|
||||
|
@ -65,6 +65,7 @@ def present(name, definition):
|
||||
**Example:**
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
mytestindex2_template:
|
||||
elasticsearch_index_template.present:
|
||||
- definition:
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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'
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user