mirror of
https://github.com/valitydev/salt.git
synced 2024-11-06 08:35:21 +00:00
Merge branch '2016.11' into 'develop'
Conflicts: - doc/ref/modules/all/salt.modules.napalm_route.rst - doc/ref/modules/all/salt.modules.napalm_snmp.rst - doc/ref/modules/all/salt.modules.napalm_users.rst - doc/ref/states/all/salt.states.netsnmp.rst - doc/ref/states/all/salt.states.netusers.rst - salt/states/cron.py
This commit is contained in:
commit
a2927226ea
@ -127,9 +127,13 @@
|
||||
# the jobs system and is not generally recommended.
|
||||
#job_cache: True
|
||||
|
||||
# Cache minion grains and pillar data in the cachedir.
|
||||
# Cache minion grains, pillar and mine data via the cache subsystem in the
|
||||
# cachedir or a database.
|
||||
#minion_data_cache: True
|
||||
|
||||
# Cache subsystem module to use for minion data cache.
|
||||
#cache: localfs
|
||||
|
||||
# Store all returns in the given returner.
|
||||
# Setting this option requires that any returner-specific configuration also
|
||||
# be set. See various returners in salt/returners for details on required
|
||||
|
10
conf/minion
10
conf/minion
@ -801,8 +801,16 @@
|
||||
|
||||
###### Returner settings ######
|
||||
############################################
|
||||
# Which returner(s) will be used for minion's result:
|
||||
# Default Minion returners. Can be a comma delimited string or a list:
|
||||
#
|
||||
#return: mysql
|
||||
#
|
||||
#return: mysql,slack,redis
|
||||
#
|
||||
#return:
|
||||
# - mysql
|
||||
# - hipchat
|
||||
# - slack
|
||||
|
||||
|
||||
###### Miscellaneous settings ######
|
||||
|
@ -49,6 +49,13 @@ class Mock(object):
|
||||
else:
|
||||
data = Mock(mapping=self.__mapping)
|
||||
return data
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
raise StopIteration
|
||||
|
||||
# pylint: enable=R0903
|
||||
|
||||
MOCK_MODULES = [
|
||||
|
@ -459,14 +459,28 @@ jobs dir.
|
||||
Default: ``True``
|
||||
|
||||
The minion data cache is a cache of information about the minions stored on the
|
||||
master, this information is primarily the pillar and grains data. The data is
|
||||
cached in the Master cachedir under the name of the minion and used to
|
||||
predetermine what minions are expected to reply from executions.
|
||||
master, this information is primarily the pillar, grains and mine data. The data
|
||||
is cached via the cache subsystem in the Master cachedir under the name of the
|
||||
minion or in a supported database. The data is used to predetermine what minions
|
||||
are expected to reply from executions.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
minion_data_cache: True
|
||||
|
||||
.. conf_master:: cache
|
||||
|
||||
``cache``
|
||||
---------------------
|
||||
|
||||
Default: ``localfs``
|
||||
|
||||
Cache subsystem module to use for minion data cache.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
cache: consul
|
||||
|
||||
.. conf_master:: ext_job_cache
|
||||
|
||||
``ext_job_cache``
|
||||
@ -2402,7 +2416,7 @@ exposed.
|
||||
- 'mail\d+.mydomain.tld'
|
||||
|
||||
|
||||
.. _pillar-configuration:
|
||||
.. _pillar-configuration-master:
|
||||
|
||||
Pillar Configuration
|
||||
====================
|
||||
|
@ -456,26 +456,6 @@ executed. By default this feature is disabled, to enable set cache_jobs to
|
||||
|
||||
cache_jobs: False
|
||||
|
||||
.. conf_minion:: minion_pillar_cache
|
||||
|
||||
``minion_pillar_cache``
|
||||
-----------------------
|
||||
|
||||
Default: ``False``
|
||||
|
||||
The minion can locally cache rendered pillar data under
|
||||
:conf_minion:`cachedir`/pillar. This allows a temporarily disconnected minion
|
||||
to access previously cached pillar data by invoking salt-call with the --local
|
||||
and --pillar_root=:conf_minion:`cachedir`/pillar options. Before enabling this
|
||||
setting consider that the rendered pillar may contain security sensitive data.
|
||||
Appropriate access restrictions should be in place. By default the saved pillar
|
||||
data will be readable only by the user account running salt. By default this
|
||||
feature is disabled, to enable set minion_pillar_cache to ``True``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
minion_pillar_cache: False
|
||||
|
||||
.. conf_minion:: grains
|
||||
|
||||
``grains``
|
||||
@ -1557,8 +1537,10 @@ sha512 are also supported.
|
||||
hash_type: sha256
|
||||
|
||||
|
||||
Pillar Settings
|
||||
===============
|
||||
.. _pillar-configuration-minion:
|
||||
|
||||
Pillar Configuration
|
||||
====================
|
||||
|
||||
.. conf_minion:: pillar_roots
|
||||
|
||||
@ -1629,6 +1611,28 @@ Set this option to ``True`` to force a ``KeyError`` to be raised whenever an
|
||||
attempt to retrieve a named value from pillar fails. When this option is set
|
||||
to ``False``, the failed attempt returns an empty string.
|
||||
|
||||
.. conf_minion:: minion_pillar_cache
|
||||
|
||||
``minion_pillar_cache``
|
||||
-----------------------
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
Default: ``False``
|
||||
|
||||
The minion can locally cache rendered pillar data under
|
||||
:conf_minion:`cachedir`/pillar. This allows a temporarily disconnected minion
|
||||
to access previously cached pillar data by invoking salt-call with the --local
|
||||
and --pillar_root=:conf_minion:`cachedir`/pillar options. Before enabling this
|
||||
setting consider that the rendered pillar may contain security sensitive data.
|
||||
Appropriate access restrictions should be in place. By default the saved pillar
|
||||
data will be readable only by the user account running salt. By default this
|
||||
feature is disabled, to enable set minion_pillar_cache to ``True``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
minion_pillar_cache: False
|
||||
|
||||
.. conf_minion:: file_recv_max_size
|
||||
|
||||
``file_recv_max_size``
|
||||
|
@ -347,6 +347,7 @@ execution modules
|
||||
ssh
|
||||
ssh_package
|
||||
ssh_service
|
||||
snapper
|
||||
state
|
||||
status
|
||||
stormpath
|
||||
|
@ -1,7 +1,7 @@
|
||||
================================
|
||||
salt.modules.napalm_route module
|
||||
================================
|
||||
|
||||
.. automodule:: salt.modules.napalm_route
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
===============================
|
||||
salt.modules.napalm_snmp module
|
||||
===============================
|
||||
|
||||
.. automodule:: salt.modules.napalm_snmp
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
================================
|
||||
salt.modules.napalm_users module
|
||||
================================
|
||||
|
||||
.. automodule:: salt.modules.napalm_users
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
6
doc/ref/modules/all/salt.modules.snapper.rst
Normal file
6
doc/ref/modules/all/salt.modules.snapper.rst
Normal file
@ -0,0 +1,6 @@
|
||||
salt.modules.snapper module
|
||||
===========================
|
||||
|
||||
.. automodule:: salt.modules.snapper
|
||||
:members:
|
||||
:undoc-members:
|
@ -8,8 +8,14 @@ Pillars
|
||||
Salt includes a number of built-in external pillars, listed at
|
||||
:ref:`all-salt.pillars`.
|
||||
|
||||
You may also wish to look at the standard pillar documentation, at
|
||||
:ref:`pillar-configuration`
|
||||
The below links contain documentation for the configuration options
|
||||
|
||||
- :ref:`master-side configuration <pillar-configuration-master>`
|
||||
- :ref:`minion-side configuration <pillar-configuration-minion>`
|
||||
|
||||
Note that some of same the configuration options from the master are present in
|
||||
the minion configuration file, these are used in :ref:`masterless
|
||||
<tutorial-standalone-minion>` mode.
|
||||
|
||||
The source for the built-in Salt pillars can be found here:
|
||||
:blob:`salt/pillar`
|
||||
:blob:`salt/pillar`
|
||||
|
@ -205,6 +205,7 @@ state modules
|
||||
slack
|
||||
smartos
|
||||
smtp
|
||||
snapper
|
||||
splunk
|
||||
splunk_search
|
||||
sqlite3
|
||||
|
@ -4,4 +4,5 @@ salt.states.netsnmp
|
||||
|
||||
.. automodule:: salt.states.netsnmp
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
@ -4,4 +4,5 @@ salt.states.netusers
|
||||
|
||||
.. automodule:: salt.states.netusers
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
@ -12,24 +12,25 @@ Pillar was added to Salt in version 0.9.8
|
||||
|
||||
.. note:: Storing sensitive data
|
||||
|
||||
Unlike state tree, pillar data is only available for the targeted
|
||||
minion specified by the matcher type. This makes it useful for
|
||||
storing sensitive data specific to a particular minion.
|
||||
Pillar data is compiled on the master. Additionally, pillar data for a
|
||||
given minion is only accessible by the minion for which it is targeted in
|
||||
the pillar configuration. This makes pillar useful for storing sensitive
|
||||
data specific to a particular minion.
|
||||
|
||||
|
||||
Declaring the Master Pillar
|
||||
===========================
|
||||
|
||||
The Salt Master server maintains a pillar_roots setup that matches the
|
||||
structure of the file_roots used in the Salt file server. Like the
|
||||
Salt file server the ``pillar_roots`` option in the master config is based
|
||||
on environments mapping to directories. The pillar data is then mapped to
|
||||
minions based on matchers in a top file which is laid out in the same way
|
||||
as the state top file. Salt pillars can use the same matcher types as the
|
||||
standard top file.
|
||||
The Salt Master server maintains a :conf_master:`pillar_roots` setup that
|
||||
matches the structure of the :conf_master:`file_roots` used in the Salt file
|
||||
server. Like :conf_master:`file_roots`, the :conf_master:`pillar_roots` option
|
||||
mapps environments to directories. The pillar data is then mapped to minions
|
||||
based on matchers in a top file which is laid out in the same way as the state
|
||||
top file. Salt pillars can use the same matcher types as the standard :ref:`top
|
||||
file <states-top>`.
|
||||
|
||||
The configuration for the :conf_master:`pillar_roots` in the master config file
|
||||
is identical in behavior and function as :conf_master:`file_roots`:
|
||||
conf_master:`pillar_roots` is configured just like :conf_master:`file_roots`.
|
||||
For example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
@ -149,10 +150,15 @@ And the actual pillar file at '/srv/pillar/common_pillar.sls':
|
||||
foo: bar
|
||||
boo: baz
|
||||
|
||||
Pillar namespace flattened
|
||||
==========================
|
||||
Pillar Namespace Flattening
|
||||
===========================
|
||||
|
||||
The separate pillar files all share the same namespace. Given a ``top.sls`` of:
|
||||
The separate pillar SLS files all merge down into a single dictionary of
|
||||
key-value pairs. When the same key is defined in multiple SLS files, this can
|
||||
result in unexpected behavior if care is not taken to how the pillar SLS files
|
||||
are laid out.
|
||||
|
||||
For example, given a ``top.sls`` containing the following:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
@ -161,44 +167,49 @@ The separate pillar files all share the same namespace. Given a ``top.sls`` of:
|
||||
- packages
|
||||
- services
|
||||
|
||||
a ``packages.sls`` file of:
|
||||
with ``packages.sls`` containing:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
bind: bind9
|
||||
|
||||
and a ``services.sls`` file of:
|
||||
and ``services.sls`` containing:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
bind: named
|
||||
|
||||
Then a request for the ``bind`` pillar will only return ``named``; the
|
||||
``bind9`` value is not available. It is better to structure your pillar files
|
||||
with more hierarchy. For example your ``package.sls`` file could look like:
|
||||
Then a request for the ``bind`` pillar key will only return ``named``. The
|
||||
``bind9`` value will be lost, because ``services.sls`` was evaluated later.
|
||||
|
||||
.. note::
|
||||
Pillar files are applied in the order they are listed in the top file.
|
||||
Therefore conflicting keys will be overwritten in a 'last one wins' manner!
|
||||
For example, in the above scenario conflicting key values in ``services``
|
||||
will overwrite those in ``packages`` because it's at the bottom of the list.
|
||||
|
||||
It can be better to structure your pillar files with more hierarchy. For
|
||||
example the ``package.sls`` file could be configured like so:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
packages:
|
||||
bind: bind9
|
||||
|
||||
Pillar Namespace Merges
|
||||
=======================
|
||||
This would make the ``packages`` pillar key a nested dictionary containing a
|
||||
``bind`` key.
|
||||
|
||||
With some care, the pillar namespace can merge content from multiple pillar
|
||||
files under a single key, so long as conflicts are avoided as described above.
|
||||
Pillar Dictionary Merging
|
||||
=========================
|
||||
|
||||
For example, if the above example were modified as follows, the values are
|
||||
merged below a single key:
|
||||
If the same pillar key is defined in multiple pillar SLS files, and the keys in
|
||||
both files refer to nested dictionaries, then the content from these
|
||||
dictionaries will be recursively merged.
|
||||
|
||||
.. code-block:: yaml
|
||||
For example, keeping the ``top.sls`` the same, assume the following
|
||||
modifications to the pillar SLS files:
|
||||
|
||||
base:
|
||||
'*':
|
||||
- packages
|
||||
- services
|
||||
|
||||
And a ``packages.sls`` file like:
|
||||
``packages.sls``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
@ -206,7 +217,7 @@ And a ``packages.sls`` file like:
|
||||
package-name: bind9
|
||||
version: 9.9.5
|
||||
|
||||
And a ``services.sls`` file like:
|
||||
``services.sls``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
@ -214,7 +225,7 @@ And a ``services.sls`` file like:
|
||||
port: 53
|
||||
listen-on: any
|
||||
|
||||
The resulting pillar will be as follows:
|
||||
The resulting pillar dictionary will be:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@ -230,11 +241,9 @@ The resulting pillar will be as follows:
|
||||
version:
|
||||
9.9.5
|
||||
|
||||
.. note::
|
||||
Pillar files are applied in the order they are listed in the top file.
|
||||
Therefore conflicting keys will be overwritten in a 'last one wins' manner!
|
||||
For example, in the above scenario conflicting key values in ``services``
|
||||
will overwrite those in ``packages`` because it's at the bottom of the list.
|
||||
Since both pillar SLS files contained a ``bind`` key which contained a nested
|
||||
dictionary, the pillar dictionary's ``bind`` key contains the combined contents
|
||||
of both SLS files' ``bind`` keys.
|
||||
|
||||
Including Other Pillars
|
||||
=======================
|
||||
@ -266,34 +275,118 @@ With this form, the included file (users.sls) will be nested within the 'users'
|
||||
key of the compiled pillar. Additionally, the 'sudo' value will be available
|
||||
as a template variable to users.sls.
|
||||
|
||||
.. _pillar-in-memory:
|
||||
|
||||
Viewing Minion Pillar
|
||||
=====================
|
||||
In-Memory Pillar Data vs. On-Demand Pillar Data
|
||||
===============================================
|
||||
|
||||
Once the pillar is set up the data can be viewed on the minion via the
|
||||
``pillar`` module, the pillar module comes with functions,
|
||||
:mod:`pillar.items <salt.modules.pillar.items>` and :mod:`pillar.raw
|
||||
<salt.modules.pillar.raw>`. :mod:`pillar.items <salt.modules.pillar.items>`
|
||||
will return a freshly reloaded pillar and :mod:`pillar.raw
|
||||
<salt.modules.pillar.raw>` will return the current pillar without a refresh:
|
||||
Since compiling pillar data is computationally expensive, the minion will
|
||||
maintain a copy of the pillar data in memory to avoid needing to ask the master
|
||||
to recompile and send it a copy of the pillar data each time pillar data is
|
||||
requested. This in-memory pillar data is what is returned by the
|
||||
:py:func:`pillar.item <salt.modules.pillar.item>`, :py:func:`pillar.get
|
||||
<salt.modules.pillar.get>`, and :py:func:`pillar.raw <salt.modules.pillar.raw>`
|
||||
functions.
|
||||
|
||||
Also, for those writing custom execution modules, or contributing to Salt's
|
||||
existing execution modules, the in-memory pillar data is available as the
|
||||
``__pillar__`` dunder dictionary.
|
||||
|
||||
The in-memory pillar data is generated on minion start, and can be refreshed
|
||||
using the :py:func:`saltutil.refresh_pillar
|
||||
<salt.modules.saltutil.refresh_pillar>` function:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' pillar.items
|
||||
salt '*' saltutil.refresh_pillar
|
||||
|
||||
This function triggers the minion to asynchronously refresh the in-memory
|
||||
pillar data and will always return ``None``.
|
||||
|
||||
In contrast to in-memory pillar data, certain actions trigger pillar data to be
|
||||
compiled to ensure that the most up-to-date pillar data is available. These
|
||||
actions include:
|
||||
|
||||
- Running states
|
||||
- Running :py:func:`pillar.items <salt.modules.pillar.items>`
|
||||
|
||||
Performing these actions will *not* refresh the in-memory pillar data. So, if
|
||||
pillar data is modified, and then states are run, the states will see the
|
||||
updated pillar data, but :py:func:`pillar.item <salt.modules.pillar.item>`,
|
||||
:py:func:`pillar.get <salt.modules.pillar.get>`, and :py:func:`pillar.raw
|
||||
<salt.modules.pillar.raw>` will not see this data unless refreshed using
|
||||
:py:func:`saltutil.refresh_pillar <salt.modules.saltutil.refresh_pillar>`.
|
||||
|
||||
|
||||
How Pillar Environments Are Handled
|
||||
===================================
|
||||
|
||||
When multiple pillar environments are used, the default behavior is for the
|
||||
pillar data from all environments to be merged together. The pillar dictionary
|
||||
will therefore contain keys from all configured environments.
|
||||
|
||||
The :conf_minion:`pillarenv` minion config option can be used to force the
|
||||
minion to only consider pillar configuration from a single environment. This
|
||||
can be useful in cases where one needs to run states with alternate pillar
|
||||
data, either in a testing/QA environment or to test changes to the pillar data
|
||||
before pushing them live.
|
||||
|
||||
For example, assume that the following is set in the minion config file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
pillarenv: base
|
||||
|
||||
This would cause that minion to ignore all other pillar environments besides
|
||||
``base`` when compiling the in-memory pillar data. Then, when running states,
|
||||
the ``pillarenv`` CLI argument can be used to override the minion's
|
||||
:conf_minion:`pillarenv` config value:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' state.apply mystates pillarenv=testing
|
||||
|
||||
The above command will run the states with pillar data sourced exclusively from
|
||||
the ``testing`` environment, without modifying the in-memory pillar data.
|
||||
|
||||
.. note::
|
||||
Prior to version 0.16.2, this function is named ``pillar.data``. This
|
||||
function name is still supported for backwards compatibility.
|
||||
When running states, the ``pillarenv`` CLI option does not require a
|
||||
:conf_minion:`pillarenv` option to be set in the minion config file. When
|
||||
:conf_minion:`pillarenv` is left unset, as mentioned above all configured
|
||||
environments will be combined. Running states with ``pillarenv=testing`` in
|
||||
this case would still restrict the states' pillar data to just that of the
|
||||
``testing`` pillar environment.
|
||||
|
||||
Viewing Pillar Data
|
||||
===================
|
||||
|
||||
To view pillar data, use the :mod:`pillar <salt.modules.pillar>` execution
|
||||
module. This module includes several functions, each of them with their own
|
||||
use. These functions include:
|
||||
|
||||
- :py:func:`pillar.item <salt.modules.pillar.item>` - Retrieves the value of
|
||||
one or more keys from the :ref:`in-memory pillar datj <pillar-in-memory>`.
|
||||
- :py:func:`pillar.items <salt.modules.pillar.items>` - Compiles a fresh pillar
|
||||
dictionary and returns it, leaving the :ref:`in-memory pillar data
|
||||
<pillar-in-memory>` untouched. If pillar keys are passed to this function
|
||||
however, this function acts like :py:func:`pillar.item
|
||||
<salt.modules.pillar.item>` and returns their values from the :ref:`in-memory
|
||||
pillar data <pillar-in-memory>`.
|
||||
- :py:func:`pillar.raw <salt.modules.pillar.raw>` - Like :py:func:`pillar.items
|
||||
<salt.modules.pillar.items>`, it returns the entire pillar dictionary, but
|
||||
from the :ref:`in-memory pillar data <pillar-in-memory>` instead of compiling
|
||||
fresh pillar data.
|
||||
- :py:func:`pillar.get <salt.modules.pillar.get>` - Described in detail below.
|
||||
|
||||
|
||||
Pillar "get" Function
|
||||
=====================
|
||||
The :py:func:`pillar.get <salt.modules.pillar.get>` Function
|
||||
============================================================
|
||||
|
||||
.. versionadded:: 0.14.0
|
||||
|
||||
The :mod:`pillar.get <salt.modules.pillar.get>` function works much in the same
|
||||
way as the ``get`` method in a python dict, but with an enhancement: nested
|
||||
dict components can be extracted using a `:` delimiter.
|
||||
dictonaries can be traversed using a colon as a delimiter.
|
||||
|
||||
If a structure like this is in pillar:
|
||||
|
||||
@ -330,23 +423,8 @@ This makes handling nested structures much easier.
|
||||
'qux')``) to get the salt function, instead of the default dictionary
|
||||
behavior.
|
||||
|
||||
|
||||
Refreshing Pillar Data
|
||||
======================
|
||||
|
||||
When pillar data is changed on the master the minions need to refresh the data
|
||||
locally. This is done with the ``saltutil.refresh_pillar`` function.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' saltutil.refresh_pillar
|
||||
|
||||
This function triggers the minion to asynchronously refresh the pillar and will
|
||||
always return ``None``.
|
||||
|
||||
|
||||
Set Pillar Data at the Command Line
|
||||
===================================
|
||||
Setting Pillar Data at the Command Line
|
||||
=======================================
|
||||
|
||||
Pillar data can be set at the command line like the following example:
|
||||
|
||||
@ -354,7 +432,7 @@ Pillar data can be set at the command line like the following example:
|
||||
|
||||
salt '*' state.apply pillar='{"cheese": "spam"}'
|
||||
|
||||
This will add a Pillar key of ``cheese`` with its value set to ``spam``.
|
||||
This will add a pillar key of ``cheese`` with its value set to ``spam``.
|
||||
|
||||
.. note::
|
||||
|
||||
@ -364,7 +442,7 @@ This will add a Pillar key of ``cheese`` with its value set to ``spam``.
|
||||
a security concern in some cases.
|
||||
|
||||
|
||||
Master Config In Pillar
|
||||
Master Config in Pillar
|
||||
=======================
|
||||
|
||||
For convenience the data stored in the master configuration file can be made
|
||||
@ -372,14 +450,13 @@ available in all minion's pillars. This makes global configuration of services
|
||||
and systems very easy but may not be desired if sensitive data is stored in the
|
||||
master configuration. This option is disabled by default.
|
||||
|
||||
To enable the master config from being added to the pillar set ``pillar_opts``
|
||||
to ``True``:
|
||||
To enable the master config from being added to the pillar set
|
||||
:conf_minion:`pillar_opts` to ``True`` in the minion config file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
pillar_opts: True
|
||||
|
||||
|
||||
Minion Config in Pillar
|
||||
=======================
|
||||
|
||||
|
@ -139,7 +139,7 @@ case "$1" in
|
||||
RETVAL=$?
|
||||
fi
|
||||
;;
|
||||
condrestart)
|
||||
condrestart|try-restart)
|
||||
[ -f $LOCKFILE ] && restart || :
|
||||
;;
|
||||
reload)
|
||||
@ -147,7 +147,7 @@ case "$1" in
|
||||
RETVAL=1
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
@ -122,7 +122,7 @@ case "$1" in
|
||||
RETVAL=$?
|
||||
fi
|
||||
;;
|
||||
condrestart)
|
||||
condrestart|try-restart)
|
||||
[ -f $LOCKFILE ] && restart || :
|
||||
;;
|
||||
reload)
|
||||
@ -130,7 +130,7 @@ case "$1" in
|
||||
RETVAL=1
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
@ -129,7 +129,7 @@ case "$1" in
|
||||
RETVAL=$?
|
||||
fi
|
||||
;;
|
||||
condrestart)
|
||||
condrestart|try-restart)
|
||||
[ -f $LOCKFILE ] && restart || :
|
||||
;;
|
||||
reload)
|
||||
@ -137,7 +137,7 @@ case "$1" in
|
||||
RETVAL=1
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
@ -123,7 +123,7 @@ case "$1" in
|
||||
RETVAL=$?
|
||||
fi
|
||||
;;
|
||||
condrestart)
|
||||
condrestart|try-restart)
|
||||
[ -f $LOCKFILE ] && restart || :
|
||||
;;
|
||||
reload)
|
||||
@ -131,7 +131,7 @@ case "$1" in
|
||||
RETVAL=$?
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
2
salt/cache/__init__.py
vendored
2
salt/cache/__init__.py
vendored
@ -22,7 +22,7 @@ class Cache(object):
|
||||
|
||||
:param cache:
|
||||
The name of the cache driver to use. This is the name of the python
|
||||
module of the `salt.cache` package. Defult is `localfs`.
|
||||
module of the `salt.cache` package. Default is `localfs`.
|
||||
|
||||
:param serial:
|
||||
The module of `salt.serializers` package that should be used by the cache
|
||||
|
172
salt/cache/consul.py
vendored
Normal file
172
salt/cache/consul.py
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Minion data cache plugin for Consul key/value data store.
|
||||
|
||||
It is up to the system administrator to set up and configure the Consul
|
||||
infrastructure. All is needed for this plugin is a working Consul agent
|
||||
with a read-write access to the key-value storae.
|
||||
|
||||
The related documentation can be found here: https://www.consul.io/docs/index.html
|
||||
|
||||
To enable this cache plugin the master will need the python client for
|
||||
Consul installed that could be easily done with `pip install python-consul`.
|
||||
|
||||
Optionally depending on the Consul agent configuration the following values
|
||||
could be set in the master config, these are the defaults:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
consul.host: 127.0.0.1
|
||||
consul.port: 8500
|
||||
consul.token: None
|
||||
consul.scheme: http
|
||||
consul.consistency: default
|
||||
consul.dc: None
|
||||
consul.verify: True
|
||||
|
||||
Related docs could be found here:
|
||||
* python-consul: https://python-consul.readthedocs.io/en/latest/#consul
|
||||
|
||||
To use the consul as a minion data cache backend set the master `cache` config
|
||||
value to `consul`:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
cache: consul
|
||||
|
||||
.. versionadded:: 2016.11.2
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
try:
|
||||
import consul
|
||||
HAS_CONSUL = True
|
||||
except ImportError:
|
||||
HAS_CONSUL = False
|
||||
|
||||
from salt.exceptions import SaltCacheError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
api = None
|
||||
|
||||
|
||||
# Define the module's virtual name
|
||||
__virtualname__ = 'consul'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Confirm this python-consul package is installed
|
||||
'''
|
||||
if not HAS_CONSUL:
|
||||
return (False, "Please install python-consul package to use consul data cache driver")
|
||||
|
||||
consul_kwargs = {
|
||||
'host': __opts__.get('consul.host', '127.0.0.1'),
|
||||
'port': __opts__.get('consul.port', 8500),
|
||||
'token': __opts__.get('consul.token', None),
|
||||
'scheme': __opts__.get('consul.scheme', 'http'),
|
||||
'consistency': __opts__.get('consul.consistency', 'default'),
|
||||
'dc': __opts__.get('consul.dc', None),
|
||||
'verify': __opts__.get('consul.verify', True),
|
||||
}
|
||||
|
||||
global api
|
||||
api = consul.Consul(**consul_kwargs)
|
||||
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def store(bank, key, data):
|
||||
'''
|
||||
Store a key value.
|
||||
'''
|
||||
c_key = '{0}/{1}'.format(bank, key)
|
||||
try:
|
||||
c_data = __context__['serial'].dumps(data)
|
||||
api.kv.put(c_key, c_data)
|
||||
except Exception as exc:
|
||||
raise SaltCacheError(
|
||||
'There was an error writing the key, {0}: {1}'.format(
|
||||
c_key, exc
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def fetch(bank, key):
|
||||
'''
|
||||
Fetch a key value.
|
||||
'''
|
||||
c_key = '{0}/{1}'.format(bank, key)
|
||||
try:
|
||||
_, value = api.kv.get(c_key)
|
||||
if value is None:
|
||||
return value
|
||||
return __context__['serial'].loads(value['Value'])
|
||||
except Exception as exc:
|
||||
raise SaltCacheError(
|
||||
'There was an error reading the key, {0}: {1}'.format(
|
||||
c_key, exc
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def flush(bank, key=None):
|
||||
'''
|
||||
Remove the key from the cache bank with all the key content.
|
||||
'''
|
||||
if key is None:
|
||||
c_key = bank
|
||||
else:
|
||||
c_key = '{0}/{1}'.format(bank, key)
|
||||
try:
|
||||
return api.kv.delete(c_key, recurse=key is None)
|
||||
except Exception as exc:
|
||||
raise SaltCacheError(
|
||||
'There was an error removing the key, {0}: {1}'.format(
|
||||
c_key, exc
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def list(bank):
|
||||
'''
|
||||
Return an iterable object containing all entries stored in the specified bank.
|
||||
'''
|
||||
try:
|
||||
_, keys = api.kv.get(bank + '/', keys=True, separator='/')
|
||||
except Exception as exc:
|
||||
raise SaltCacheError(
|
||||
'There was an error getting the key "{0}": {1}'.format(
|
||||
bank, exc
|
||||
)
|
||||
)
|
||||
if keys is None:
|
||||
keys = []
|
||||
else:
|
||||
# Any key could be a branch and a leaf at the same time in Consul
|
||||
# so we have to return a list of unique names only.
|
||||
out = set()
|
||||
for key in keys:
|
||||
out.add(key[len(bank) + 1:].rstrip('/'))
|
||||
keys = list(out)
|
||||
return keys
|
||||
|
||||
|
||||
def contains(bank, key):
|
||||
'''
|
||||
Checks if the specified bank contains the specified key.
|
||||
'''
|
||||
if key is None:
|
||||
return True # any key could be a branch and a leaf at the same time in Consul
|
||||
else:
|
||||
try:
|
||||
c_key = '{0}/{1}'.format(bank, key)
|
||||
_, value = api.kv.get(c_key)
|
||||
except Exception as exc:
|
||||
raise SaltCacheError(
|
||||
'There was an error getting the key, {0}: {1}'.format(
|
||||
c_key, exc
|
||||
)
|
||||
)
|
||||
return value is not None
|
@ -943,6 +943,9 @@ VALID_OPTS = {
|
||||
'thin_extra_mods': str,
|
||||
'min_extra_mods': str,
|
||||
|
||||
# Default returners minion should use. List or comma-delimited string
|
||||
'return': (str, list),
|
||||
|
||||
# TLS/SSL connection options. This could be set to a dictionary containing arguments
|
||||
# corresponding to python ssl.wrap_socket method. For details see:
|
||||
# http://www.tornadoweb.org/en/stable/tcpserver.html#tornado.tcpserver.TCPServer
|
||||
@ -1697,6 +1700,10 @@ def _validate_opts(opts):
|
||||
format_multi_opt(VALID_OPTS[key]))
|
||||
)
|
||||
|
||||
# Convert list to comma-delimited string for 'return' config option
|
||||
if isinstance(opts.get('return'), list):
|
||||
opts['return'] = ','.join(opts['return'])
|
||||
|
||||
# RAET on Windows uses 'win32file.CreateMailslot()' for IPC. Due to this,
|
||||
# sock_dirs must start with '\\.\mailslot\' and not contain any colons.
|
||||
# We don't expect the user to know this, so we will fix up their path for
|
||||
|
@ -1567,6 +1567,15 @@ class Minion(MinionBase):
|
||||
ret,
|
||||
timeout=minion_instance._return_retry_timer()
|
||||
)
|
||||
|
||||
# Add default returners from minion config
|
||||
# Should have been coverted to comma-delimited string already
|
||||
if isinstance(opts.get('return'), six.string_types):
|
||||
if data['ret']:
|
||||
data['ret'] = ','.join((data['ret'], opts['return']))
|
||||
else:
|
||||
data['ret'] = opts['return']
|
||||
|
||||
# TODO: make a list? Seems odd to split it this late :/
|
||||
if data['ret'] and isinstance(data['ret'], six.string_types):
|
||||
if 'ret_config' in data:
|
||||
|
@ -244,18 +244,35 @@ def item(*args, **kwargs):
|
||||
Return one or more pillar entries
|
||||
|
||||
pillar
|
||||
if specified, allows for a dictionary of pillar data to be made
|
||||
If specified, allows for a dictionary of pillar data to be made
|
||||
available to pillar and ext_pillar rendering. these pillar variables
|
||||
will also override any variables of the same name in pillar or
|
||||
ext_pillar.
|
||||
|
||||
.. versionadded:: 2015.5.0
|
||||
|
||||
delimiter
|
||||
Delimiter used to traverse nested dictionaries.
|
||||
|
||||
.. note::
|
||||
This is different from :py:func:`pillar.get
|
||||
<salt.modules.pillar.get>` in that no default value can be
|
||||
specified. :py:func:`pillar.get <salt.modules.pillar.get>` should
|
||||
probably still be used in most cases to retrieve nested pillar
|
||||
values, as it is a bit more flexible. One reason to use this
|
||||
function instead of :py:func:`pillar.get <salt.modules.pillar.get>`
|
||||
however is when it is desirable to retrieve the values of more than
|
||||
one key, since :py:func:`pillar.get <salt.modules.pillar.get>` can
|
||||
only retrieve one key at a time.
|
||||
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
CLI Examples:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' pillar.item foo
|
||||
salt '*' pillar.item foo:bar
|
||||
salt '*' pillar.item foo bar baz
|
||||
'''
|
||||
ret = {}
|
||||
|
@ -970,15 +970,40 @@ def freeze(bin_env=None,
|
||||
cwd
|
||||
Current working directory to run pip from
|
||||
|
||||
.. note::
|
||||
|
||||
If the version of pip available is older than 8.0.3, the list will not
|
||||
include the packages pip, wheel, setuptools, or distribute even if they
|
||||
are installed.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' pip.freeze /home/code/path/to/virtualenv/
|
||||
|
||||
.. versionchanged:: 2016.11.2
|
||||
|
||||
The packages pip, wheel, setuptools, and distribute are included if the
|
||||
installed pip is new enough.
|
||||
'''
|
||||
pip_bin = _get_pip_bin(bin_env)
|
||||
|
||||
cmd = [pip_bin, 'freeze']
|
||||
|
||||
# Include pip, setuptools, distribute, wheel
|
||||
min_version = '8.0.3'
|
||||
cur_version = version(bin_env)
|
||||
if not salt.utils.compare_versions(ver1=cur_version, oper='>=',
|
||||
ver2=min_version):
|
||||
logger.warning(
|
||||
('The version of pip installed is {0}, which is older than {1}. '
|
||||
'The packages pip, wheel, setuptools, and distribute will not be '
|
||||
'included in the output of pip.freeze').format(cur_version,
|
||||
min_version))
|
||||
else:
|
||||
cmd.append('--all')
|
||||
|
||||
cmd_kwargs = dict(runas=user, cwd=cwd, use_vt=use_vt, python_shell=False)
|
||||
if bin_env and os.path.isdir(bin_env):
|
||||
cmd_kwargs['env'] = {'VIRTUAL_ENV': bin_env}
|
||||
@ -998,30 +1023,31 @@ def list_(prefix=None,
|
||||
Filter list of installed apps from ``freeze`` and check to see if
|
||||
``prefix`` exists in the list of packages installed.
|
||||
|
||||
.. note::
|
||||
|
||||
If the version of pip available is older than 8.0.3, the packages
|
||||
wheel, setuptools, and distribute will not be reported by this function
|
||||
even if they are installed. Unlike
|
||||
:py:func:`pip.freeze <salt.modules.pip.freeze>`, this function always
|
||||
reports the version of pip which is installed.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' pip.list salt
|
||||
|
||||
.. versionchanged:: 2016.11.2
|
||||
|
||||
The packages wheel, setuptools, and distribute are included if the
|
||||
installed pip is new enough.
|
||||
'''
|
||||
packages = {}
|
||||
|
||||
pip_bin = _get_pip_bin(bin_env)
|
||||
|
||||
cmd = [pip_bin, 'freeze']
|
||||
|
||||
cmd_kwargs = dict(runas=user, cwd=cwd, python_shell=False)
|
||||
if bin_env and os.path.isdir(bin_env):
|
||||
cmd_kwargs['env'] = {'VIRTUAL_ENV': bin_env}
|
||||
|
||||
if not prefix or prefix in ('p', 'pi', 'pip'):
|
||||
if prefix is None or 'pip'.startswith(prefix):
|
||||
packages['pip'] = version(bin_env)
|
||||
|
||||
result = __salt__['cmd.run_all'](cmd, **cmd_kwargs)
|
||||
if result['retcode'] > 0:
|
||||
raise CommandExecutionError(result['stderr'])
|
||||
|
||||
for line in result['stdout'].splitlines():
|
||||
for line in freeze(bin_env=bin_env, user=user, cwd=cwd):
|
||||
if line.startswith('-f') or line.startswith('#'):
|
||||
# ignore -f line as it contains --find-links directory
|
||||
# ignore comment lines
|
||||
@ -1044,6 +1070,7 @@ def list_(prefix=None,
|
||||
packages[name] = version_
|
||||
else:
|
||||
packages[name] = version_
|
||||
|
||||
return packages
|
||||
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
'''
|
||||
Module to manage filesystem snapshots with snapper
|
||||
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
:codeauthor: Duncan Mac-Vicar P. <dmacvicar@suse.de>
|
||||
:codeauthor: Pablo Suárez Hernández <psuarezhernandez@suse.de>
|
||||
|
||||
|
@ -122,7 +122,7 @@ The corresponding Pillar top file would look like this:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
{{env}}:
|
||||
{{saltenv}}:
|
||||
'*':
|
||||
- bar
|
||||
|
||||
@ -139,6 +139,10 @@ The corresponding Pillar top file would look like this:
|
||||
to :conf_master:`gitfs_base`. This has been fixed in the 2016.3.5 and
|
||||
2016.11.1 releases (2016.11.0 contains the incorrect behavior).
|
||||
|
||||
Additionally, in releases before 2016.11.0, both ``{{env}}`` and
|
||||
``{{saltenv}}`` could be used as a placeholder for the environment.
|
||||
Starting in 2016.11.0, ``{{env}}`` is no longer supported.
|
||||
|
||||
.. _git-pillar-2015-8-0-and-later:
|
||||
|
||||
Configuring git_pillar for Salt releases 2015.8.0 and later
|
||||
@ -232,7 +236,7 @@ The corresponding Pillar top file would look like this:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
{{env}}:
|
||||
{{saltenv}}:
|
||||
'*':
|
||||
- bar
|
||||
|
||||
@ -258,6 +262,10 @@ The corresponding Pillar top file would look like this:
|
||||
(instead of the minion's) before falling back to the master's
|
||||
:conf_master:`git_pillar_base`.
|
||||
|
||||
Additionally, in releases before 2016.11.0, both ``{{env}}`` and
|
||||
``{{saltenv}}`` could be used as a placeholder for the environment.
|
||||
Starting in 2016.11.0, ``{{env}}`` is no longer supported.
|
||||
|
||||
With the addition of pygit2_ support, git_pillar can now interact with
|
||||
authenticated remotes. Authentication works just like in gitfs (as outlined in
|
||||
the :ref:`Git Fileserver Backend Walkthrough <gitfs-authentication>`), only
|
||||
|
@ -40,29 +40,35 @@ Configuring Nodegroups Pillar
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import Salt libs
|
||||
from salt.minion import Matcher
|
||||
from salt.utils.minions import CkMinions
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
|
||||
__version__ = '0.0.1'
|
||||
__version__ = '0.0.2'
|
||||
|
||||
|
||||
def ext_pillar(minion_id, pillar, pillar_name=None):
|
||||
'''
|
||||
A salt external pillar which provides the list of nodegroups of which the minion is a memeber.
|
||||
A salt external pillar which provides the list of nodegroups of which the minion is a member.
|
||||
|
||||
:param minion_id: provided by salt, but not used by nodegroups ext_pillar
|
||||
:param minion_id: used for compound matching nodegroups
|
||||
:param pillar: provided by salt, but not used by nodegroups ext_pillar
|
||||
:param pillar_name: optional name to use for the pillar, defaults to 'nodegroups'
|
||||
:return: a dictionary which is included by the salt master in the pillars returned to the minion
|
||||
'''
|
||||
|
||||
pillar_name = pillar_name or 'nodegroups'
|
||||
m = Matcher(__opts__)
|
||||
all_nodegroups = __opts__['nodegroups']
|
||||
nodegroups_minion_is_in = []
|
||||
ckminions = None
|
||||
for nodegroup_name in six.iterkeys(all_nodegroups):
|
||||
if m.nodegroup_match(nodegroup_name, all_nodegroups):
|
||||
ckminions = ckminions or CkMinions(__opts__)
|
||||
match = ckminions.check_minions(
|
||||
all_nodegroups[nodegroup_name],
|
||||
'compound')
|
||||
|
||||
if minion_id in match:
|
||||
nodegroups_minion_is_in.append(nodegroup_name)
|
||||
|
||||
return {pillar_name: nodegroups_minion_is_in}
|
||||
|
@ -148,8 +148,8 @@ def init(opts):
|
||||
log.error(
|
||||
"Cannot connect to {hostname}{port} as {username}. Please check error: {error}".format(
|
||||
hostname=NETWORK_DEVICE.get('HOSTNAME', ''),
|
||||
port=(':{port}'.format(port=NETWORK_DEVICE['OPTIONAL_ARGS'])
|
||||
if NETWORK_DEVICE['OPTIONAL_ARGS'].get('port') else ''),
|
||||
port=(':{port}'.format(port=NETWORK_DEVICE.get('OPTIONAL_ARGS', {}).get('port'))
|
||||
if NETWORK_DEVICE.get('OPTIONAL_ARGS', {}).get('port') else ''),
|
||||
username=NETWORK_DEVICE.get('USERNAME', ''),
|
||||
error=error
|
||||
)
|
||||
@ -227,8 +227,8 @@ def shutdown(opts):
|
||||
log.error(
|
||||
'Cannot close connection with {hostname}{port}! Please check error: {error}'.format(
|
||||
hostname=NETWORK_DEVICE.get('HOSTNAME', '[unknown hostname]'),
|
||||
port=(':{port}'.format(port=NETWORK_DEVICE['OPTIONAL_ARGS'])
|
||||
if NETWORK_DEVICE['OPTIONAL_ARGS'].get('port') else ''),
|
||||
port=(':{port}'.format(port=NETWORK_DEVICE.get('OPTIONAL_ARGS', {}).get('port'))
|
||||
if NETWORK_DEVICE.get('OPTIONAL_ARGS', {}).get('port') else ''),
|
||||
error=error
|
||||
)
|
||||
)
|
||||
@ -289,8 +289,8 @@ def call(method, **params):
|
||||
err_tb = traceback.format_exc() # let's get the full traceback and display for debugging reasons.
|
||||
comment = 'Cannot execute "{method}" on {device}{port} as {user}. Reason: {error}!'.format(
|
||||
device=NETWORK_DEVICE.get('HOSTNAME', '[unspecified hostname]'),
|
||||
port=(':{port}'.format(port=NETWORK_DEVICE['OPTIONAL_ARGS'])
|
||||
if NETWORK_DEVICE['OPTIONAL_ARGS'].get('port') else ''),
|
||||
port=(':{port}'.format(port=NETWORK_DEVICE.get('OPTIONAL_ARGS', {}).get('port'))
|
||||
if NETWORK_DEVICE.get('OPTIONAL_ARGS', {}).get('port') else ''),
|
||||
user=NETWORK_DEVICE.get('USERNAME', ''),
|
||||
method=method,
|
||||
error=error
|
||||
|
@ -573,6 +573,7 @@ def file(name,
|
||||
template,
|
||||
source,
|
||||
source_hash,
|
||||
source_hash_name,
|
||||
user,
|
||||
group,
|
||||
mode,
|
||||
|
@ -98,7 +98,7 @@ def query(name, match=None, match_type='string', status=None, wait_for=None, **k
|
||||
ret['result'] = False
|
||||
ret['comment'] += ' Match text "{0}" was not found.'.format(match)
|
||||
elif match_type == 'pcre':
|
||||
if re.search(match, data['text']):
|
||||
if re.search(match, data.get('text', '')):
|
||||
ret['result'] = True
|
||||
ret['comment'] += ' Match pattern "{0}" was found.'.format(match)
|
||||
else:
|
||||
|
@ -3,6 +3,8 @@
|
||||
Managing implicit state and baselines using snapshots
|
||||
=====================================================
|
||||
|
||||
.. versionadded:: 2016.11.0
|
||||
|
||||
Salt can manage state against explicitly defined state, for example
|
||||
if your minion state is defined by:
|
||||
|
||||
|
@ -900,23 +900,66 @@ class PipTestCase(TestCase):
|
||||
}
|
||||
)
|
||||
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
|
||||
ret = pip.freeze()
|
||||
mock.assert_called_once_with(
|
||||
['pip', 'freeze'],
|
||||
cwd=None,
|
||||
runas=None,
|
||||
use_vt=False,
|
||||
python_shell=False,
|
||||
)
|
||||
self.assertEqual(ret, eggs)
|
||||
with patch('salt.modules.pip.version',
|
||||
MagicMock(return_value='6.1.1')):
|
||||
ret = pip.freeze()
|
||||
mock.assert_called_once_with(
|
||||
['pip', 'freeze'],
|
||||
cwd=None,
|
||||
runas=None,
|
||||
use_vt=False,
|
||||
python_shell=False,
|
||||
)
|
||||
self.assertEqual(ret, eggs)
|
||||
|
||||
# Non zero returncode raises exception?
|
||||
mock = MagicMock(return_value={'retcode': 1, 'stderr': 'CABOOOOMMM!'})
|
||||
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
|
||||
self.assertRaises(
|
||||
CommandExecutionError,
|
||||
pip.freeze,
|
||||
)
|
||||
with patch('salt.modules.pip.version',
|
||||
MagicMock(return_value='6.1.1')):
|
||||
self.assertRaises(
|
||||
CommandExecutionError,
|
||||
pip.freeze,
|
||||
)
|
||||
|
||||
def test_freeze_command_with_all(self):
|
||||
eggs = [
|
||||
'M2Crypto==0.21.1',
|
||||
'-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev',
|
||||
'bbfreeze==1.1.0',
|
||||
'bbfreeze-loader==1.1.0',
|
||||
'pip==0.9.1',
|
||||
'pycrypto==2.6',
|
||||
'setuptools==20.10.1'
|
||||
]
|
||||
mock = MagicMock(
|
||||
return_value={
|
||||
'retcode': 0,
|
||||
'stdout': '\n'.join(eggs)
|
||||
}
|
||||
)
|
||||
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
|
||||
with patch('salt.modules.pip.version',
|
||||
MagicMock(return_value='9.0.1')):
|
||||
ret = pip.freeze()
|
||||
mock.assert_called_once_with(
|
||||
['pip', 'freeze', '--all'],
|
||||
cwd=None,
|
||||
runas=None,
|
||||
use_vt=False,
|
||||
python_shell=False,
|
||||
)
|
||||
self.assertEqual(ret, eggs)
|
||||
|
||||
# Non zero returncode raises exception?
|
||||
mock = MagicMock(return_value={'retcode': 1, 'stderr': 'CABOOOOMMM!'})
|
||||
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
|
||||
with patch('salt.modules.pip.version',
|
||||
MagicMock(return_value='9.0.1')):
|
||||
self.assertRaises(
|
||||
CommandExecutionError,
|
||||
pip.freeze,
|
||||
)
|
||||
|
||||
def test_list_command(self):
|
||||
eggs = [
|
||||
@ -937,6 +980,7 @@ class PipTestCase(TestCase):
|
||||
cwd=None,
|
||||
runas=None,
|
||||
python_shell=False,
|
||||
use_vt=False,
|
||||
)
|
||||
self.assertEqual(
|
||||
ret, {
|
||||
@ -959,6 +1003,54 @@ class PipTestCase(TestCase):
|
||||
pip.list_,
|
||||
)
|
||||
|
||||
def test_list_command_with_all(self):
|
||||
eggs = [
|
||||
'M2Crypto==0.21.1',
|
||||
'-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev',
|
||||
'bbfreeze==1.1.0',
|
||||
'bbfreeze-loader==1.1.0',
|
||||
'pip==9.0.1',
|
||||
'pycrypto==2.6',
|
||||
'setuptools==20.10.1'
|
||||
]
|
||||
# N.B.: this is deliberately different from the "output" of pip freeze.
|
||||
# This is to demonstrate that the version reported comes from freeze
|
||||
# instead of from the pip.version function.
|
||||
mock_version = '9.0.0'
|
||||
mock = MagicMock(return_value={'retcode': 0, 'stdout': '\n'.join(eggs)})
|
||||
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
|
||||
with patch('salt.modules.pip.version',
|
||||
MagicMock(return_value=mock_version)):
|
||||
ret = pip.list_()
|
||||
mock.assert_called_with(
|
||||
['pip', 'freeze', '--all'],
|
||||
cwd=None,
|
||||
runas=None,
|
||||
python_shell=False,
|
||||
use_vt=False,
|
||||
)
|
||||
self.assertEqual(
|
||||
ret, {
|
||||
'SaltTesting-dev': 'git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8',
|
||||
'M2Crypto': '0.21.1',
|
||||
'bbfreeze-loader': '1.1.0',
|
||||
'bbfreeze': '1.1.0',
|
||||
'pip': '9.0.1',
|
||||
'pycrypto': '2.6',
|
||||
'setuptools': '20.10.1'
|
||||
}
|
||||
)
|
||||
|
||||
# Non zero returncode raises exception?
|
||||
mock = MagicMock(return_value={'retcode': 1, 'stderr': 'CABOOOOMMM!'})
|
||||
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
|
||||
with patch('salt.modules.pip.version',
|
||||
MagicMock(return_value='6.1.1')):
|
||||
self.assertRaises(
|
||||
CommandExecutionError,
|
||||
pip.list_,
|
||||
)
|
||||
|
||||
def test_list_command_with_prefix(self):
|
||||
eggs = [
|
||||
'M2Crypto==0.21.1',
|
||||
@ -974,19 +1066,22 @@ class PipTestCase(TestCase):
|
||||
}
|
||||
)
|
||||
with patch.dict(pip.__salt__, {'cmd.run_all': mock}):
|
||||
ret = pip.list_(prefix='bb')
|
||||
mock.assert_called_with(
|
||||
['pip', 'freeze'],
|
||||
cwd=None,
|
||||
runas=None,
|
||||
python_shell=False,
|
||||
)
|
||||
self.assertEqual(
|
||||
ret, {
|
||||
'bbfreeze-loader': '1.1.0',
|
||||
'bbfreeze': '1.1.0',
|
||||
}
|
||||
)
|
||||
with patch('salt.modules.pip.version',
|
||||
MagicMock(return_value='6.1.1')):
|
||||
ret = pip.list_(prefix='bb')
|
||||
mock.assert_called_with(
|
||||
['pip', 'freeze'],
|
||||
cwd=None,
|
||||
runas=None,
|
||||
python_shell=False,
|
||||
use_vt=False,
|
||||
)
|
||||
self.assertEqual(
|
||||
ret, {
|
||||
'bbfreeze-loader': '1.1.0',
|
||||
'bbfreeze': '1.1.0',
|
||||
}
|
||||
)
|
||||
|
||||
def test_install_pre_argument_in_resulting_command(self):
|
||||
pkg = 'pep8'
|
||||
|
@ -6,6 +6,7 @@ from __future__ import absolute_import
|
||||
# Import Salt Testing libs
|
||||
from salttesting import TestCase
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import patch, MagicMock
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
@ -15,25 +16,37 @@ from salt.pillar import nodegroups
|
||||
fake_minion_id = 'fake_id'
|
||||
fake_pillar = {}
|
||||
fake_nodegroups = {
|
||||
'a': fake_minion_id,
|
||||
'b': 'nodegroup_b',
|
||||
'groupA': fake_minion_id,
|
||||
'groupB': 'another_minion_id',
|
||||
}
|
||||
fake_opts = {
|
||||
'cache': 'localfs',
|
||||
'nodegroups': fake_nodegroups,
|
||||
'id': fake_minion_id
|
||||
}
|
||||
fake_opts = {'nodegroups': fake_nodegroups, 'id': fake_minion_id}
|
||||
fake_pillar_name = 'fake_pillar_name'
|
||||
|
||||
nodegroups.__opts__ = fake_opts
|
||||
|
||||
|
||||
def side_effect(group_sel, t):
|
||||
if group_sel.find(fake_minion_id) != -1:
|
||||
return [fake_minion_id, ]
|
||||
return ['another_minion_id', ]
|
||||
|
||||
|
||||
class NodegroupsPillarTestCase(TestCase):
|
||||
'''
|
||||
Tests for salt.pillar.nodegroups
|
||||
'''
|
||||
|
||||
@patch('salt.utils.minions.CkMinions.check_minions',
|
||||
MagicMock(side_effect=side_effect))
|
||||
def _runner(self, expected_ret, pillar_name=None):
|
||||
pillar_name = pillar_name or fake_pillar_name
|
||||
actual_ret = nodegroups.ext_pillar(fake_minion_id, fake_pillar, pillar_name=pillar_name)
|
||||
self.assertDictEqual(actual_ret, expected_ret)
|
||||
|
||||
def test_succeeds(self):
|
||||
ret = {fake_pillar_name: ['a', ]}
|
||||
ret = {fake_pillar_name: ['groupA', ]}
|
||||
self._runner(ret)
|
||||
|
Loading…
Reference in New Issue
Block a user