mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
Merge branch 'develop' into develop
This commit is contained in:
commit
1bbd1565d1
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
|
||||
# 1130 is approximately 3 years and 1 month
|
||||
daysUntilStale: 1130
|
||||
# 1115 is approximately 3 years and 1 month
|
||||
daysUntilStale: 1115
|
||||
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
|
@ -1,4 +1,11 @@
|
||||
{
|
||||
"alwaysNotifyForPaths": [
|
||||
{
|
||||
"name": "ryan-lane",
|
||||
"files": ["salt/**/*boto*.py"],
|
||||
"skipTeamPrs": false
|
||||
}
|
||||
],
|
||||
"skipTitle": "Merge forward",
|
||||
"userBlacklist": ["cvrebert", "markusgattol", "olliewalsh"]
|
||||
}
|
||||
|
@ -245,8 +245,8 @@ on_saltstack = 'SALT_ON_SALTSTACK' in os.environ
|
||||
project = 'Salt'
|
||||
|
||||
version = salt.version.__version__
|
||||
latest_release = '2017.7.0' # latest release
|
||||
previous_release = '2016.11.6' # latest release from previous branch
|
||||
latest_release = '2017.7.1' # latest release
|
||||
previous_release = '2016.11.7' # latest release from previous branch
|
||||
previous_release_dir = '2016.11' # path on web server for previous branch
|
||||
next_release = '' # next release
|
||||
next_release_dir = '' # path on web server for next release branch
|
||||
@ -258,8 +258,8 @@ if on_saltstack:
|
||||
copyright = time.strftime("%Y")
|
||||
|
||||
# < --- START do not merge these settings to other branches START ---> #
|
||||
build_type = 'latest' # latest, previous, develop, next
|
||||
release = latest_release # version, latest_release, previous_release
|
||||
build_type = 'develop' # latest, previous, develop, next
|
||||
release = version # version, latest_release, previous_release
|
||||
# < --- END do not merge these settings to other branches END ---> #
|
||||
|
||||
# Set google custom search engine
|
||||
|
@ -19,5 +19,4 @@ auth modules
|
||||
pki
|
||||
rest
|
||||
sharedsecret
|
||||
stormpath
|
||||
yubico
|
||||
|
@ -1,6 +0,0 @@
|
||||
===================
|
||||
salt.auth.stormpath
|
||||
===================
|
||||
|
||||
.. automodule:: salt.auth.stormpath
|
||||
:members:
|
@ -33,6 +33,10 @@ Output Options
|
||||
|
||||
Write the output to the specified file.
|
||||
|
||||
.. option:: --out-file-append, --output-file-append
|
||||
|
||||
Append the output to the specified file.
|
||||
|
||||
.. option:: --no-color
|
||||
|
||||
Disable all colored output
|
||||
@ -46,3 +50,14 @@ Output Options
|
||||
|
||||
``green`` denotes success, ``red`` denotes failure, ``blue`` denotes
|
||||
changes and success and ``yellow`` denotes a expected future change in configuration.
|
||||
|
||||
.. option:: --state-output=STATE_OUTPUT, --state_output=STATE_OUTPUT
|
||||
|
||||
Override the configured state_output value for minion
|
||||
output. One of 'full', 'terse', 'mixed', 'changes' or
|
||||
'filter'. Default: 'none'.
|
||||
|
||||
.. option:: --state-verbose=STATE_VERBOSE, --state_verbose=STATE_VERBOSE
|
||||
|
||||
Override the configured state_verbose value for minion
|
||||
output. Set to True or False. Default: none.
|
||||
|
@ -81,7 +81,7 @@ Options
|
||||
|
||||
Pass in an external authentication medium to validate against. The
|
||||
credentials will be prompted for. The options are `auto`,
|
||||
`keystone`, `ldap`, `pam`, and `stormpath`. Can be used with the -T
|
||||
`keystone`, `ldap`, and `pam`. Can be used with the -T
|
||||
option.
|
||||
|
||||
.. option:: -T, --make-token
|
||||
|
@ -97,6 +97,7 @@ execution modules
|
||||
cytest
|
||||
daemontools
|
||||
data
|
||||
datadog_api
|
||||
ddns
|
||||
deb_apache
|
||||
deb_postgres
|
||||
@ -399,7 +400,6 @@ execution modules
|
||||
state
|
||||
status
|
||||
statuspage
|
||||
stormpath
|
||||
supervisord
|
||||
suse_apache
|
||||
svn
|
||||
|
6
doc/ref/modules/all/salt.modules.datadog_api.rst
Normal file
6
doc/ref/modules/all/salt.modules.datadog_api.rst
Normal file
@ -0,0 +1,6 @@
|
||||
========================
|
||||
salt.modules.datadog_api
|
||||
========================
|
||||
|
||||
.. automodule:: salt.modules.datadog_api
|
||||
:members:
|
@ -1,6 +0,0 @@
|
||||
======================
|
||||
salt.modules.stormpath
|
||||
======================
|
||||
|
||||
.. automodule:: salt.modules.stormpath
|
||||
:members:
|
@ -4,3 +4,4 @@ salt.modules.test
|
||||
|
||||
.. automodule:: salt.modules.test
|
||||
:members:
|
||||
:exclude-members: rand_str
|
||||
|
@ -429,7 +429,7 @@ similar to the following:
|
||||
Confine this module to Mac OS with Homebrew.
|
||||
'''
|
||||
|
||||
if salt.utils.which('brew') and __grains__['os'] == 'MacOS':
|
||||
if salt.utils.path.which('brew') and __grains__['os'] == 'MacOS':
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
@ -146,8 +146,10 @@ Here is a simple YAML renderer example:
|
||||
|
||||
import yaml
|
||||
from salt.utils.yamlloader import SaltYamlSafeLoader
|
||||
from salt.ext import six
|
||||
|
||||
def render(yaml_data, saltenv='', sls='', **kws):
|
||||
if not isinstance(yaml_data, basestring):
|
||||
if not isinstance(yaml_data, six.string_types):
|
||||
yaml_data = yaml_data.read()
|
||||
data = yaml.load(
|
||||
yaml_data,
|
||||
|
@ -250,7 +250,6 @@ state modules
|
||||
stateconf
|
||||
status
|
||||
statuspage
|
||||
stormpath_account
|
||||
supervisord
|
||||
svn
|
||||
sysctl
|
||||
|
@ -1,6 +1,6 @@
|
||||
=======================
|
||||
salt.modules.kubernetes
|
||||
=======================
|
||||
======================
|
||||
salt.states.kubernetes
|
||||
======================
|
||||
|
||||
.. automodule:: salt.modules.kubernetes
|
||||
.. automodule:: salt.states.kubernetes
|
||||
:members:
|
||||
|
@ -1,6 +0,0 @@
|
||||
=============================
|
||||
salt.states.stormpath_account
|
||||
=============================
|
||||
|
||||
.. automodule:: salt.states.stormpath_account
|
||||
:members:
|
@ -135,19 +135,23 @@ A State Module must return a dict containing the following keys/values:
|
||||
``test=True``, and changes would have been made if the state was not run in
|
||||
test mode.
|
||||
|
||||
+--------------------+-----------+-----------+
|
||||
+--------------------+-----------+------------------------+
|
||||
| | live mode | test mode |
|
||||
+====================+===========+===========+
|
||||
+====================+===========+========================+
|
||||
| no changes | ``True`` | ``True`` |
|
||||
+--------------------+-----------+-----------+
|
||||
+--------------------+-----------+------------------------+
|
||||
| successful changes | ``True`` | ``None`` |
|
||||
+--------------------+-----------+-----------+
|
||||
| failed changes | ``False`` | ``None`` |
|
||||
+--------------------+-----------+-----------+
|
||||
+--------------------+-----------+------------------------+
|
||||
| failed changes | ``False`` | ``False`` or ``None`` |
|
||||
+--------------------+-----------+------------------------+
|
||||
|
||||
.. note::
|
||||
|
||||
Test mode does not predict if the changes will be successful or not.
|
||||
Test mode does not predict if the changes will be successful or not,
|
||||
and hence the result for pending changes is usually ``None``.
|
||||
|
||||
However, if a state is going to fail and this can be determined
|
||||
in test mode without applying the change, ``False`` can be returned.
|
||||
|
||||
- **comment:** A string containing a summary of the result.
|
||||
|
||||
|
@ -777,8 +777,6 @@ Stateconf
|
||||
stderr
|
||||
stdin
|
||||
stdout
|
||||
stormpath
|
||||
Stormpath
|
||||
str
|
||||
strftime
|
||||
subfolder
|
||||
|
@ -146,24 +146,24 @@ library. The following two lines set up the imports:
|
||||
.. code-block:: python
|
||||
|
||||
from salt.cloud.libcloudfuncs import * # pylint: disable=W0614,W0401
|
||||
from salt.utils import namespaced_function
|
||||
import salt.utils
|
||||
|
||||
And then a series of declarations will make the necessary functions available
|
||||
within the cloud module.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
get_size = namespaced_function(get_size, globals())
|
||||
get_image = namespaced_function(get_image, globals())
|
||||
avail_locations = namespaced_function(avail_locations, globals())
|
||||
avail_images = namespaced_function(avail_images, globals())
|
||||
avail_sizes = namespaced_function(avail_sizes, globals())
|
||||
script = namespaced_function(script, globals())
|
||||
destroy = namespaced_function(destroy, globals())
|
||||
list_nodes = namespaced_function(list_nodes, globals())
|
||||
list_nodes_full = namespaced_function(list_nodes_full, globals())
|
||||
list_nodes_select = namespaced_function(list_nodes_select, globals())
|
||||
show_instance = namespaced_function(show_instance, globals())
|
||||
get_size = salt.utils.namespaced_function(get_size, globals())
|
||||
get_image = salt.utils.namespaced_function(get_image, globals())
|
||||
avail_locations = salt.utils.namespaced_function(avail_locations, globals())
|
||||
avail_images = salt.utils.namespaced_function(avail_images, globals())
|
||||
avail_sizes = salt.utils.namespaced_function(avail_sizes, globals())
|
||||
script = salt.utils.namespaced_function(script, globals())
|
||||
destroy = salt.utils.namespaced_function(destroy, globals())
|
||||
list_nodes = salt.utils.namespaced_function(list_nodes, globals())
|
||||
list_nodes_full = salt.utils.namespaced_function(list_nodes_full, globals())
|
||||
list_nodes_select = salt.utils.namespaced_function(list_nodes_select, globals())
|
||||
show_instance = salt.utils.namespaced_function(show_instance, globals())
|
||||
|
||||
If necessary, these functions may be replaced by removing the appropriate
|
||||
declaration line, and then adding the function as normal.
|
||||
|
@ -49,7 +49,7 @@ Set up an initial profile at ``/etc/salt/cloud.profiles`` or in the
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
joyent_512
|
||||
joyent_512:
|
||||
provider: my-joyent-config
|
||||
size: g4-highcpu-512M
|
||||
image: ubuntu-16.04
|
||||
|
@ -18,10 +18,10 @@ on the significance and complexity of the changes required by the user.
|
||||
|
||||
Salt feature releases are based on the Periodic Table. Any new features going
|
||||
into the develop branch will be named after the next element in the Periodic
|
||||
Table. For example, Beryllium was the feature release name of the develop branch
|
||||
before the 2015.8 branch was tagged. At that point in time, any new features going
|
||||
into the develop branch after 2015.8 was branched were part of the Boron feature
|
||||
release.
|
||||
Table. For example, Beryllium was the feature release name of the develop
|
||||
branch before the 2015.8 branch was tagged. At that point in time, any new
|
||||
features going into the develop branch after 2015.8 was branched were part of
|
||||
the Boron feature release.
|
||||
|
||||
A deprecation warning should be in place for at least two major releases before
|
||||
the deprecated code and its accompanying deprecation warning are removed. More
|
||||
@ -29,14 +29,14 @@ time should be given for more complex changes. For example, if the current
|
||||
release under development is ``Sodium``, the deprecated code and associated
|
||||
warnings should remain in place and warn for at least ``Aluminum``.
|
||||
|
||||
To help in this deprecation task, salt provides :func:`salt.utils.warn_until
|
||||
<salt.utils.warn_until>`. The idea behind this helper function is to show the
|
||||
deprecation warning to the user until salt reaches the provided version. Once
|
||||
that provided version is equaled :func:`salt.utils.warn_until
|
||||
<salt.utils.warn_until>` will raise a :py:exc:`RuntimeError` making salt stop
|
||||
its execution. This stoppage is unpleasant and will remind the developer that
|
||||
the deprecation limit has been reached and that the code can then be safely
|
||||
removed.
|
||||
To help in this deprecation task, salt provides
|
||||
:func:`salt.utils.versions.warn_until <salt.utils.versions.warn_until>`. The
|
||||
idea behind this helper function is to show the deprecation warning to the user
|
||||
until salt reaches the provided version. Once that provided version is equaled
|
||||
:func:`salt.utils.versions.warn_until <salt.utils.versions.warn_until>` will
|
||||
raise a :py:exc:`RuntimeError` making salt stop its execution. This stoppage is
|
||||
unpleasant and will remind the developer that the deprecation limit has been
|
||||
reached and that the code can then be safely removed.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
@ -44,7 +44,7 @@ Consider the following example:
|
||||
|
||||
def some_function(bar=False, foo=None):
|
||||
if foo is not None:
|
||||
salt.utils.warn_until(
|
||||
salt.utils.versions.warn_until(
|
||||
'Aluminum',
|
||||
'The \'foo\' argument has been deprecated and its '
|
||||
'functionality removed, as such, its usage is no longer '
|
||||
|
154
doc/topics/installation/eos.rst
Normal file
154
doc/topics/installation/eos.rst
Normal file
@ -0,0 +1,154 @@
|
||||
=========================================
|
||||
Arista EOS Salt minion installation guide
|
||||
=========================================
|
||||
|
||||
The Salt minion for Arista EOS is distributed as a SWIX extension and can be installed directly on the switch. The EOS network operating system is based on old Fedora distributions and the installation of the ``salt-minion`` requires backports. This SWIX extension contains the necessary backports, together with the Salt basecode.
|
||||
|
||||
.. note::
|
||||
|
||||
This SWIX extension has been tested on Arista DCS-7280SE-68-R, running EOS 4.17.5M and vEOS 4.18.3F.
|
||||
|
||||
Important Notes
|
||||
===============
|
||||
|
||||
This package is in beta, make sure to test it carefully before running it in production.
|
||||
|
||||
If confirmed working correctly, please report and add a note on this page with the platform model and EOS version.
|
||||
|
||||
If you want to uninstall this package, please refer to the uninstalling_ section.
|
||||
|
||||
Installation from the Official SaltStack Repository
|
||||
===================================================
|
||||
|
||||
Download the swix package and save it to flash.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos#copy https://salt-eos.netops.life/salt-eos-latest.swix flash:
|
||||
veos#copy https://salt-eos.netops.life/startup.sh flash:
|
||||
|
||||
Install the Extension
|
||||
=====================
|
||||
|
||||
Copy the Salt package to extension
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos#copy flash:salt-eos-latest.swix extension:
|
||||
|
||||
Install the SWIX
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos#extension salt-eos-latest.swix force
|
||||
|
||||
Verify the installation
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos#show extensions | include salt-eos
|
||||
salt-eos-2017-07-19.swix 1.0.11/1.fc25 A, F 27
|
||||
|
||||
Change the Salt master IP address or FQDN, by edit the variable (SALT_MASTER)
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos#bash vi /mnt/flash/startup.sh
|
||||
|
||||
Make sure you enable the eAPI with unix-socket
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos(config)#management api http-commands
|
||||
protocol unix-socket
|
||||
no shutdown
|
||||
|
||||
Post-installation tasks
|
||||
=======================
|
||||
|
||||
Generate Keys and host record and start Salt minion
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos#bash
|
||||
#sudo /mnt/flash/startup.sh
|
||||
|
||||
``salt-minion`` should be running
|
||||
|
||||
Copy the installed extensions to boot-extensions
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos#copy installed-extensions boot-extensions
|
||||
|
||||
Apply event-handler to let EOS start salt-minion during boot-up
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos(config)#event-handler boot-up-script
|
||||
trigger on-boot
|
||||
action bash sudo /mnt/flash/startup.sh
|
||||
|
||||
For more specific installation details of the ``salt-minion``, please refer to :ref:`Configuring Salt<configuring-salt>`.
|
||||
|
||||
.. _uninstalling:
|
||||
|
||||
Uninstalling
|
||||
============
|
||||
|
||||
If you decide to uninstall this package, the following steps are recommended for safety:
|
||||
|
||||
1. Remove the extension from boot-extensions
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos#bash rm /mnt/flash/boot-extensions
|
||||
|
||||
2. Remove the extension from extensions folder
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos#bash rm /mnt/flash/.extensions/salt-eos-latest.swix
|
||||
|
||||
2. Remove boot-up script
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
veos(config)#no event-handler boot-up-script
|
||||
|
||||
Additional Information
|
||||
======================
|
||||
|
||||
This SWIX extension contains the following RPM packages:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
libsodium-1.0.11-1.fc25.i686.rpm
|
||||
libstdc++-6.2.1-2.fc25.i686.rpm
|
||||
openpgm-5.2.122-6.fc24.i686.rpm
|
||||
python-Jinja2-2.8-0.i686.rpm
|
||||
python-PyYAML-3.12-0.i686.rpm
|
||||
python-babel-0.9.6-5.fc18.noarch.rpm
|
||||
python-backports-1.0-3.fc18.i686.rpm
|
||||
python-backports-ssl_match_hostname-3.4.0.2-1.fc18.noarch.rpm
|
||||
python-backports_abc-0.5-0.i686.rpm
|
||||
python-certifi-2016.9.26-0.i686.rpm
|
||||
python-chardet-2.0.1-5.fc18.noarch.rpm
|
||||
python-crypto-1.4.1-1.noarch.rpm
|
||||
python-crypto-2.6.1-1.fc18.i686.rpm
|
||||
python-futures-3.1.1-1.noarch.rpm
|
||||
python-jtextfsm-0.3.1-0.noarch.rpm
|
||||
python-kitchen-1.1.1-2.fc18.noarch.rpm
|
||||
python-markupsafe-0.18-1.fc18.i686.rpm
|
||||
python-msgpack-python-0.4.8-0.i686.rpm
|
||||
python-napalm-base-0.24.3-1.noarch.rpm
|
||||
python-napalm-eos-0.6.0-1.noarch.rpm
|
||||
python-netaddr-0.7.18-0.noarch.rpm
|
||||
python-pyeapi-0.7.0-0.noarch.rpm
|
||||
python-salt-2017.7.0_1414_g2fb986f-1.noarch.rpm
|
||||
python-singledispatch-3.4.0.3-0.i686.rpm
|
||||
python-six-1.10.0-0.i686.rpm
|
||||
python-tornado-4.4.2-0.i686.rpm
|
||||
python-urllib3-1.5-7.fc18.noarch.rpm
|
||||
python2-zmq-15.3.0-2.fc25.i686.rpm
|
||||
zeromq-4.1.4-5.fc25.i686.rpm
|
@ -46,6 +46,7 @@ These guides go into detail how to install Salt on a given platform.
|
||||
|
||||
arch
|
||||
debian
|
||||
eos
|
||||
fedora
|
||||
freebsd
|
||||
gentoo
|
||||
|
@ -828,12 +828,14 @@ Returns:
|
||||
08.03.2017 17:00
|
||||
|
||||
|
||||
.. jinja_ref:: str_to_num
|
||||
.. jinja_ref:: to_num
|
||||
|
||||
``str_to_num``
|
||||
--------------
|
||||
``to_num``
|
||||
----------
|
||||
|
||||
.. versionadded:: 2017.7.0
|
||||
.. versionadded:: Oxygen
|
||||
Renamed from ``str_to_num`` to ``to_num``.
|
||||
|
||||
Converts a string to its numerical value.
|
||||
|
||||
@ -841,7 +843,7 @@ Example:
|
||||
|
||||
.. code-block:: jinja
|
||||
|
||||
{{ '5' | str_to_num }}
|
||||
{{ '5' | to_num }}
|
||||
|
||||
Returns:
|
||||
|
||||
@ -917,10 +919,10 @@ Returns:
|
||||
{'a': 'b'}
|
||||
|
||||
|
||||
.. jinja_ref:: rand_str
|
||||
.. jinja_ref:: random_hash
|
||||
|
||||
``rand_str``
|
||||
------------
|
||||
``random_hash``
|
||||
---------------
|
||||
|
||||
.. versionadded:: 2017.7.0
|
||||
.. versionadded:: Oxygen
|
||||
@ -937,8 +939,8 @@ Example:
|
||||
.. code-block:: jinja
|
||||
|
||||
{% set num_range = 99999999 %}
|
||||
{{ num_range | rand_str }}
|
||||
{{ num_range | rand_str('sha512') }}
|
||||
{{ num_range | random_hash }}
|
||||
{{ num_range | random_hash('sha512') }}
|
||||
|
||||
Returns:
|
||||
|
||||
|
@ -89,7 +89,7 @@ they are being loaded for the correct proxytype, example below:
|
||||
Only work on proxy
|
||||
'''
|
||||
try:
|
||||
if salt.utils.is_proxy() and \
|
||||
if salt.utils.platform.is_proxy() and \
|
||||
__opts__['proxy']['proxytype'] == 'ssh_sample':
|
||||
return __virtualname__
|
||||
except KeyError:
|
||||
@ -156,20 +156,23 @@ will need to be restarted to pick up any changes. A corresponding utility funct
|
||||
``saltutil.sync_proxymodules``, has been added to sync these modules to minions.
|
||||
|
||||
In addition, a salt.utils helper function called `is_proxy()` was added to make
|
||||
it easier to tell when the running minion is a proxy minion.
|
||||
it easier to tell when the running minion is a proxy minion. **NOTE: This
|
||||
function was renamed to salt.utils.platform.is_proxy() for the Oxygen release**
|
||||
|
||||
New in 2015.8
|
||||
-------------
|
||||
|
||||
Starting with the 2015.8 release of Salt, proxy processes are no longer forked off from a controlling minion.
|
||||
Instead, they have their own script ``salt-proxy`` which takes mostly the same arguments that the
|
||||
standard Salt minion does with the addition of ``--proxyid``. This is the id that the salt-proxy will
|
||||
use to identify itself to the master. Proxy configurations are still best kept in Pillar and their format
|
||||
has not changed.
|
||||
Starting with the 2015.8 release of Salt, proxy processes are no longer forked
|
||||
off from a controlling minion. Instead, they have their own script
|
||||
``salt-proxy`` which takes mostly the same arguments that the standard Salt
|
||||
minion does with the addition of ``--proxyid``. This is the id that the
|
||||
salt-proxy will use to identify itself to the master. Proxy configurations are
|
||||
still best kept in Pillar and their format has not changed.
|
||||
|
||||
This change allows for better process control and logging. Proxy processes can now be listed with standard
|
||||
process management utilities (``ps`` from the command line). Also, a full Salt minion is no longer
|
||||
required (though it is still strongly recommended) on machines hosting proxies.
|
||||
This change allows for better process control and logging. Proxy processes can
|
||||
now be listed with standard process management utilities (``ps`` from the
|
||||
command line). Also, a full Salt minion is no longer required (though it is
|
||||
still strongly recommended) on machines hosting proxies.
|
||||
|
||||
|
||||
Getting Started
|
||||
@ -619,9 +622,10 @@ in the proxymodule itself. This might be useful if a proxymodule author wants t
|
||||
all the code for the proxy interface in the same place instead of splitting it between
|
||||
the proxy and grains directories.
|
||||
|
||||
This function will only be called automatically if the configuration variable ``proxy_merge_grains_in_module``
|
||||
is set to True in the proxy configuration file (default ``/etc/salt/proxy``). This
|
||||
variable defaults to ``True`` in the release code-named *2017.7.0*.
|
||||
This function will only be called automatically if the configuration variable
|
||||
``proxy_merge_grains_in_module`` is set to True in the proxy configuration file
|
||||
(default ``/etc/salt/proxy``). This variable defaults to ``True`` in the
|
||||
release code-named *2017.7.0*.
|
||||
|
||||
|
||||
.. code: python::
|
||||
@ -640,7 +644,7 @@ variable defaults to ``True`` in the release code-named *2017.7.0*.
|
||||
|
||||
def __virtual__():
|
||||
try:
|
||||
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'rest_sample':
|
||||
if salt.utils.platform.is_proxy() and __opts__['proxy']['proxytype'] == 'rest_sample':
|
||||
return __virtualname__
|
||||
except KeyError:
|
||||
pass
|
||||
@ -708,7 +712,7 @@ Example from ``salt/grains/rest_sample.py``:
|
||||
|
||||
def __virtual__():
|
||||
try:
|
||||
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'rest_sample':
|
||||
if salt.utils.platform.is_proxy() and __opts__['proxy']['proxytype'] == 'rest_sample':
|
||||
return __virtualname__
|
||||
except KeyError:
|
||||
pass
|
||||
|
@ -175,6 +175,10 @@ they are being loaded for the correct proxytype, example below:
|
||||
|
||||
return False
|
||||
|
||||
.. note::
|
||||
``salt.utils.is_proxy()`` has been renamed to
|
||||
``salt.utils.platform.is_proxy`` as of the Oxygen release.
|
||||
|
||||
The try/except block above exists because grains are processed very early
|
||||
in the proxy minion startup process, sometimes earlier than the proxy
|
||||
key in the ``__opts__`` dictionary is populated.
|
||||
|
@ -38,6 +38,14 @@ In previous releases the bind credentials would only be used to determine
|
||||
the LDAP user's existence and group membership. The user's LDAP credentials
|
||||
were used from then on.
|
||||
|
||||
Stormpath External Authentication Removed
|
||||
-----------------------------------------
|
||||
|
||||
Per Stormpath's announcement, their API will be shutting down on 8/17/2017 at
|
||||
noon PST so the Stormpath external authentication module has been removed.
|
||||
|
||||
https://stormpath.com/oktaplusstormpath
|
||||
|
||||
New GitFS Features
|
||||
------------------
|
||||
|
||||
@ -63,10 +71,10 @@ environments (i.e. ``saltenvs``) have been added:
|
||||
available as saltenvs.
|
||||
|
||||
Salt Cloud Features
|
||||
===================
|
||||
-------------------
|
||||
|
||||
Pre-Flight Commands
|
||||
-------------------
|
||||
===================
|
||||
|
||||
Support has been added for specified "preflight commands" to run on a VM before
|
||||
the deploy script is run. These must be defined as a list in a cloud configuration
|
||||
@ -98,23 +106,514 @@ running on T-Series SPARC hardware. The ``virtual_subtype`` grain is
|
||||
populated as a list of domain roles.
|
||||
|
||||
|
||||
Beacon configuration changes
|
||||
----------------------------------------
|
||||
|
||||
In order to remain consistent and to align with other Salt components such as states,
|
||||
support for configuring beacons using dictionary based configuration has been deprecated
|
||||
in favor of list based configuration. All beacons have a validation function which will
|
||||
check the configuration for the correct format and only load if the validation passes.
|
||||
|
||||
- ``avahi_announce`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
avahi_announce:
|
||||
run_once: True
|
||||
servicetype: _demo._tcp
|
||||
port: 1234
|
||||
txt:
|
||||
ProdName: grains.productname
|
||||
SerialNo: grains.serialnumber
|
||||
Comments: 'this is a test'
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
avahi_announce:
|
||||
- run_once: True
|
||||
- servicetype: _demo._tcp
|
||||
- port: 1234
|
||||
- txt:
|
||||
ProdName: grains.productname
|
||||
SerialNo: grains.serialnumber
|
||||
Comments: 'this is a test'
|
||||
```
|
||||
|
||||
- ``bonjour_announce`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
bonjour_announce:
|
||||
run_once: True
|
||||
servicetype: _demo._tcp
|
||||
port: 1234
|
||||
txt:
|
||||
ProdName: grains.productname
|
||||
SerialNo: grains.serialnumber
|
||||
Comments: 'this is a test'
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
bonjour_announce:
|
||||
- run_once: True
|
||||
- servicetype: _demo._tcp
|
||||
- port: 1234
|
||||
- txt:
|
||||
ProdName: grains.productname
|
||||
SerialNo: grains.serialnumber
|
||||
Comments: 'this is a test'
|
||||
```
|
||||
|
||||
- ``btmp`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
btmp: {}
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
btmp: []
|
||||
|
||||
```
|
||||
|
||||
- ``glxinfo`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
glxinfo:
|
||||
user: frank
|
||||
screen_event: True
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
glxinfo:
|
||||
- user: frank
|
||||
- screen_event: True
|
||||
```
|
||||
|
||||
- ``haproxy`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
haproxy:
|
||||
- www-backend:
|
||||
threshold: 45
|
||||
servers:
|
||||
- web1
|
||||
- web2
|
||||
- interval: 120
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
haproxy:
|
||||
- backends:
|
||||
www-backend:
|
||||
threshold: 45
|
||||
servers:
|
||||
- web1
|
||||
- web2
|
||||
- interval: 120
|
||||
```
|
||||
|
||||
- ``inotify`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
inotify:
|
||||
/path/to/file/or/dir:
|
||||
mask:
|
||||
- open
|
||||
- create
|
||||
- close_write
|
||||
recurse: True
|
||||
auto_add: True
|
||||
exclude:
|
||||
- /path/to/file/or/dir/exclude1
|
||||
- /path/to/file/or/dir/exclude2
|
||||
- /path/to/file/or/dir/regex[a-m]*$:
|
||||
regex: True
|
||||
coalesce: True
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
inotify:
|
||||
- files:
|
||||
/path/to/file/or/dir:
|
||||
mask:
|
||||
- open
|
||||
- create
|
||||
- close_write
|
||||
recurse: True
|
||||
auto_add: True
|
||||
exclude:
|
||||
- /path/to/file/or/dir/exclude1
|
||||
- /path/to/file/or/dir/exclude2
|
||||
- /path/to/file/or/dir/regex[a-m]*$:
|
||||
regex: True
|
||||
- coalesce: True
|
||||
```
|
||||
|
||||
- ``journald`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
journald:
|
||||
sshd:
|
||||
SYSLOG_IDENTIFIER: sshd
|
||||
PRIORITY: 6
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
journald:
|
||||
- services:
|
||||
sshd:
|
||||
SYSLOG_IDENTIFIER: sshd
|
||||
PRIORITY: 6
|
||||
```
|
||||
|
||||
- ``load`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
load:
|
||||
1m:
|
||||
- 0.0
|
||||
- 2.0
|
||||
5m:
|
||||
- 0.0
|
||||
- 1.5
|
||||
15m:
|
||||
- 0.1
|
||||
- 1.0
|
||||
emitatstartup: True
|
||||
onchangeonly: False
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
load:
|
||||
- averages:
|
||||
1m:
|
||||
- 0.0
|
||||
- 2.0
|
||||
5m:
|
||||
- 0.0
|
||||
- 1.5
|
||||
15m:
|
||||
- 0.1
|
||||
- 1.0
|
||||
- emitatstartup: True
|
||||
- onchangeonly: False
|
||||
```
|
||||
|
||||
- ``log`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
log:
|
||||
file: <path>
|
||||
<tag>:
|
||||
regex: <pattern>
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
log:
|
||||
- file: <path>
|
||||
- tags:
|
||||
<tag>:
|
||||
regex: <pattern>
|
||||
```
|
||||
|
||||
- ``network_info`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
network_info:
|
||||
- eth0:
|
||||
type: equal
|
||||
bytes_sent: 100000
|
||||
bytes_recv: 100000
|
||||
packets_sent: 100000
|
||||
packets_recv: 100000
|
||||
errin: 100
|
||||
errout: 100
|
||||
dropin: 100
|
||||
dropout: 100
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
network_info:
|
||||
- interfaces:
|
||||
eth0:
|
||||
type: equal
|
||||
bytes_sent: 100000
|
||||
bytes_recv: 100000
|
||||
packets_sent: 100000
|
||||
packets_recv: 100000
|
||||
errin: 100
|
||||
errout: 100
|
||||
dropin: 100
|
||||
dropout: 100
|
||||
```
|
||||
|
||||
- ``network_settings`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
network_settings:
|
||||
eth0:
|
||||
ipaddr:
|
||||
promiscuity:
|
||||
onvalue: 1
|
||||
eth1:
|
||||
linkmode:
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
network_settings:
|
||||
- interfaces:
|
||||
- eth0:
|
||||
ipaddr:
|
||||
promiscuity:
|
||||
onvalue: 1
|
||||
- eth1:
|
||||
linkmode:
|
||||
```
|
||||
|
||||
- ``proxy_example`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
proxy_example:
|
||||
endpoint: beacon
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
proxy_example:
|
||||
- endpoint: beacon
|
||||
```
|
||||
|
||||
- ``ps`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
ps:
|
||||
- salt-master: running
|
||||
- mysql: stopped
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
ps:
|
||||
- processes:
|
||||
salt-master: running
|
||||
mysql: stopped
|
||||
```
|
||||
|
||||
- ``salt_proxy`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
salt_proxy:
|
||||
- p8000: {}
|
||||
- p8001: {}
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
salt_proxy:
|
||||
- proxies:
|
||||
p8000: {}
|
||||
p8001: {}
|
||||
```
|
||||
|
||||
- ``sensehat`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
sensehat:
|
||||
humidity: 70%
|
||||
temperature: [20, 40]
|
||||
temperature_from_pressure: 40
|
||||
pressure: 1500
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
sensehat:
|
||||
- sensors:
|
||||
humidity: 70%
|
||||
temperature: [20, 40]
|
||||
temperature_from_pressure: 40
|
||||
pressure: 1500
|
||||
```
|
||||
|
||||
- ``service`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
service:
|
||||
salt-master:
|
||||
mysql:
|
||||
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
service:
|
||||
- services:
|
||||
nginx:
|
||||
onchangeonly: True
|
||||
delay: 30
|
||||
uncleanshutdown: /run/nginx.pid
|
||||
```
|
||||
|
||||
- ``sh`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
sh: {}
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
sh: []
|
||||
```
|
||||
|
||||
- ``status`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
status: {}
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
status: []
|
||||
```
|
||||
|
||||
- ``telegram_bot_msg`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
telegram_bot_msg:
|
||||
token: "<bot access token>"
|
||||
accept_from:
|
||||
- "<valid username>"
|
||||
interval: 10
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
telegram_bot_msg:
|
||||
- token: "<bot access token>"
|
||||
- accept_from:
|
||||
- "<valid username>"
|
||||
- interval: 10
|
||||
```
|
||||
|
||||
- ``twilio_txt_msg`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
twilio_txt_msg:
|
||||
account_sid: "<account sid>"
|
||||
auth_token: "<auth token>"
|
||||
twilio_number: "+15555555555"
|
||||
interval: 10
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
twilio_txt_msg:
|
||||
- account_sid: "<account sid>"
|
||||
- auth_token: "<auth token>"
|
||||
- twilio_number: "+15555555555"
|
||||
- interval: 10
|
||||
```
|
||||
|
||||
- ``wtmp`` beacon
|
||||
|
||||
Old behavior:
|
||||
```
|
||||
beacons:
|
||||
wtmp: {}
|
||||
```
|
||||
|
||||
New behavior:
|
||||
```
|
||||
beacons:
|
||||
wtmp: []
|
||||
```
|
||||
|
||||
Deprecations
|
||||
============
|
||||
------------
|
||||
|
||||
Configuration Option Deprecations
|
||||
---------------------------------
|
||||
=================================
|
||||
|
||||
- The ``requests_lib`` configuration option has been removed. Please use
|
||||
``backend`` instead.
|
||||
|
||||
Profitbricks Cloud Updated Dependency
|
||||
-------------------------------------
|
||||
=====================================
|
||||
|
||||
The minimum version of the `profitbrick` python package for the `profitbricks`
|
||||
The minimum version of the ``profitbrick`` python package for the ``profitbricks``
|
||||
cloud driver has changed from 3.0.0 to 3.1.0.
|
||||
|
||||
Module Deprecations
|
||||
-------------------
|
||||
===================
|
||||
|
||||
The ``blockdev`` execution module has been removed. Its functions were merged
|
||||
with the ``disk`` module. Please use the ``disk`` execution module instead.
|
||||
@ -154,7 +653,7 @@ The ``win_service`` module had the following changes:
|
||||
``service_type`` instead.
|
||||
|
||||
Runner Deprecations
|
||||
-------------------
|
||||
===================
|
||||
|
||||
The ``manage`` runner had the following changes:
|
||||
|
||||
@ -162,7 +661,7 @@ The ``manage`` runner had the following changes:
|
||||
use ``salt-ssh`` roster entries for the host instead.
|
||||
|
||||
State Deprecations
|
||||
------------------
|
||||
==================
|
||||
|
||||
The ``archive`` state had the following changes:
|
||||
|
||||
@ -185,7 +684,7 @@ The ``file`` state had the following changes:
|
||||
- The ``show_diff`` option was removed. Please use ``show_changes`` instead.
|
||||
|
||||
Grain Deprecations
|
||||
------------------
|
||||
==================
|
||||
|
||||
For ``smartos`` some grains have been deprecated. These grains will be removed in Neon.
|
||||
|
||||
@ -205,7 +704,7 @@ as well, by using special grains keys ``minion_blackout`` and
|
||||
``minion_blackout_whitelist``.
|
||||
|
||||
Utils Deprecations
|
||||
------------------
|
||||
==================
|
||||
|
||||
The ``salt.utils.cloud.py`` file had the following change:
|
||||
|
||||
@ -213,7 +712,7 @@ The ``salt.utils.cloud.py`` file had the following change:
|
||||
optional.
|
||||
|
||||
Other Miscellaneous Deprecations
|
||||
--------------------------------
|
||||
================================
|
||||
|
||||
The ``version.py`` file had the following changes:
|
||||
|
||||
|
@ -166,13 +166,15 @@ Ubuntu 14.04 LTS and Debian Wheezy (7.x) also have a compatible version packaged
|
||||
|
||||
# apt-get install python-git
|
||||
|
||||
If your master is running an older version (such as Ubuntu 12.04 LTS or Debian
|
||||
Squeeze), then you will need to install GitPython using either pip_ or
|
||||
easy_install (it is recommended to use pip). Version 0.3.2.RC1 is now marked as
|
||||
the stable release in PyPI, so it should be a simple matter of running ``pip
|
||||
install GitPython`` (or ``easy_install GitPython``) as root.
|
||||
GitPython_ requires the ``git`` CLI utility to work. If installed from a system
|
||||
package, then git should already be installed, but if installed via pip_ then
|
||||
it may still be necessary to install git separately. For MacOS users,
|
||||
GitPython_ comes bundled in with the Salt installer, but git must still be
|
||||
installed for it to work properly. Git can be installed in several ways,
|
||||
including by installing XCode_.
|
||||
|
||||
.. _`pip`: http://www.pip-installer.org/
|
||||
.. _pip: http://www.pip-installer.org/
|
||||
.. _XCode: https://developer.apple.com/xcode/
|
||||
|
||||
.. warning::
|
||||
|
||||
|
@ -110,7 +110,7 @@ To pass through a file that contains jinja + yaml templating (the default):
|
||||
method='POST',
|
||||
data_file='/srv/salt/somefile.jinja',
|
||||
data_render=True,
|
||||
template_data={'key1': 'value1', 'key2': 'value2'}
|
||||
template_dict={'key1': 'value1', 'key2': 'value2'}
|
||||
)
|
||||
|
||||
To pass through a file that contains mako templating:
|
||||
@ -123,7 +123,7 @@ To pass through a file that contains mako templating:
|
||||
data_file='/srv/salt/somefile.mako',
|
||||
data_render=True,
|
||||
data_renderer='mako',
|
||||
template_data={'key1': 'value1', 'key2': 'value2'}
|
||||
template_dict={'key1': 'value1', 'key2': 'value2'}
|
||||
)
|
||||
|
||||
Because this function uses Salt's own rendering system, any Salt renderer can
|
||||
@ -140,7 +140,7 @@ However, this can be changed to ``master`` if necessary.
|
||||
method='POST',
|
||||
data_file='/srv/salt/somefile.jinja',
|
||||
data_render=True,
|
||||
template_data={'key1': 'value1', 'key2': 'value2'},
|
||||
template_dict={'key1': 'value1', 'key2': 'value2'},
|
||||
opts=__opts__
|
||||
)
|
||||
|
||||
@ -149,7 +149,7 @@ However, this can be changed to ``master`` if necessary.
|
||||
method='POST',
|
||||
data_file='/srv/salt/somefile.jinja',
|
||||
data_render=True,
|
||||
template_data={'key1': 'value1', 'key2': 'value2'},
|
||||
template_dict={'key1': 'value1', 'key2': 'value2'},
|
||||
node='master'
|
||||
)
|
||||
|
||||
@ -170,11 +170,11 @@ a Python dict.
|
||||
header_file='/srv/salt/headers.jinja',
|
||||
header_render=True,
|
||||
header_renderer='jinja',
|
||||
template_data={'key1': 'value1', 'key2': 'value2'}
|
||||
template_dict={'key1': 'value1', 'key2': 'value2'}
|
||||
)
|
||||
|
||||
Because much of the data that would be templated between headers and data may be
|
||||
the same, the ``template_data`` is the same for both. Correcting possible
|
||||
the same, the ``template_dict`` is the same for both. Correcting possible
|
||||
variable name collisions is up to the user.
|
||||
|
||||
Authentication
|
||||
|
@ -28,7 +28,6 @@ Tutorials Index
|
||||
* :ref:`States tutorial, part 3 - Templating, Includes, Extends <tutorial-states-part-3>`
|
||||
* :ref:`States tutorial, part 4 <tutorial-states-part-4>`
|
||||
* :ref:`How to Convert Jinja Logic to an Execution Module <tutorial-jinja_to_execution-module>`
|
||||
* :ref:`Using Salt with Stormpath <tutorial-stormpath>`
|
||||
* :ref:`Syslog-ng usage <syslog-ng-sate-usage>`
|
||||
* :ref:`The macOS (Maverick) Developer Step By Step Guide To Salt Installation <tutorial-macos-walk-through>`
|
||||
* :ref:`SaltStack Walk-through <tutorial-salt-walk-through>`
|
||||
|
@ -1,198 +0,0 @@
|
||||
.. _tutorial-stormpath:
|
||||
|
||||
=========================
|
||||
Using Salt with Stormpath
|
||||
=========================
|
||||
|
||||
`Stormpath <https://stormpath.com/>`_ is a user management and authentication
|
||||
service. This tutorial covers using SaltStack to manage and take advantage of
|
||||
Stormpath's features.
|
||||
|
||||
External Authentication
|
||||
-----------------------
|
||||
Stormpath can be used for Salt's external authentication system. In order to do
|
||||
this, the master should be configured with an ``apiid``, ``apikey``, and the ID
|
||||
of the ``application`` that is associated with the users to be authenticated:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
stormpath:
|
||||
apiid: 367DFSF4FRJ8767FSF4G34FGH
|
||||
apikey: FEFREF43t3FEFRe/f323fwer4FWF3445gferWRWEer1
|
||||
application: 786786FREFrefreg435fr1
|
||||
|
||||
.. note::
|
||||
These values can be found in the `Stormpath dashboard
|
||||
<https://api.stormpath.com/ui2/index.html#/>`_`.
|
||||
|
||||
Users that are to be authenticated should be set up under the ``stormpath``
|
||||
dict under ``external_auth``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
external_auth:
|
||||
stormpath:
|
||||
larry:
|
||||
- .*
|
||||
- '@runner'
|
||||
- '@wheel'
|
||||
|
||||
Keep in mind that while Stormpath defaults the username associated with the
|
||||
account to the email address, it is better to use a username without an ``@``
|
||||
sign in it.
|
||||
|
||||
|
||||
Configuring Stormpath Modules
|
||||
-----------------------------
|
||||
Stormpath accounts can be managed via either an execution or state module. In
|
||||
order to use either, a minion must be configured with an API ID and key.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
stormpath:
|
||||
apiid: 367DFSF4FRJ8767FSF4G34FGH
|
||||
apikey: FEFREF43t3FEFRe/f323fwer4FWF3445gferWRWEer1
|
||||
directory: efreg435fr1786786FREFr
|
||||
application: 786786FREFrefreg435fr1
|
||||
|
||||
Some functions in the ``stormpath`` modules can make use of other options. The
|
||||
following options are also available.
|
||||
|
||||
directory
|
||||
`````````
|
||||
The ID of the directory that is to be used with this minion. Many functions
|
||||
require an ID to be specified to do their work. However, if the ID of a
|
||||
``directory`` is specified, then Salt can often look up the resource in
|
||||
question.
|
||||
|
||||
application
|
||||
```````````
|
||||
The ID of the application that is to be used with this minion. Many functions
|
||||
require an ID to be specified to do their work. However, if the ID of a
|
||||
``application`` is specified, then Salt can often look up the resource in
|
||||
question.
|
||||
|
||||
|
||||
Managing Stormpath Accounts
|
||||
---------------------------
|
||||
With the ``stormpath`` configuration in place, Salt can be used to configure
|
||||
accounts (which may be thought of as users) on the Stormpath service. The
|
||||
following functions are available.
|
||||
|
||||
stormpath.create_account
|
||||
````````````````````````
|
||||
Create an account on the Stormpath service. This requires a ``directory_id`` as
|
||||
the first argument; it will not be retrieved from the minion configuration. An
|
||||
``email`` address, ``password``, first name (``givenName``) and last name
|
||||
(``surname``) are also required. For the full list of other parameters that may
|
||||
be specified, see:
|
||||
|
||||
http://docs.stormpath.com/rest/product-guide/#account-resource
|
||||
|
||||
When executed with no errors, this function will return the information about
|
||||
the account, from Stormpath.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt myminion stormpath.create_account <directory_id> shemp@example.com letmein Shemp Howard
|
||||
|
||||
|
||||
stormpath.list_accounts
|
||||
```````````````````````
|
||||
Show all accounts on the Stormpath service. This will return all accounts,
|
||||
regardless of directory, application, or group.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt myminion stormpath.list_accounts
|
||||
'''
|
||||
|
||||
stormpath.show_account
|
||||
``````````````````````
|
||||
Show the details for a specific Stormpath account. An ``account_id`` is normally
|
||||
required. However, if am ``email`` is provided instead, along with either a
|
||||
``directory_id``, ``application_id``, or ``group_id``, then Salt will search the
|
||||
specified resource to try and locate the ``account_id``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt myminion stormpath.show_account <account_id>
|
||||
salt myminion stormpath.show_account email=<email> directory_id=<directory_id>
|
||||
|
||||
|
||||
stormpath.update_account
|
||||
````````````````````````
|
||||
Update one or more items for this account. Specifying an empty value will clear
|
||||
it for that account. This function may be used in one of two ways. In order to
|
||||
update only one key/value pair, specify them in order:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt myminion stormpath.update_account <account_id> givenName shemp
|
||||
salt myminion stormpath.update_account <account_id> middleName ''
|
||||
|
||||
In order to specify multiple items, they need to be passed in as a dict. From
|
||||
the command line, it is best to do this as a JSON string:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt myminion stormpath.update_account <account_id> items='{"givenName": "Shemp"}
|
||||
salt myminion stormpath.update_account <account_id> items='{"middlename": ""}
|
||||
|
||||
When executed with no errors, this function will return the information about
|
||||
the account, from Stormpath.
|
||||
|
||||
|
||||
stormpath.delete_account
|
||||
````````````````````````
|
||||
Delete an account from Stormpath.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt myminion stormpath.delete_account <account_id>
|
||||
|
||||
|
||||
stormpath.list_directories
|
||||
``````````````````````````
|
||||
Show all directories associated with this tenant.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt myminion stormpath.list_directories
|
||||
|
||||
|
||||
Using Stormpath States
|
||||
----------------------
|
||||
Stormpath resources may be managed using the state system. The following states
|
||||
are available.
|
||||
|
||||
stormpath_account.present
|
||||
`````````````````````````
|
||||
Ensure that an account exists on the Stormpath service. All options that are
|
||||
available with the ``stormpath.create_account`` function are available here.
|
||||
If an account needs to be created, then this function will require the same
|
||||
fields that ``stormpath.create_account`` requires, including the ``password``.
|
||||
However, if a password changes for an existing account, it will NOT be updated
|
||||
by this state.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
curly@example.com:
|
||||
stormpath_account.present:
|
||||
- directory_id: efreg435fr1786786FREFr
|
||||
- password: badpass
|
||||
- firstName: Curly
|
||||
- surname: Howard
|
||||
- nickname: curly
|
||||
|
||||
It is advisable to always set a ``nickname`` that is not also an email address,
|
||||
so that it can be used by Salt's external authentication module.
|
||||
|
||||
stormpath_account.absent
|
||||
````````````````````````
|
||||
Ensure that an account does not exist on Stormpath. As with
|
||||
``stormpath_account.present``, the ``name`` supplied to this state is the
|
||||
``email`` address associated with this account. Salt will use this, with or
|
||||
without the ``directory`` ID that is configured for the minion. However, lookups
|
||||
will be much faster with a directory ID specified.
|
||||
|
@ -7,7 +7,7 @@ CherryPy==11.0.0
|
||||
click==6.7
|
||||
enum34==1.1.6
|
||||
gitdb==0.6.4
|
||||
GitPython==2.1.5
|
||||
GitPython==2.1.1
|
||||
idna==2.5
|
||||
ipaddress==1.0.18
|
||||
Jinja2==2.9.6
|
||||
|
@ -5,3 +5,4 @@ yappi>=0.8.2
|
||||
--allow-unverified python-neutronclient>2.3.6
|
||||
python-gnupg
|
||||
cherrypy>=3.2.2
|
||||
libnacl
|
||||
|
@ -7,6 +7,7 @@ Salt package
|
||||
from __future__ import absolute_import
|
||||
import warnings
|
||||
|
||||
# future lint: disable=non-unicode-string
|
||||
# All salt related deprecation warnings should be shown once each!
|
||||
warnings.filterwarnings(
|
||||
'once', # Show once
|
||||
@ -14,18 +15,19 @@ warnings.filterwarnings(
|
||||
DeprecationWarning, # This filter is for DeprecationWarnings
|
||||
r'^(salt|salt\.(.*))$' # Match module(s) 'salt' and 'salt.<whatever>'
|
||||
)
|
||||
# future lint: enable=non-unicode-string
|
||||
|
||||
# While we are supporting Python2.6, hide nested with-statements warnings
|
||||
warnings.filterwarnings(
|
||||
'ignore',
|
||||
'With-statements now directly support multiple context managers',
|
||||
u'ignore',
|
||||
u'With-statements now directly support multiple context managers',
|
||||
DeprecationWarning
|
||||
)
|
||||
|
||||
# Filter the backports package UserWarning about being re-imported
|
||||
warnings.filterwarnings(
|
||||
'ignore',
|
||||
'^Module backports was already imported from (.*), but (.*) is being added to sys.path$',
|
||||
u'ignore',
|
||||
u'^Module backports was already imported from (.*), but (.*) is being added to sys.path$',
|
||||
UserWarning
|
||||
)
|
||||
|
||||
@ -37,7 +39,7 @@ def __define_global_system_encoding_variable__():
|
||||
# and reset to None
|
||||
encoding = None
|
||||
|
||||
if not sys.platform.startswith('win') and sys.stdin is not None:
|
||||
if not sys.platform.startswith(u'win') and sys.stdin is not None:
|
||||
# On linux we can rely on sys.stdin for the encoding since it
|
||||
# most commonly matches the filesystem encoding. This however
|
||||
# does not apply to windows
|
||||
@ -63,16 +65,16 @@ def __define_global_system_encoding_variable__():
|
||||
# the way back to ascii
|
||||
encoding = sys.getdefaultencoding()
|
||||
if not encoding:
|
||||
if sys.platform.startswith('darwin'):
|
||||
if sys.platform.startswith(u'darwin'):
|
||||
# Mac OS X uses UTF-8
|
||||
encoding = 'utf-8'
|
||||
elif sys.platform.startswith('win'):
|
||||
encoding = u'utf-8'
|
||||
elif sys.platform.startswith(u'win'):
|
||||
# Windows uses a configurable encoding; on Windows, Python uses the name “mbcs”
|
||||
# to refer to whatever the currently configured encoding is.
|
||||
encoding = 'mbcs'
|
||||
encoding = u'mbcs'
|
||||
else:
|
||||
# On linux default to ascii as a last resort
|
||||
encoding = 'ascii'
|
||||
encoding = u'ascii'
|
||||
|
||||
# We can't use six.moves.builtins because these builtins get deleted sooner
|
||||
# than expected. See:
|
||||
@ -83,7 +85,7 @@ def __define_global_system_encoding_variable__():
|
||||
import builtins # pylint: disable=import-error
|
||||
|
||||
# Define the detected encoding as a built-in variable for ease of use
|
||||
setattr(builtins, '__salt_system_encoding__', encoding)
|
||||
setattr(builtins, u'__salt_system_encoding__', encoding)
|
||||
|
||||
# This is now garbage collectable
|
||||
del sys
|
||||
|
@ -46,7 +46,7 @@ else:
|
||||
|
||||
|
||||
if HAS_XML:
|
||||
if not hasattr(ElementTree, 'ParseError'):
|
||||
if not hasattr(ElementTree, u'ParseError'):
|
||||
class ParseError(Exception):
|
||||
'''
|
||||
older versions of ElementTree do not have ParseError
|
||||
@ -56,7 +56,7 @@ if HAS_XML:
|
||||
ElementTree.ParseError = ParseError
|
||||
|
||||
|
||||
def text_(s, encoding='latin-1', errors='strict'):
|
||||
def text_(s, encoding=u'latin-1', errors=u'strict'):
|
||||
'''
|
||||
If ``s`` is an instance of ``binary_type``, return
|
||||
``s.decode(encoding, errors)``, otherwise return ``s``
|
||||
@ -66,7 +66,7 @@ def text_(s, encoding='latin-1', errors='strict'):
|
||||
return s
|
||||
|
||||
|
||||
def bytes_(s, encoding='latin-1', errors='strict'):
|
||||
def bytes_(s, encoding=u'latin-1', errors=u'strict'):
|
||||
'''
|
||||
If ``s`` is an instance of ``text_type``, return
|
||||
``s.encode(encoding, errors)``, otherwise return ``s``
|
||||
@ -79,25 +79,25 @@ def bytes_(s, encoding='latin-1', errors='strict'):
|
||||
if PY3:
|
||||
def ascii_native_(s):
|
||||
if isinstance(s, text_type):
|
||||
s = s.encode('ascii')
|
||||
return str(s, 'ascii', 'strict')
|
||||
s = s.encode(u'ascii')
|
||||
return str(s, u'ascii', u'strict')
|
||||
else:
|
||||
def ascii_native_(s):
|
||||
if isinstance(s, text_type):
|
||||
s = s.encode('ascii')
|
||||
s = s.encode(u'ascii')
|
||||
return str(s)
|
||||
|
||||
ascii_native_.__doc__ = '''
|
||||
Python 3: If ``s`` is an instance of ``text_type``, return
|
||||
``s.encode('ascii')``, otherwise return ``str(s, 'ascii', 'strict')``
|
||||
``s.encode(u'ascii')``, otherwise return ``str(s, 'ascii', 'strict')``
|
||||
|
||||
Python 2: If ``s`` is an instance of ``text_type``, return
|
||||
``s.encode('ascii')``, otherwise return ``str(s)``
|
||||
'''
|
||||
``s.encode(u'ascii')``, otherwise return ``str(s)``
|
||||
''' # future lint: disable=non-unicode-string
|
||||
|
||||
|
||||
if PY3:
|
||||
def native_(s, encoding='latin-1', errors='strict'):
|
||||
def native_(s, encoding=u'latin-1', errors=u'strict'):
|
||||
'''
|
||||
If ``s`` is an instance of ``text_type``, return
|
||||
``s``, otherwise return ``str(s, encoding, errors)``
|
||||
@ -106,7 +106,7 @@ if PY3:
|
||||
return s
|
||||
return str(s, encoding, errors)
|
||||
else:
|
||||
def native_(s, encoding='latin-1', errors='strict'):
|
||||
def native_(s, encoding=u'latin-1', errors=u'strict'):
|
||||
'''
|
||||
If ``s`` is an instance of ``text_type``, return
|
||||
``s.encode(encoding, errors)``, otherwise return ``str(s)``
|
||||
@ -121,7 +121,7 @@ return ``str(s, encoding, errors)``
|
||||
|
||||
Python 2: If ``s`` is an instance of ``text_type``, return
|
||||
``s.encode(encoding, errors)``, otherwise return ``str(s)``
|
||||
'''
|
||||
''' # future lint: disable=non-unicode-string
|
||||
|
||||
|
||||
def string_io(data=None): # cStringIO can't handle unicode
|
||||
|
@ -10,8 +10,13 @@ found by reading the salt documentation:
|
||||
|
||||
# Import python libraries
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
|
||||
class PublisherACL(object):
|
||||
'''
|
||||
@ -30,7 +35,7 @@ class PublisherACL(object):
|
||||
|
||||
def cmd_is_blacklisted(self, cmd):
|
||||
# If this is a regular command, it is a single function
|
||||
if isinstance(cmd, str):
|
||||
if isinstance(cmd, six.string_types):
|
||||
cmd = [cmd]
|
||||
for fun in cmd:
|
||||
if not salt.utils.check_whitelist_blacklist(fun, blacklist=self.blacklist.get('modules', [])):
|
||||
|
@ -55,7 +55,7 @@ import sys
|
||||
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
# pylint: disable=import-error
|
||||
try:
|
||||
import django
|
||||
|
@ -101,8 +101,8 @@ import logging
|
||||
import os
|
||||
|
||||
# Import salt utils
|
||||
import salt.utils
|
||||
import salt.utils.files
|
||||
import salt.utils.versions
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -200,7 +200,7 @@ def _htpasswd(username, password, **kwargs):
|
||||
pwfile = HtpasswdFile(kwargs['filename'])
|
||||
|
||||
# passlib below version 1.6 uses 'verify' function instead of 'check_password'
|
||||
if salt.utils.version_cmp(kwargs['passlib_version'], '1.6') < 0:
|
||||
if salt.utils.versions.version_cmp(kwargs['passlib_version'], '1.6') < 0:
|
||||
return pwfile.verify(username, password)
|
||||
else:
|
||||
return pwfile.check_password(username, password)
|
||||
@ -222,7 +222,7 @@ def _htdigest(username, password, **kwargs):
|
||||
pwfile = HtdigestFile(kwargs['filename'])
|
||||
|
||||
# passlib below version 1.6 uses 'verify' function instead of 'check_password'
|
||||
if salt.utils.version_cmp(kwargs['passlib_version'], '1.6') < 0:
|
||||
if salt.utils.versions.version_cmp(kwargs['passlib_version'], '1.6') < 0:
|
||||
return pwfile.verify(username, realm, password)
|
||||
else:
|
||||
return pwfile.check_password(username, realm, password)
|
||||
|
@ -8,7 +8,7 @@ Provide authentication using simple LDAP binds
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
|
||||
# Import salt libs
|
||||
from salt.exceptions import CommandExecutionError, SaltInvocationError
|
||||
|
@ -42,11 +42,11 @@ from ctypes import c_void_p, c_uint, c_char_p, c_char, c_int
|
||||
from ctypes.util import find_library
|
||||
|
||||
# Import Salt libs
|
||||
from salt.utils import get_group_list
|
||||
import salt.utils # Can be removed once get_group_list is moved
|
||||
from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
|
||||
LIBPAM = CDLL(find_library('pam'))
|
||||
LIBC = CDLL(find_library('c'))
|
||||
@ -214,4 +214,4 @@ def groups(username, *args, **kwargs):
|
||||
|
||||
Uses system groups
|
||||
'''
|
||||
return get_group_list(username)
|
||||
return salt.utils.get_group_list(username)
|
||||
|
@ -1,71 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Provide authentication using Stormpath.
|
||||
|
||||
This driver requires some extra configuration beyond that which Stormpath
|
||||
normally requires.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
stormpath:
|
||||
apiid: 1234567890
|
||||
apikey: 1234567890/ABCDEF
|
||||
# Can use an application ID
|
||||
application: 6789012345
|
||||
# Or can use a directory ID
|
||||
directory: 3456789012
|
||||
# But not both
|
||||
|
||||
.. versionadded:: 2015.8.0
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import
|
||||
import json
|
||||
import base64
|
||||
import urllib
|
||||
import salt.utils.http
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def auth(username, password):
|
||||
'''
|
||||
Authenticate using a Stormpath directory or application
|
||||
'''
|
||||
apiid = __opts__.get('stormpath', {}).get('apiid', None)
|
||||
apikey = __opts__.get('stormpath', {}).get('apikey', None)
|
||||
application = __opts__.get('stormpath', {}).get('application', None)
|
||||
path = 'https://api.stormpath.com/v1'
|
||||
|
||||
if application is not None:
|
||||
path = '{0}/applications/{1}/loginAttempts'.format(path, application)
|
||||
else:
|
||||
return False
|
||||
|
||||
username = urllib.quote(username)
|
||||
data = {
|
||||
'type': 'basic',
|
||||
'value': base64.b64encode('{0}:{1}'.format(username, password))
|
||||
}
|
||||
log.debug('{0}:{1}'.format(username, password))
|
||||
log.debug(path)
|
||||
log.debug(data)
|
||||
log.debug(json.dumps(data))
|
||||
|
||||
result = salt.utils.http.query(
|
||||
path,
|
||||
method='POST',
|
||||
username=apiid,
|
||||
password=apikey,
|
||||
data=json.dumps(data),
|
||||
header_dict={'Content-type': 'application/json;charset=UTF-8'},
|
||||
decode=False,
|
||||
status=True,
|
||||
opts=__opts__,
|
||||
)
|
||||
log.debug(result)
|
||||
if result.get('status', 403) == 200:
|
||||
return True
|
||||
|
||||
return False
|
@ -37,6 +37,7 @@ class Beacon(object):
|
||||
.. code_block:: yaml
|
||||
beacons:
|
||||
inotify:
|
||||
- files:
|
||||
- /etc/fstab: {}
|
||||
- /var/cache/foo: {}
|
||||
'''
|
||||
@ -69,6 +70,7 @@ class Beacon(object):
|
||||
|
||||
log.trace('Beacon processing: {0}'.format(mod))
|
||||
fun_str = '{0}.beacon'.format(mod)
|
||||
validate_str = '{0}.validate'.format(mod)
|
||||
if fun_str in self.beacons:
|
||||
runonce = self._determine_beacon_config(current_beacon_config, 'run_once')
|
||||
interval = self._determine_beacon_config(current_beacon_config, 'interval')
|
||||
@ -95,6 +97,17 @@ class Beacon(object):
|
||||
continue
|
||||
# Update __grains__ on the beacon
|
||||
self.beacons[fun_str].__globals__['__grains__'] = grains
|
||||
|
||||
# Run the validate function if it's available,
|
||||
# otherwise there is a warning about it being missing
|
||||
if validate_str in self.beacons:
|
||||
valid, vcomment = self.beacons[validate_str](b_config[mod])
|
||||
|
||||
if not valid:
|
||||
log.info('Beacon %s configuration invalid, '
|
||||
'not running.\n%s', mod, vcomment)
|
||||
continue
|
||||
|
||||
# Fire the beacon!
|
||||
raw = self.beacons[fun_str](b_config[mod])
|
||||
for data in raw:
|
||||
@ -193,6 +206,8 @@ class Beacon(object):
|
||||
# Fire the complete event back along with the list of beacons
|
||||
evt = salt.utils.event.get_event('minion', opts=self.opts)
|
||||
b_conf = self.functions['config.merge']('beacons')
|
||||
if not isinstance(self.opts['beacons'], dict):
|
||||
self.opts['beacons'] = {}
|
||||
self.opts['beacons'].update(b_conf)
|
||||
evt.fire_event({'complete': True, 'beacons': self.opts['beacons']},
|
||||
tag='/salt/minion/minion_beacons_list_complete')
|
||||
|
@ -10,7 +10,8 @@ from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
# Salt libs
|
||||
import salt.utils
|
||||
import salt.utils.path
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -21,28 +22,37 @@ last_state_extra = {'value': False, 'no_devices': False}
|
||||
|
||||
|
||||
def __virtual__():
|
||||
which_result = salt.utils.which('adb')
|
||||
which_result = salt.utils.path.which('adb')
|
||||
if which_result is None:
|
||||
return False
|
||||
else:
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for adb beacon should be a dictionary with states array
|
||||
if not isinstance(config, dict):
|
||||
log.info('Configuration for adb beacon must be a dict.')
|
||||
return False, ('Configuration for adb beacon must be a dict.')
|
||||
elif 'states' not in config.keys():
|
||||
if not isinstance(config, list):
|
||||
log.info('Configuration for adb beacon must be a list.')
|
||||
return False, ('Configuration for adb beacon must be a list.')
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'states' not in _config:
|
||||
log.info('Configuration for adb beacon must include a states array.')
|
||||
return False, ('Configuration for adb beacon must include a states array.')
|
||||
else:
|
||||
states = ['offline', 'bootloader', 'device', 'host', 'recovery', 'no permissions',
|
||||
if not isinstance(_config['states'], list):
|
||||
log.info('Configuration for adb beacon must include a states array.')
|
||||
return False, ('Configuration for adb beacon must include a states array.')
|
||||
else:
|
||||
states = ['offline', 'bootloader', 'device', 'host',
|
||||
'recovery', 'no permissions',
|
||||
'sideload', 'unauthorized', 'unknown', 'missing']
|
||||
if any(s not in states for s in config['states']):
|
||||
if any(s not in states for s in _config['states']):
|
||||
log.info('Need a one of the following adb '
|
||||
'states: {0}'.format(', '.join(states)))
|
||||
return False, ('Need a one of the following adb '
|
||||
@ -74,11 +84,10 @@ def beacon(config):
|
||||
log.trace('adb beacon starting')
|
||||
ret = []
|
||||
|
||||
_validate = __validate__(config)
|
||||
if not _validate[0]:
|
||||
return ret
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
out = __salt__['cmd.run']('adb devices', runas=config.get('user', None))
|
||||
out = __salt__['cmd.run']('adb devices', runas=_config.get('user', None))
|
||||
|
||||
lines = out.split('\n')[1:]
|
||||
last_state_devices = list(last_state.keys())
|
||||
@ -90,21 +99,21 @@ def beacon(config):
|
||||
found_devices.append(device)
|
||||
if device not in last_state_devices or \
|
||||
('state' in last_state[device] and last_state[device]['state'] != state):
|
||||
if state in config['states']:
|
||||
if state in _config['states']:
|
||||
ret.append({'device': device, 'state': state, 'tag': state})
|
||||
last_state[device] = {'state': state}
|
||||
|
||||
if 'battery_low' in config:
|
||||
if 'battery_low' in _config:
|
||||
val = last_state.get(device, {})
|
||||
cmd = 'adb -s {0} shell cat /sys/class/power_supply/*/capacity'.format(device)
|
||||
battery_levels = __salt__['cmd.run'](cmd, runas=config.get('user', None)).split('\n')
|
||||
battery_levels = __salt__['cmd.run'](cmd, runas=_config.get('user', None)).split('\n')
|
||||
|
||||
for l in battery_levels:
|
||||
battery_level = int(l)
|
||||
if 0 < battery_level < 100:
|
||||
if 'battery' not in val or battery_level != val['battery']:
|
||||
if ('battery' not in val or val['battery'] > config['battery_low']) and \
|
||||
battery_level <= config['battery_low']:
|
||||
if ('battery' not in val or val['battery'] > _config['battery_low']) and \
|
||||
battery_level <= _config['battery_low']:
|
||||
ret.append({'device': device, 'battery_level': battery_level, 'tag': 'battery_low'})
|
||||
|
||||
if device not in last_state:
|
||||
@ -118,13 +127,13 @@ def beacon(config):
|
||||
# Find missing devices and remove them / send an event
|
||||
for device in last_state_devices:
|
||||
if device not in found_devices:
|
||||
if 'missing' in config['states']:
|
||||
if 'missing' in _config['states']:
|
||||
ret.append({'device': device, 'state': 'missing', 'tag': 'missing'})
|
||||
|
||||
del last_state[device]
|
||||
|
||||
# Maybe send an event if we don't have any devices
|
||||
if 'no_devices_event' in config and config['no_devices_event'] is True:
|
||||
if 'no_devices_event' in _config and _config['no_devices_event'] is True:
|
||||
if len(found_devices) == 0 and not last_state_extra['no_devices']:
|
||||
ret.append({'tag': 'no_devices'})
|
||||
|
||||
|
@ -15,6 +15,7 @@ Dependencies
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
import time
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# Import 3rd Party libs
|
||||
try:
|
||||
@ -54,17 +55,23 @@ def __virtual__():
|
||||
'\'python-avahi\' dependency is missing.'.format(__virtualname__)
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for avahi_announcement '
|
||||
'beacon must be a dictionary')
|
||||
elif not all(x in list(config.keys()) for x in ('servicetype', 'port', 'txt')):
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for avahi_announce '
|
||||
'beacon must be a list.')
|
||||
|
||||
elif not all(x in _config for x in ('servicetype',
|
||||
'port',
|
||||
'txt')):
|
||||
return False, ('Configuration for avahi_announce beacon '
|
||||
'must contain servicetype, port and txt items')
|
||||
return True, 'Valid beacon configuration'
|
||||
'must contain servicetype, port and txt items.')
|
||||
return True, 'Valid beacon configuration.'
|
||||
|
||||
|
||||
def _enforce_txt_record_maxlen(key, value):
|
||||
@ -138,10 +145,10 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
avahi_announce:
|
||||
run_once: True
|
||||
servicetype: _demo._tcp
|
||||
port: 1234
|
||||
txt:
|
||||
- run_once: True
|
||||
- servicetype: _demo._tcp
|
||||
- port: 1234
|
||||
- txt:
|
||||
ProdName: grains.productname
|
||||
SerialNo: grains.serialnumber
|
||||
Comments: 'this is a test'
|
||||
@ -152,30 +159,27 @@ def beacon(config):
|
||||
|
||||
global LAST_GRAINS
|
||||
|
||||
_validate = __validate__(config)
|
||||
if not _validate[0]:
|
||||
log.warning('Beacon {0} configuration invalid, '
|
||||
'not adding. {1}'.format(__virtualname__, _validate[1]))
|
||||
return ret
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'servicename' in config:
|
||||
servicename = config['servicename']
|
||||
if 'servicename' in _config:
|
||||
servicename = _config['servicename']
|
||||
else:
|
||||
servicename = __grains__['host']
|
||||
# Check for hostname change
|
||||
if LAST_GRAINS and LAST_GRAINS['host'] != servicename:
|
||||
changes['servicename'] = servicename
|
||||
|
||||
if LAST_GRAINS and config.get('reset_on_change', False):
|
||||
if LAST_GRAINS and _config.get('reset_on_change', False):
|
||||
# Check for IP address change in the case when we reset on change
|
||||
if LAST_GRAINS.get('ipv4', []) != __grains__.get('ipv4', []):
|
||||
changes['ipv4'] = __grains__.get('ipv4', [])
|
||||
if LAST_GRAINS.get('ipv6', []) != __grains__.get('ipv6', []):
|
||||
changes['ipv6'] = __grains__.get('ipv6', [])
|
||||
|
||||
for item in config['txt']:
|
||||
if config['txt'][item].startswith('grains.'):
|
||||
grain = config['txt'][item][7:]
|
||||
for item in _config['txt']:
|
||||
if _config['txt'][item].startswith('grains.'):
|
||||
grain = _config['txt'][item][7:]
|
||||
grain_index = None
|
||||
square_bracket = grain.find('[')
|
||||
if square_bracket != -1 and grain[-1] == ']':
|
||||
@ -192,7 +196,7 @@ def beacon(config):
|
||||
if LAST_GRAINS and (LAST_GRAINS.get(grain, '') != __grains__.get(grain, '')):
|
||||
changes[str('txt.' + item)] = txt[item]
|
||||
else:
|
||||
txt[item] = _enforce_txt_record_maxlen(item, config['txt'][item])
|
||||
txt[item] = _enforce_txt_record_maxlen(item, _config['txt'][item])
|
||||
|
||||
if not LAST_GRAINS:
|
||||
changes[str('txt.' + item)] = txt[item]
|
||||
@ -200,33 +204,33 @@ def beacon(config):
|
||||
if changes:
|
||||
if not LAST_GRAINS:
|
||||
changes['servicename'] = servicename
|
||||
changes['servicetype'] = config['servicetype']
|
||||
changes['port'] = config['port']
|
||||
changes['servicetype'] = _config['servicetype']
|
||||
changes['port'] = _config['port']
|
||||
changes['ipv4'] = __grains__.get('ipv4', [])
|
||||
changes['ipv6'] = __grains__.get('ipv6', [])
|
||||
GROUP.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, dbus.UInt32(0),
|
||||
servicename, config['servicetype'], '', '',
|
||||
dbus.UInt16(config['port']), avahi.dict_to_txt_array(txt))
|
||||
servicename, _config['servicetype'], '', '',
|
||||
dbus.UInt16(_config['port']), avahi.dict_to_txt_array(txt))
|
||||
GROUP.Commit()
|
||||
elif config.get('reset_on_change', False) or 'servicename' in changes:
|
||||
elif _config.get('reset_on_change', False) or 'servicename' in changes:
|
||||
# A change in 'servicename' requires a reset because we can only
|
||||
# directly update TXT records
|
||||
GROUP.Reset()
|
||||
reset_wait = config.get('reset_wait', 0)
|
||||
reset_wait = _config.get('reset_wait', 0)
|
||||
if reset_wait > 0:
|
||||
time.sleep(reset_wait)
|
||||
GROUP.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, dbus.UInt32(0),
|
||||
servicename, config['servicetype'], '', '',
|
||||
dbus.UInt16(config['port']), avahi.dict_to_txt_array(txt))
|
||||
servicename, _config['servicetype'], '', '',
|
||||
dbus.UInt16(_config['port']), avahi.dict_to_txt_array(txt))
|
||||
GROUP.Commit()
|
||||
else:
|
||||
GROUP.UpdateServiceTxt(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, dbus.UInt32(0),
|
||||
servicename, config['servicetype'], '',
|
||||
servicename, _config['servicetype'], '',
|
||||
avahi.dict_to_txt_array(txt))
|
||||
|
||||
ret.append({'tag': 'result', 'changes': changes})
|
||||
|
||||
if config.get('copy_grains', False):
|
||||
if _config.get('copy_grains', False):
|
||||
LAST_GRAINS = __grains__.copy()
|
||||
else:
|
||||
LAST_GRAINS = __grains__
|
||||
|
@ -9,6 +9,7 @@ import atexit
|
||||
import logging
|
||||
import select
|
||||
import time
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# Import 3rd Party libs
|
||||
try:
|
||||
@ -47,17 +48,23 @@ def _register_callback(sdRef, flags, errorCode, name, regtype, domain): # pylin
|
||||
log.error('Bonjour registration failed with error code {0}'.format(errorCode))
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for bonjour_announcement '
|
||||
'beacon must be a dictionary')
|
||||
elif not all(x in list(config.keys()) for x in ('servicetype', 'port', 'txt')):
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for bonjour_announce '
|
||||
'beacon must be a list.')
|
||||
|
||||
elif not all(x in _config for x in ('servicetype',
|
||||
'port',
|
||||
'txt')):
|
||||
return False, ('Configuration for bonjour_announce beacon '
|
||||
'must contain servicetype, port and txt items')
|
||||
return True, 'Valid beacon configuration'
|
||||
'must contain servicetype, port and txt items.')
|
||||
return True, 'Valid beacon configuration.'
|
||||
|
||||
|
||||
def _enforce_txt_record_maxlen(key, value):
|
||||
@ -131,10 +138,10 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
bonjour_announce:
|
||||
run_once: True
|
||||
servicetype: _demo._tcp
|
||||
port: 1234
|
||||
txt:
|
||||
- run_once: True
|
||||
- servicetype: _demo._tcp
|
||||
- port: 1234
|
||||
- txt:
|
||||
ProdName: grains.productname
|
||||
SerialNo: grains.serialnumber
|
||||
Comments: 'this is a test'
|
||||
@ -146,30 +153,27 @@ def beacon(config):
|
||||
global LAST_GRAINS
|
||||
global SD_REF
|
||||
|
||||
_validate = __validate__(config)
|
||||
if not _validate[0]:
|
||||
log.warning('Beacon {0} configuration invalid, '
|
||||
'not adding. {1}'.format(__virtualname__, _validate[1]))
|
||||
return ret
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'servicename' in config:
|
||||
servicename = config['servicename']
|
||||
if 'servicename' in _config:
|
||||
servicename = _config['servicename']
|
||||
else:
|
||||
servicename = __grains__['host']
|
||||
# Check for hostname change
|
||||
if LAST_GRAINS and LAST_GRAINS['host'] != servicename:
|
||||
changes['servicename'] = servicename
|
||||
|
||||
if LAST_GRAINS and config.get('reset_on_change', False):
|
||||
if LAST_GRAINS and _config.get('reset_on_change', False):
|
||||
# Check for IP address change in the case when we reset on change
|
||||
if LAST_GRAINS.get('ipv4', []) != __grains__.get('ipv4', []):
|
||||
changes['ipv4'] = __grains__.get('ipv4', [])
|
||||
if LAST_GRAINS.get('ipv6', []) != __grains__.get('ipv6', []):
|
||||
changes['ipv6'] = __grains__.get('ipv6', [])
|
||||
|
||||
for item in config['txt']:
|
||||
if config['txt'][item].startswith('grains.'):
|
||||
grain = config['txt'][item][7:]
|
||||
for item in _config['txt']:
|
||||
if _config['txt'][item].startswith('grains.'):
|
||||
grain = _config['txt'][item][7:]
|
||||
grain_index = None
|
||||
square_bracket = grain.find('[')
|
||||
if square_bracket != -1 and grain[-1] == ']':
|
||||
@ -186,7 +190,7 @@ def beacon(config):
|
||||
if LAST_GRAINS and (LAST_GRAINS.get(grain, '') != __grains__.get(grain, '')):
|
||||
changes[str('txt.' + item)] = txt[item]
|
||||
else:
|
||||
txt[item] = _enforce_txt_record_maxlen(item, config['txt'][item])
|
||||
txt[item] = _enforce_txt_record_maxlen(item, _config['txt'][item])
|
||||
|
||||
if not LAST_GRAINS:
|
||||
changes[str('txt.' + item)] = txt[item]
|
||||
@ -195,32 +199,32 @@ def beacon(config):
|
||||
txt_record = pybonjour.TXTRecord(items=txt)
|
||||
if not LAST_GRAINS:
|
||||
changes['servicename'] = servicename
|
||||
changes['servicetype'] = config['servicetype']
|
||||
changes['port'] = config['port']
|
||||
changes['servicetype'] = _config['servicetype']
|
||||
changes['port'] = _config['port']
|
||||
changes['ipv4'] = __grains__.get('ipv4', [])
|
||||
changes['ipv6'] = __grains__.get('ipv6', [])
|
||||
SD_REF = pybonjour.DNSServiceRegister(
|
||||
name=servicename,
|
||||
regtype=config['servicetype'],
|
||||
port=config['port'],
|
||||
regtype=_config['servicetype'],
|
||||
port=_config['port'],
|
||||
txtRecord=txt_record,
|
||||
callBack=_register_callback)
|
||||
atexit.register(_close_sd_ref)
|
||||
ready = select.select([SD_REF], [], [])
|
||||
if SD_REF in ready[0]:
|
||||
pybonjour.DNSServiceProcessResult(SD_REF)
|
||||
elif config.get('reset_on_change', False) or 'servicename' in changes:
|
||||
elif _config.get('reset_on_change', False) or 'servicename' in changes:
|
||||
# A change in 'servicename' requires a reset because we can only
|
||||
# directly update TXT records
|
||||
SD_REF.close()
|
||||
SD_REF = None
|
||||
reset_wait = config.get('reset_wait', 0)
|
||||
reset_wait = _config.get('reset_wait', 0)
|
||||
if reset_wait > 0:
|
||||
time.sleep(reset_wait)
|
||||
SD_REF = pybonjour.DNSServiceRegister(
|
||||
name=servicename,
|
||||
regtype=config['servicetype'],
|
||||
port=config['port'],
|
||||
regtype=_config['servicetype'],
|
||||
port=_config['port'],
|
||||
txtRecord=txt_record,
|
||||
callBack=_register_callback)
|
||||
ready = select.select([SD_REF], [], [])
|
||||
@ -236,7 +240,7 @@ def beacon(config):
|
||||
|
||||
ret.append({'tag': 'result', 'changes': changes})
|
||||
|
||||
if config.get('copy_grains', False):
|
||||
if _config.get('copy_grains', False):
|
||||
LAST_GRAINS = __grains__.copy()
|
||||
else:
|
||||
LAST_GRAINS = __grains__
|
||||
|
@ -5,7 +5,7 @@ Beacon to fire events at failed login of users
|
||||
.. code-block:: yaml
|
||||
|
||||
beacons:
|
||||
btmp: {}
|
||||
btmp: []
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
@ -16,6 +16,9 @@ import struct
|
||||
# Import Salt Libs
|
||||
import salt.utils.files
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
__virtualname__ = 'btmp'
|
||||
BTMP = '/var/log/btmp'
|
||||
FMT = 'hi32s4s32s256shhiii4i20x'
|
||||
@ -49,14 +52,14 @@ def _get_loc():
|
||||
return __context__[LOC_KEY]
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for load beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for btmp beacon must '
|
||||
'be a list of dictionaries.')
|
||||
'be a list.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -68,7 +71,7 @@ def beacon(config):
|
||||
.. code-block:: yaml
|
||||
|
||||
beacons:
|
||||
btmp: {}
|
||||
btmp: []
|
||||
'''
|
||||
ret = []
|
||||
with salt.utils.files.fopen(BTMP, 'rb') as fp_:
|
||||
@ -88,7 +91,7 @@ def beacon(config):
|
||||
event = {}
|
||||
for ind, field in enumerate(FIELDS):
|
||||
event[field] = pack[ind]
|
||||
if isinstance(event[field], str):
|
||||
if isinstance(event[field], six.string_types):
|
||||
event[field] = event[field].strip('\x00')
|
||||
ret.append(event)
|
||||
return ret
|
||||
|
@ -31,14 +31,14 @@ def __virtual__():
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for diskusage beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for diskusage beacon '
|
||||
'must be a dictionary.')
|
||||
'must be a list.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -86,25 +86,24 @@ def beacon(config):
|
||||
parts = psutil.disk_partitions(all=False)
|
||||
ret = []
|
||||
for mounts in config:
|
||||
mount = mounts.keys()[0]
|
||||
mount = next(iter(mounts))
|
||||
|
||||
for part in parts:
|
||||
if re.match(mount, part.mountpoint):
|
||||
_mount = part.mountpoint
|
||||
|
||||
try:
|
||||
_current_usage = psutil.disk_usage(mount)
|
||||
except OSError:
|
||||
# Ensure a valid mount point
|
||||
log.warning('{0} is not a valid mount point, try regex.'.format(mount))
|
||||
for part in parts:
|
||||
if re.match(mount, part.mountpoint):
|
||||
row = {}
|
||||
row[part.mountpoint] = mounts[mount]
|
||||
config.append(row)
|
||||
log.warning('{0} is not a valid mount point.'.format(mount))
|
||||
continue
|
||||
|
||||
current_usage = _current_usage.percent
|
||||
monitor_usage = mounts[mount]
|
||||
log.info('current_usage {}'.format(current_usage))
|
||||
if '%' in monitor_usage:
|
||||
monitor_usage = re.sub('%', '', monitor_usage)
|
||||
monitor_usage = float(monitor_usage)
|
||||
if current_usage >= monitor_usage:
|
||||
ret.append({'diskusage': current_usage, 'mount': mount})
|
||||
ret.append({'diskusage': current_usage, 'mount': _mount})
|
||||
return ret
|
||||
|
@ -10,7 +10,8 @@ from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
# Salt libs
|
||||
import salt.utils
|
||||
import salt.utils.path
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -21,21 +22,25 @@ last_state = {}
|
||||
|
||||
def __virtual__():
|
||||
|
||||
which_result = salt.utils.which('glxinfo')
|
||||
which_result = salt.utils.path.which('glxinfo')
|
||||
if which_result is None:
|
||||
return False
|
||||
else:
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for glxinfo beacon should be a dictionary
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for glxinfo beacon must be a dict.')
|
||||
if 'user' not in config:
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for glxinfo beacon must be a list.')
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'user' not in _config:
|
||||
return False, ('Configuration for glxinfo beacon must '
|
||||
'include a user as glxinfo is not available to root.')
|
||||
return True, 'Valid beacon configuration'
|
||||
@ -45,27 +50,28 @@ def beacon(config):
|
||||
'''
|
||||
Emit the status of a connected display to the minion
|
||||
|
||||
Mainly this is used to detect when the display fails to connect for whatever reason.
|
||||
Mainly this is used to detect when the display fails to connect
|
||||
for whatever reason.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
beacons:
|
||||
glxinfo:
|
||||
user: frank
|
||||
screen_event: True
|
||||
- user: frank
|
||||
- screen_event: True
|
||||
|
||||
'''
|
||||
|
||||
log.trace('glxinfo beacon starting')
|
||||
ret = []
|
||||
|
||||
_validate = __validate__(config)
|
||||
if not _validate[0]:
|
||||
return ret
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
retcode = __salt__['cmd.retcode']('DISPLAY=:0 glxinfo', runas=config['user'], python_shell=True)
|
||||
retcode = __salt__['cmd.retcode']('DISPLAY=:0 glxinfo',
|
||||
runas=_config['user'], python_shell=True)
|
||||
|
||||
if 'screen_event' in config and config['screen_event']:
|
||||
if 'screen_event' in _config and _config['screen_event']:
|
||||
last_value = last_state.get('screen_available', False)
|
||||
screen_available = retcode == 0
|
||||
if last_value != screen_available or 'screen_available' not in last_state:
|
||||
|
@ -9,7 +9,7 @@ Fire an event when over a specified threshold.
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -23,17 +23,39 @@ def __virtual__():
|
||||
if 'haproxy.get_sessions' in __salt__:
|
||||
return __virtualname__
|
||||
else:
|
||||
log.debug('Not loading haproxy beacon')
|
||||
return False
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for haproxy beacon must be a dictionary.')
|
||||
if 'haproxy' not in config:
|
||||
return False, ('Configuration for haproxy beacon requires a list of backends and servers')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for haproxy beacon must '
|
||||
'be a list.')
|
||||
else:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'backends' not in _config:
|
||||
return False, ('Configuration for haproxy beacon '
|
||||
'requires backends.')
|
||||
else:
|
||||
if not isinstance(_config['backends'], dict):
|
||||
return False, ('Backends for haproxy beacon '
|
||||
'must be a dictionary.')
|
||||
else:
|
||||
for backend in _config['backends']:
|
||||
log.debug('_config {}'.format(_config['backends'][backend]))
|
||||
if 'servers' not in _config['backends'][backend]:
|
||||
return False, ('Backends for haproxy beacon '
|
||||
'require servers.')
|
||||
else:
|
||||
_servers = _config['backends'][backend]['servers']
|
||||
if not isinstance(_servers, list):
|
||||
return False, ('Servers for haproxy beacon '
|
||||
'must be a list.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -46,22 +68,23 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
haproxy:
|
||||
- www-backend:
|
||||
- backends:
|
||||
www-backend:
|
||||
threshold: 45
|
||||
servers:
|
||||
- web1
|
||||
- web2
|
||||
- interval: 120
|
||||
'''
|
||||
log.debug('haproxy beacon starting')
|
||||
ret = []
|
||||
_validate = __validate__(config)
|
||||
if not _validate:
|
||||
log.debug('haproxy beacon unable to validate')
|
||||
return ret
|
||||
for backend in config:
|
||||
threshold = config[backend]['threshold']
|
||||
for server in config[backend]['servers']:
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
for backend in _config.get('backends', ()):
|
||||
backend_config = _config['backends'][backend]
|
||||
threshold = backend_config['threshold']
|
||||
for server in backend_config['servers']:
|
||||
scur = __salt__['haproxy.get_sessions'](server, backend)
|
||||
if scur:
|
||||
if int(scur) > int(threshold):
|
||||
@ -69,6 +92,10 @@ def beacon(config):
|
||||
'scur': scur,
|
||||
'threshold': threshold,
|
||||
}
|
||||
log.debug('Emit because {0} > {1} for {2} in {3}'.format(scur, threshold, server, backend))
|
||||
log.debug('Emit because {0} > {1}'
|
||||
' for {2} in {3}'.format(scur,
|
||||
threshold,
|
||||
server,
|
||||
backend))
|
||||
ret.append(_server)
|
||||
return ret
|
||||
|
@ -23,6 +23,7 @@ import re
|
||||
|
||||
# Import salt libs
|
||||
import salt.ext.six
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
@ -79,7 +80,7 @@ def _get_notifier(config):
|
||||
return __context__['inotify.notifier']
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
@ -105,34 +106,42 @@ def __validate__(config):
|
||||
]
|
||||
|
||||
# Configuration for inotify beacon should be a dict of dicts
|
||||
log.debug('config {0}'.format(config))
|
||||
if not isinstance(config, dict):
|
||||
return False, 'Configuration for inotify beacon must be a dictionary.'
|
||||
if not isinstance(config, list):
|
||||
return False, 'Configuration for inotify beacon must be a list.'
|
||||
else:
|
||||
for config_item in config:
|
||||
if not isinstance(config[config_item], dict):
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'files' not in _config:
|
||||
return False, 'Configuration for inotify beacon must include files.'
|
||||
else:
|
||||
for path in _config.get('files'):
|
||||
|
||||
if not isinstance(_config['files'][path], dict):
|
||||
return False, ('Configuration for inotify beacon must '
|
||||
'be a dictionary of dictionaries.')
|
||||
'be a list of dictionaries.')
|
||||
else:
|
||||
if not any(j in ['mask', 'recurse', 'auto_add'] for j in config[config_item]):
|
||||
if not any(j in ['mask',
|
||||
'recurse',
|
||||
'auto_add'] for j in _config['files'][path]):
|
||||
return False, ('Configuration for inotify beacon must '
|
||||
'contain mask, recurse or auto_add items.')
|
||||
|
||||
if 'auto_add' in config[config_item]:
|
||||
if not isinstance(config[config_item]['auto_add'], bool):
|
||||
if 'auto_add' in _config['files'][path]:
|
||||
if not isinstance(_config['files'][path]['auto_add'], bool):
|
||||
return False, ('Configuration for inotify beacon '
|
||||
'auto_add must be boolean.')
|
||||
|
||||
if 'recurse' in config[config_item]:
|
||||
if not isinstance(config[config_item]['recurse'], bool):
|
||||
if 'recurse' in _config['files'][path]:
|
||||
if not isinstance(_config['files'][path]['recurse'], bool):
|
||||
return False, ('Configuration for inotify beacon '
|
||||
'recurse must be boolean.')
|
||||
|
||||
if 'mask' in config[config_item]:
|
||||
if not isinstance(config[config_item]['mask'], list):
|
||||
if 'mask' in _config['files'][path]:
|
||||
if not isinstance(_config['files'][path]['mask'], list):
|
||||
return False, ('Configuration for inotify beacon '
|
||||
'mask must be list.')
|
||||
for mask in config[config_item]['mask']:
|
||||
for mask in _config['files'][path]['mask']:
|
||||
if mask not in VALID_MASK:
|
||||
return False, ('Configuration for inotify beacon '
|
||||
'invalid mask option {0}.'.format(mask))
|
||||
@ -149,6 +158,7 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
inotify:
|
||||
- files:
|
||||
/path/to/file/or/dir:
|
||||
mask:
|
||||
- open
|
||||
@ -161,7 +171,7 @@ def beacon(config):
|
||||
- /path/to/file/or/dir/exclude2
|
||||
- /path/to/file/or/dir/regex[a-m]*$:
|
||||
regex: True
|
||||
coalesce: True
|
||||
- coalesce: True
|
||||
|
||||
The mask list can contain the following events (the default mask is create,
|
||||
delete, and modify):
|
||||
@ -203,8 +213,11 @@ def beacon(config):
|
||||
affects all paths that are being watched. This is due to this option
|
||||
being at the Notifier level in pyinotify.
|
||||
'''
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
ret = []
|
||||
notifier = _get_notifier(config)
|
||||
notifier = _get_notifier(_config)
|
||||
wm = notifier._watch_manager
|
||||
|
||||
# Read in existing events
|
||||
@ -219,11 +232,13 @@ def beacon(config):
|
||||
# Find the matching path in config
|
||||
path = event.path
|
||||
while path != '/':
|
||||
if path in config:
|
||||
if path in _config.get('files', {}):
|
||||
break
|
||||
path = os.path.dirname(path)
|
||||
|
||||
excludes = config[path].get('exclude', '')
|
||||
for path in _config.get('files', {}):
|
||||
excludes = _config['files'][path].get('exclude', '')
|
||||
|
||||
if excludes and isinstance(excludes, list):
|
||||
for exclude in excludes:
|
||||
if isinstance(exclude, dict):
|
||||
@ -257,9 +272,10 @@ def beacon(config):
|
||||
|
||||
# Update existing watches and add new ones
|
||||
# TODO: make the config handle more options
|
||||
for path in config:
|
||||
if isinstance(config[path], dict):
|
||||
mask = config[path].get('mask', DEFAULT_MASK)
|
||||
for path in _config.get('files', ()):
|
||||
|
||||
if isinstance(_config['files'][path], dict):
|
||||
mask = _config['files'][path].get('mask', DEFAULT_MASK)
|
||||
if isinstance(mask, list):
|
||||
r_mask = 0
|
||||
for sub in mask:
|
||||
@ -269,8 +285,8 @@ def beacon(config):
|
||||
else:
|
||||
r_mask = mask
|
||||
mask = r_mask
|
||||
rec = config[path].get('recurse', False)
|
||||
auto_add = config[path].get('auto_add', False)
|
||||
rec = _config['files'][path].get('recurse', False)
|
||||
auto_add = _config['files'][path].get('auto_add', False)
|
||||
else:
|
||||
mask = DEFAULT_MASK
|
||||
rec = False
|
||||
@ -287,7 +303,7 @@ def beacon(config):
|
||||
if update:
|
||||
wm.update_watch(wd, mask=mask, rec=rec, auto_add=auto_add)
|
||||
elif os.path.exists(path):
|
||||
excludes = config[path].get('exclude', '')
|
||||
excludes = _config['files'][path].get('exclude', '')
|
||||
excl = None
|
||||
if isinstance(excludes, list):
|
||||
excl = []
|
||||
|
@ -10,6 +10,7 @@ from __future__ import absolute_import
|
||||
import salt.utils
|
||||
import salt.utils.locales
|
||||
import salt.ext.six
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
@ -43,18 +44,21 @@ def _get_journal():
|
||||
return __context__['systemd.journald']
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for journald beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
return False
|
||||
if not isinstance(config, list):
|
||||
return (False, 'Configuration for journald beacon must be a list.')
|
||||
else:
|
||||
for item in config:
|
||||
if not isinstance(config[item], dict):
|
||||
return False, ('Configuration for journald beacon must '
|
||||
'be a dictionary of dictionaries.')
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
for name in _config.get('services', {}):
|
||||
if not isinstance(_config['services'][name], dict):
|
||||
return False, ('Services configuration for journald beacon '
|
||||
'must be a list of dictionaries.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -69,25 +73,31 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
journald:
|
||||
- services:
|
||||
sshd:
|
||||
SYSLOG_IDENTIFIER: sshd
|
||||
PRIORITY: 6
|
||||
'''
|
||||
ret = []
|
||||
journal = _get_journal()
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
while True:
|
||||
cur = journal.get_next()
|
||||
if not cur:
|
||||
break
|
||||
for name in config:
|
||||
|
||||
for name in _config.get('services', {}):
|
||||
n_flag = 0
|
||||
for key in config[name]:
|
||||
for key in _config['services'][name]:
|
||||
if isinstance(key, salt.ext.six.string_types):
|
||||
key = salt.utils.locales.sdecode(key)
|
||||
if key in cur:
|
||||
if config[name][key] == cur[key]:
|
||||
if _config['services'][name][key] == cur[key]:
|
||||
n_flag += 1
|
||||
if n_flag == len(config[name]):
|
||||
if n_flag == len(_config['services'][name]):
|
||||
# Match!
|
||||
sub = salt.utils.simple_types_filter(cur)
|
||||
sub.update({'tag': name})
|
||||
|
@ -9,7 +9,8 @@ import logging
|
||||
import os
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils
|
||||
import salt.utils.platform
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# Import Py3 compat
|
||||
from salt.ext.six.moves import zip
|
||||
@ -22,13 +23,13 @@ LAST_STATUS = {}
|
||||
|
||||
|
||||
def __virtual__():
|
||||
if salt.utils.is_windows():
|
||||
if salt.utils.platform.is_windows():
|
||||
return False
|
||||
else:
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
@ -37,25 +38,26 @@ def __validate__(config):
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for load beacon must be a list.')
|
||||
else:
|
||||
for config_item in config:
|
||||
if not isinstance(config_item, dict):
|
||||
return False, ('Configuration for load beacon must '
|
||||
'be a list of dictionaries.')
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'averages' not in _config:
|
||||
return False, ('Averages configuration is required'
|
||||
' for load beacon.')
|
||||
else:
|
||||
if not all(j in ['1m', '5m', '15m'] for j in config_item.keys()):
|
||||
return False, ('Configuration for load beacon must '
|
||||
'contain 1m, 5m or 15m items.')
|
||||
|
||||
if not any(j in ['1m', '5m', '15m'] for j
|
||||
in _config.get('averages', {})):
|
||||
return False, ('Averages configuration for load beacon '
|
||||
'must contain 1m, 5m or 15m items.')
|
||||
|
||||
for item in ['1m', '5m', '15m']:
|
||||
if item not in config_item:
|
||||
continue
|
||||
|
||||
if not isinstance(config_item[item], list):
|
||||
return False, ('Configuration for load beacon: '
|
||||
if not isinstance(_config['averages'][item], list):
|
||||
return False, ('Averages configuration for load beacon: '
|
||||
'1m, 5m and 15m items must be '
|
||||
'a list of two items.')
|
||||
else:
|
||||
if len(config_item[item]) != 2:
|
||||
if len(_config['averages'][item]) != 2:
|
||||
return False, ('Configuration for load beacon: '
|
||||
'1m, 5m and 15m items must be '
|
||||
'a list of two items.')
|
||||
@ -82,6 +84,7 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
load:
|
||||
- averages:
|
||||
1m:
|
||||
- 0.0
|
||||
- 2.0
|
||||
@ -91,24 +94,27 @@ def beacon(config):
|
||||
15m:
|
||||
- 0.1
|
||||
- 1.0
|
||||
emitatstartup: True
|
||||
onchangeonly: False
|
||||
- emitatstartup: True
|
||||
- onchangeonly: False
|
||||
|
||||
'''
|
||||
log.trace('load beacon starting')
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
# Default config if not present
|
||||
if 'emitatstartup' not in config:
|
||||
config['emitatstartup'] = True
|
||||
if 'onchangeonly' not in config:
|
||||
config['onchangeonly'] = False
|
||||
if 'emitatstartup' not in _config:
|
||||
_config['emitatstartup'] = True
|
||||
if 'onchangeonly' not in _config:
|
||||
_config['onchangeonly'] = False
|
||||
|
||||
ret = []
|
||||
avgs = os.getloadavg()
|
||||
avg_keys = ['1m', '5m', '15m']
|
||||
avg_dict = dict(zip(avg_keys, avgs))
|
||||
|
||||
if config['onchangeonly']:
|
||||
if _config['onchangeonly']:
|
||||
if not LAST_STATUS:
|
||||
for k in ['1m', '5m', '15m']:
|
||||
LAST_STATUS[k] = avg_dict[k]
|
||||
@ -120,27 +126,40 @@ def beacon(config):
|
||||
|
||||
# Check each entry for threshold
|
||||
for k in ['1m', '5m', '15m']:
|
||||
if k in config:
|
||||
if config['onchangeonly']:
|
||||
# Emit if current is more that threshold and old value less that threshold
|
||||
if float(avg_dict[k]) > float(config[k][1]) and float(LAST_STATUS[k]) < float(config[k][1]):
|
||||
log.debug('Emit because {0} > {1} and last was {2}'.format(float(avg_dict[k]), float(config[k][1]), float(LAST_STATUS[k])))
|
||||
if k in _config.get('averages', {}):
|
||||
if _config['onchangeonly']:
|
||||
# Emit if current is more that threshold and old value less
|
||||
# that threshold
|
||||
if float(avg_dict[k]) > float(_config['averages'][k][1]) and \
|
||||
float(LAST_STATUS[k]) < float(_config['averages'][k][1]):
|
||||
log.debug('Emit because {0} > {1} and last was '
|
||||
'{2}'.format(float(avg_dict[k]),
|
||||
float(_config['averages'][k][1]),
|
||||
float(LAST_STATUS[k])))
|
||||
send_beacon = True
|
||||
break
|
||||
# Emit if current is less that threshold and old value more that threshold
|
||||
if float(avg_dict[k]) < float(config[k][0]) and float(LAST_STATUS[k]) > float(config[k][0]):
|
||||
log.debug('Emit because {0} < {1} and last was {2}'.format(float(avg_dict[k]), float(config[k][0]), float(LAST_STATUS[k])))
|
||||
# Emit if current is less that threshold and old value more
|
||||
# that threshold
|
||||
if float(avg_dict[k]) < float(_config['averages'][k][0]) and \
|
||||
float(LAST_STATUS[k]) > float(_config['averages'][k][0]):
|
||||
log.debug('Emit because {0} < {1} and last was'
|
||||
'{2}'.format(float(avg_dict[k]),
|
||||
float(_config['averages'][k][0]),
|
||||
float(LAST_STATUS[k])))
|
||||
send_beacon = True
|
||||
break
|
||||
else:
|
||||
# Emit no matter LAST_STATUS
|
||||
if float(avg_dict[k]) < float(config[k][0]) or \
|
||||
float(avg_dict[k]) > float(config[k][1]):
|
||||
log.debug('Emit because {0} < {1} or > {2}'.format(float(avg_dict[k]), float(config[k][0]), float(config[k][1])))
|
||||
if float(avg_dict[k]) < float(_config['averages'][k][0]) or \
|
||||
float(avg_dict[k]) > float(_config['averages'][k][1]):
|
||||
log.debug('Emit because {0} < {1} or > '
|
||||
'{2}'.format(float(avg_dict[k]),
|
||||
float(_config['averages'][k][0]),
|
||||
float(_config['averages'][k][1])))
|
||||
send_beacon = True
|
||||
break
|
||||
|
||||
if config['onchangeonly']:
|
||||
if _config['onchangeonly']:
|
||||
for k in ['1m', '5m', '15m']:
|
||||
LAST_STATUS[k] = avg_dict[k]
|
||||
|
||||
|
@ -11,8 +11,9 @@ from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.files
|
||||
import salt.utils.platform
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
|
||||
try:
|
||||
@ -35,7 +36,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __virtual__():
|
||||
if not salt.utils.is_windows() and HAS_REGEX:
|
||||
if not salt.utils.platform.is_windows() and HAS_REGEX:
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
@ -48,13 +49,20 @@ def _get_loc():
|
||||
return __context__[LOC_KEY]
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
# Configuration for log beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for log beacon must be a dictionary.')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for log beacon must be a list.')
|
||||
|
||||
if 'file' not in _config:
|
||||
return False, ('Configuration for log beacon '
|
||||
'must contain file option.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -67,20 +75,24 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
log:
|
||||
file: <path>
|
||||
- file: <path>
|
||||
- tags:
|
||||
<tag>:
|
||||
regex: <pattern>
|
||||
'''
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
ret = []
|
||||
|
||||
if 'file' not in config:
|
||||
if 'file' not in _config:
|
||||
event = SKEL.copy()
|
||||
event['tag'] = 'global'
|
||||
event['error'] = 'file not defined in config'
|
||||
ret.append(event)
|
||||
return ret
|
||||
|
||||
with salt.utils.files.fopen(config['file'], 'r') as fp_:
|
||||
with salt.utils.files.fopen(_config['file'], 'r') as fp_:
|
||||
loc = __context__.get(LOC_KEY, 0)
|
||||
if loc == 0:
|
||||
fp_.seek(0, 2)
|
||||
@ -92,16 +104,17 @@ def beacon(config):
|
||||
fp_.seek(loc)
|
||||
|
||||
txt = fp_.read()
|
||||
log.info('txt {}'.format(txt))
|
||||
|
||||
d = {}
|
||||
for tag in config:
|
||||
if 'regex' not in config[tag]:
|
||||
for tag in _config.get('tags', {}):
|
||||
if 'regex' not in _config['tags'][tag]:
|
||||
continue
|
||||
if len(config[tag]['regex']) < 1:
|
||||
if len(_config['tags'][tag]['regex']) < 1:
|
||||
continue
|
||||
try:
|
||||
d[tag] = re.compile(r'{0}'.format(config[tag]['regex']))
|
||||
except Exception:
|
||||
d[tag] = re.compile(r'{0}'.format(_config['tags'][tag]['regex']))
|
||||
except Exception as e:
|
||||
event = SKEL.copy()
|
||||
event['tag'] = tag
|
||||
event['error'] = 'bad regex'
|
||||
|
@ -11,6 +11,7 @@ Beacon to monitor memory usage.
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
import re
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# Import Third Party Libs
|
||||
try:
|
||||
@ -31,14 +32,22 @@ def __virtual__():
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for memusage beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for memusage '
|
||||
'beacon must be a dictionary.')
|
||||
'beacon must be a list.')
|
||||
else:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'percent' not in _config:
|
||||
return False, ('Configuration for memusage beacon '
|
||||
'requires percent.')
|
||||
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -46,7 +55,8 @@ def beacon(config):
|
||||
'''
|
||||
Monitor the memory usage of the minion
|
||||
|
||||
Specify thresholds for percent used and only emit a beacon if it is exceeded.
|
||||
Specify thresholds for percent used and only emit a beacon
|
||||
if it is exceeded.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
@ -55,12 +65,14 @@ def beacon(config):
|
||||
- percent: 63%
|
||||
'''
|
||||
ret = []
|
||||
for memusage in config:
|
||||
mount = memusage.keys()[0]
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
_current_usage = psutil.virtual_memory()
|
||||
|
||||
current_usage = _current_usage.percent
|
||||
monitor_usage = memusage[mount]
|
||||
monitor_usage = _config['percent']
|
||||
if '%' in monitor_usage:
|
||||
monitor_usage = re.sub('%', '', monitor_usage)
|
||||
monitor_usage = float(monitor_usage)
|
||||
|
@ -16,6 +16,9 @@ try:
|
||||
HAS_PSUTIL = True
|
||||
except ImportError:
|
||||
HAS_PSUTIL = False
|
||||
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# pylint: enable=import-error
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -45,7 +48,7 @@ def __virtual__():
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
@ -57,15 +60,19 @@ def __validate__(config):
|
||||
]
|
||||
|
||||
# Configuration for load beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for load beacon must be a dictionary.')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for network_info beacon must be a list.')
|
||||
else:
|
||||
for item in config:
|
||||
if not isinstance(config[item], dict):
|
||||
return False, ('Configuration for load beacon must '
|
||||
'be a dictionary of dictionaries.')
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
for item in _config.get('interfaces', {}):
|
||||
if not isinstance(_config['interfaces'][item], dict):
|
||||
return False, ('Configuration for network_info beacon must '
|
||||
'be a list of dictionaries.')
|
||||
else:
|
||||
if not any(j in VALID_ITEMS for j in config[item]):
|
||||
if not any(j in VALID_ITEMS for j in _config['interfaces'][item]):
|
||||
return False, ('Invalid configuration item in '
|
||||
'Beacon configuration.')
|
||||
return True, 'Valid beacon configuration'
|
||||
@ -86,7 +93,8 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
network_info:
|
||||
- eth0:
|
||||
- interfaces:
|
||||
eth0:
|
||||
type: equal
|
||||
bytes_sent: 100000
|
||||
bytes_recv: 100000
|
||||
@ -104,7 +112,8 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
network_info:
|
||||
- eth0:
|
||||
- interfaces:
|
||||
eth0:
|
||||
type: greater
|
||||
bytes_sent: 100000
|
||||
bytes_recv: 100000
|
||||
@ -119,31 +128,37 @@ def beacon(config):
|
||||
'''
|
||||
ret = []
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
log.debug('psutil.net_io_counters {}'.format(psutil.net_io_counters))
|
||||
|
||||
_stats = psutil.net_io_counters(pernic=True)
|
||||
|
||||
for interface_config in config:
|
||||
interface = interface_config.keys()[0]
|
||||
log.debug('_stats {}'.format(_stats))
|
||||
for interface in _config.get('interfaces', {}):
|
||||
if interface in _stats:
|
||||
interface_config = _config['interfaces'][interface]
|
||||
_if_stats = _stats[interface]
|
||||
_diff = False
|
||||
for attr in __attrs:
|
||||
if attr in interface_config[interface]:
|
||||
if 'type' in interface_config[interface] and \
|
||||
interface_config[interface]['type'] == 'equal':
|
||||
if attr in interface_config:
|
||||
if 'type' in interface_config and \
|
||||
interface_config['type'] == 'equal':
|
||||
if getattr(_if_stats, attr, None) == \
|
||||
int(interface_config[interface][attr]):
|
||||
int(interface_config[attr]):
|
||||
_diff = True
|
||||
elif 'type' in interface_config[interface] and \
|
||||
interface_config[interface]['type'] == 'greater':
|
||||
elif 'type' in interface_config and \
|
||||
interface_config['type'] == 'greater':
|
||||
if getattr(_if_stats, attr, None) > \
|
||||
int(interface_config[interface][attr]):
|
||||
int(interface_config[attr]):
|
||||
_diff = True
|
||||
else:
|
||||
log.debug('attr {}'.format(getattr(_if_stats,
|
||||
attr, None)))
|
||||
else:
|
||||
if getattr(_if_stats, attr, None) == \
|
||||
int(interface_config[interface][attr]):
|
||||
int(interface_config[attr]):
|
||||
_diff = True
|
||||
if _diff:
|
||||
ret.append({'interface': interface,
|
||||
|
@ -18,6 +18,8 @@ import ast
|
||||
import re
|
||||
import salt.loader
|
||||
import logging
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__virtual_name__ = 'network_settings'
|
||||
@ -45,22 +47,23 @@ def __virtual__():
|
||||
return False
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
if not isinstance(config, dict):
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for network_settings '
|
||||
'beacon must be a dictionary.')
|
||||
'beacon must be a list.')
|
||||
else:
|
||||
for item in config:
|
||||
if item == 'coalesce':
|
||||
continue
|
||||
if not isinstance(config[item], dict):
|
||||
return False, ('Configuration for network_settings beacon must be a '
|
||||
'dictionary of dictionaries.')
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
for item in _config.get('interfaces', {}):
|
||||
if not isinstance(_config['interfaces'][item], dict):
|
||||
return False, ('Configuration for network_settings beacon '
|
||||
' must be a list of dictionaries.')
|
||||
else:
|
||||
if not all(j in ATTRS for j in config[item]):
|
||||
if not all(j in ATTRS for j in _config['interfaces'][item]):
|
||||
return False, ('Invalid configuration item in Beacon '
|
||||
'configuration.')
|
||||
return True, 'Valid beacon configuration'
|
||||
@ -75,6 +78,7 @@ def _copy_interfaces_info(interfaces):
|
||||
for interface in interfaces:
|
||||
_interface_attrs_cpy = set()
|
||||
for attr in ATTRS:
|
||||
if attr in interfaces[interface]:
|
||||
attr_dict = Hashabledict()
|
||||
attr_dict[attr] = repr(interfaces[interface][attr])
|
||||
_interface_attrs_cpy.add(attr_dict)
|
||||
@ -89,8 +93,8 @@ def beacon(config):
|
||||
|
||||
By default, the beacon will emit when there is a value change on one of the
|
||||
settings on watch. The config also support the onvalue parameter for each
|
||||
setting, which instruct the beacon to only emit if the setting changed to the
|
||||
value defined.
|
||||
setting, which instruct the beacon to only emit if the setting changed to
|
||||
the value defined.
|
||||
|
||||
Example Config
|
||||
|
||||
@ -98,11 +102,12 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
network_settings:
|
||||
eth0:
|
||||
- interfaces:
|
||||
- eth0:
|
||||
ipaddr:
|
||||
promiscuity:
|
||||
onvalue: 1
|
||||
eth1:
|
||||
- eth1:
|
||||
linkmode:
|
||||
|
||||
The config above will check for value changes on eth0 ipaddr and eth1 linkmode. It will also
|
||||
@ -118,12 +123,16 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
network_settings:
|
||||
coalesce: True
|
||||
eth0:
|
||||
- coalesce: True
|
||||
- interfaces:
|
||||
- eth0:
|
||||
ipaddr:
|
||||
promiscuity:
|
||||
|
||||
'''
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
ret = []
|
||||
interfaces = []
|
||||
expanded_config = {}
|
||||
@ -137,45 +146,51 @@ def beacon(config):
|
||||
if not LAST_STATS:
|
||||
LAST_STATS = _stats
|
||||
|
||||
if 'coalesce' in config and config['coalesce']:
|
||||
if 'coalesce' in _config and _config['coalesce']:
|
||||
coalesce = True
|
||||
changes = {}
|
||||
|
||||
log.debug('_stats {}'.format(_stats))
|
||||
# Get list of interfaces included in config that are registered in the
|
||||
# system, including interfaces defined by wildcards (eth*, wlan*)
|
||||
for item in config:
|
||||
if item == 'coalesce':
|
||||
continue
|
||||
if item in _stats:
|
||||
interfaces.append(item)
|
||||
for interface in _config.get('interfaces', {}):
|
||||
if interface in _stats:
|
||||
interfaces.append(interface)
|
||||
else:
|
||||
# No direct match, try with * wildcard regexp
|
||||
interface_regexp = item.replace('*', '[0-9]+')
|
||||
interface_regexp = interface.replace('*', '[0-9]+')
|
||||
for interface in _stats:
|
||||
match = re.search(interface_regexp, interface)
|
||||
if match:
|
||||
interfaces.append(match.group())
|
||||
expanded_config[match.group()] = config[item]
|
||||
expanded_config[match.group()] = config['interfaces'][interface]
|
||||
|
||||
if expanded_config:
|
||||
config.update(expanded_config)
|
||||
|
||||
# config updated so update _config
|
||||
list(map(_config.update, config))
|
||||
|
||||
log.debug('interfaces {}'.format(interfaces))
|
||||
for interface in interfaces:
|
||||
_send_event = False
|
||||
_diff_stats = _stats[interface] - LAST_STATS[interface]
|
||||
_ret_diff = {}
|
||||
interface_config = _config['interfaces'][interface]
|
||||
|
||||
log.debug('_diff_stats {}'.format(_diff_stats))
|
||||
if _diff_stats:
|
||||
_diff_stats_dict = {}
|
||||
LAST_STATS[interface] = _stats[interface]
|
||||
|
||||
for item in _diff_stats:
|
||||
_diff_stats_dict.update(item)
|
||||
for attr in config[interface]:
|
||||
for attr in interface_config:
|
||||
if attr in _diff_stats_dict:
|
||||
config_value = None
|
||||
if config[interface][attr] and 'onvalue' in config[interface][attr]:
|
||||
config_value = config[interface][attr]['onvalue']
|
||||
if interface_config[attr] and \
|
||||
'onvalue' in interface_config[attr]:
|
||||
config_value = interface_config[attr]['onvalue']
|
||||
new_value = ast.literal_eval(_diff_stats_dict[attr])
|
||||
if not config_value or config_value == new_value:
|
||||
_send_event = True
|
||||
@ -185,7 +200,9 @@ def beacon(config):
|
||||
if coalesce:
|
||||
changes[interface] = _ret_diff
|
||||
else:
|
||||
ret.append({'tag': interface, 'interface': interface, 'change': _ret_diff})
|
||||
ret.append({'tag': interface,
|
||||
'interface': interface,
|
||||
'change': _ret_diff})
|
||||
|
||||
if coalesce and changes:
|
||||
grains_info = salt.loader.grains(__opts__, True)
|
||||
|
@ -21,15 +21,25 @@ def __virtual__():
|
||||
return __virtualname__ if 'pkg.upgrade_available' in __salt__ else False
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for pkg beacon should be a list
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for pkg beacon must be a dictionary.')
|
||||
if 'pkgs' not in config:
|
||||
return False, ('Configuration for pkg beacon requires list of pkgs.')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for pkg beacon must be a list.')
|
||||
|
||||
# Configuration for pkg beacon should contain pkgs
|
||||
pkgs_found = False
|
||||
pkgs_not_list = False
|
||||
for config_item in config:
|
||||
if 'pkgs' in config_item:
|
||||
pkgs_found = True
|
||||
if isinstance(config_item['pkgs'], list):
|
||||
pkgs_not_list = True
|
||||
|
||||
if not pkgs_found or not pkgs_not_list:
|
||||
return False, 'Configuration for pkg beacon requires list of pkgs.'
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -48,14 +58,16 @@ def beacon(config):
|
||||
- refresh: True
|
||||
'''
|
||||
ret = []
|
||||
_validate = __validate__(config)
|
||||
if not _validate[0]:
|
||||
return ret
|
||||
|
||||
_refresh = False
|
||||
pkgs = []
|
||||
for config_item in config:
|
||||
if 'pkgs' in config_item:
|
||||
pkgs += config_item['pkgs']
|
||||
if 'refresh' in config and config['refresh']:
|
||||
_refresh = True
|
||||
for pkg in config['pkgs']:
|
||||
|
||||
for pkg in pkgs:
|
||||
_installed = __salt__['pkg.version'](pkg)
|
||||
_latest = __salt__['pkg.latest_version'](pkg, refresh=_refresh)
|
||||
if _installed and _latest:
|
||||
|
@ -15,6 +15,7 @@ import logging
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.http
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# Important: If used with salt-proxy
|
||||
# this is required for the beacon to load!!!
|
||||
@ -33,12 +34,12 @@ def __virtual__():
|
||||
return True
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for rest_example beacon must be a dictionary.')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for proxy_example beacon must be a list.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -51,7 +52,7 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
proxy_example:
|
||||
endpoint: beacon
|
||||
- endpoint: beacon
|
||||
'''
|
||||
# Important!!!
|
||||
# Although this toy example makes an HTTP call
|
||||
@ -59,8 +60,11 @@ def beacon(config):
|
||||
# please be advised that doing CPU or IO intensive
|
||||
# operations in this method will cause the beacon loop
|
||||
# to block.
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
beacon_url = '{0}{1}'.format(__opts__['proxy']['url'],
|
||||
config['endpoint'])
|
||||
_config['endpoint'])
|
||||
ret = salt.utils.http.query(beacon_url,
|
||||
decode_type='json',
|
||||
decode=True)
|
||||
|
@ -14,6 +14,9 @@ try:
|
||||
HAS_PSUTIL = True
|
||||
except ImportError:
|
||||
HAS_PSUTIL = False
|
||||
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# pylint: enable=import-error
|
||||
|
||||
log = logging.getLogger(__name__) # pylint: disable=invalid-name
|
||||
@ -23,17 +26,27 @@ __virtualname__ = 'ps'
|
||||
|
||||
def __virtual__():
|
||||
if not HAS_PSUTIL:
|
||||
return (False, 'cannot load network_info beacon: psutil not available')
|
||||
return (False, 'cannot load ps beacon: psutil not available')
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for ps beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for ps beacon must be a dictionary.')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for ps beacon must be a list.')
|
||||
else:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'processes' not in _config:
|
||||
return False, ('Configuration for ps beacon requires processes.')
|
||||
else:
|
||||
if not isinstance(_config['processes'], dict):
|
||||
return False, ('Processes for ps beacon must be a dictionary.')
|
||||
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -47,8 +60,9 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
ps:
|
||||
- salt-master: running
|
||||
- mysql: stopped
|
||||
- processes:
|
||||
salt-master: running
|
||||
mysql: stopped
|
||||
|
||||
The config above sets up beacons to check that
|
||||
processes are running or stopped.
|
||||
@ -60,14 +74,16 @@ def beacon(config):
|
||||
if _name not in procs:
|
||||
procs.append(_name)
|
||||
|
||||
for entry in config:
|
||||
for process in entry:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
for process in _config.get('processes', {}):
|
||||
ret_dict = {}
|
||||
if entry[process] == 'running':
|
||||
if _config['processes'][process] == 'running':
|
||||
if process in procs:
|
||||
ret_dict[process] = 'Running'
|
||||
ret.append(ret_dict)
|
||||
elif entry[process] == 'stopped':
|
||||
elif _config['processes'][process] == 'stopped':
|
||||
if process not in procs:
|
||||
ret_dict[process] = 'Stopped'
|
||||
ret.append(ret_dict)
|
||||
|
@ -9,6 +9,7 @@
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -20,9 +21,7 @@ def _run_proxy_processes(proxies):
|
||||
aren't running
|
||||
'''
|
||||
ret = []
|
||||
for prox_ in proxies:
|
||||
# prox_ is a dict
|
||||
proxy = prox_.keys()[0]
|
||||
for proxy in proxies:
|
||||
result = {}
|
||||
if not __salt__['salt_proxy.is_running'](proxy)['result']:
|
||||
__salt__['salt_proxy.configure_proxy'](proxy, start=True)
|
||||
@ -35,7 +34,29 @@ def _run_proxy_processes(proxies):
|
||||
return ret
|
||||
|
||||
|
||||
def beacon(proxies):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for adb beacon should be a dictionary with states array
|
||||
if not isinstance(config, list):
|
||||
log.info('Configuration for salt_proxy beacon must be a list.')
|
||||
return False, ('Configuration for salt_proxy beacon must be a list.')
|
||||
|
||||
else:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'proxies' not in _config:
|
||||
return False, ('Configuration for salt_proxy'
|
||||
' beacon requires proxies.')
|
||||
else:
|
||||
if not isinstance(_config['proxies'], dict):
|
||||
return False, ('Proxies for salt_proxy '
|
||||
'beacon must be a dictionary.')
|
||||
|
||||
|
||||
def beacon(config):
|
||||
'''
|
||||
Handle configured proxies
|
||||
|
||||
@ -43,9 +64,13 @@ def beacon(proxies):
|
||||
|
||||
beacons:
|
||||
salt_proxy:
|
||||
- p8000: {}
|
||||
- p8001: {}
|
||||
- proxies:
|
||||
p8000: {}
|
||||
p8001: {}
|
||||
'''
|
||||
log.trace('salt proxy beacon called')
|
||||
|
||||
return _run_proxy_processes(proxies)
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
return _run_proxy_processes(_config['proxies'])
|
||||
|
@ -11,6 +11,7 @@ of a Raspberry Pi.
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
import re
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -19,14 +20,22 @@ def __virtual__():
|
||||
return 'sensehat.get_pressure' in __salt__
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for sensehat beacon should be a dict
|
||||
if not isinstance(config, dict):
|
||||
# Configuration for sensehat beacon should be a list
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for sensehat beacon '
|
||||
'must be a dictionary.')
|
||||
'must be a list.')
|
||||
else:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'sensors' not in _config:
|
||||
return False, ('Configuration for sensehat'
|
||||
' beacon requires sensors.')
|
||||
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -48,6 +57,7 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
sensehat:
|
||||
- sensors:
|
||||
humidity: 70%
|
||||
temperature: [20, 40]
|
||||
temperature_from_pressure: 40
|
||||
@ -60,13 +70,16 @@ def beacon(config):
|
||||
'temperature': '-273.15'
|
||||
}
|
||||
|
||||
for sensor in config:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
for sensor in _config.get('sensors', {}):
|
||||
sensor_function = 'sensehat.get_{0}'.format(sensor)
|
||||
if sensor_function not in __salt__:
|
||||
log.error('No sensor for meassuring {0}. Skipping.'.format(sensor))
|
||||
continue
|
||||
|
||||
sensor_config = config[sensor]
|
||||
sensor_config = _config['sensors'][sensor]
|
||||
if isinstance(sensor_config, list):
|
||||
sensor_min = str(sensor_config[0])
|
||||
sensor_max = str(sensor_config[1])
|
||||
|
@ -9,19 +9,35 @@ from __future__ import absolute_import
|
||||
import os
|
||||
import logging
|
||||
import time
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
log = logging.getLogger(__name__) # pylint: disable=invalid-name
|
||||
|
||||
LAST_STATUS = {}
|
||||
|
||||
__virtualname__ = 'service'
|
||||
|
||||
def __validate__(config):
|
||||
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for service beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for service beacon must be a dictionary.')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for service beacon must be a list.')
|
||||
else:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if 'services' not in _config:
|
||||
return False, ('Configuration for service beacon'
|
||||
' requires services.')
|
||||
else:
|
||||
for config_item in _config['services']:
|
||||
if not isinstance(_config['services'][config_item], dict):
|
||||
return False, ('Configuration for service beacon must '
|
||||
'be a list of dictionaries.')
|
||||
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -35,6 +51,7 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
service:
|
||||
- services:
|
||||
salt-master:
|
||||
mysql:
|
||||
|
||||
@ -79,14 +96,21 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
service:
|
||||
- services:
|
||||
nginx:
|
||||
onchangeonly: True
|
||||
delay: 30
|
||||
uncleanshutdown: /run/nginx.pid
|
||||
'''
|
||||
ret = []
|
||||
for service in config:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
for service in _config.get('services', {}):
|
||||
ret_dict = {}
|
||||
|
||||
service_config = _config['services'][service]
|
||||
|
||||
ret_dict[service] = {'running': __salt__['service.status'](service)}
|
||||
ret_dict['service_name'] = service
|
||||
ret_dict['tag'] = service
|
||||
@ -95,40 +119,43 @@ def beacon(config):
|
||||
# If no options is given to the service, we fall back to the defaults
|
||||
# assign a False value to oncleanshutdown and onchangeonly. Those
|
||||
# key:values are then added to the service dictionary.
|
||||
if 'oncleanshutdown' not in config[service]:
|
||||
config[service]['oncleanshutdown'] = False
|
||||
if 'emitatstartup' not in config[service]:
|
||||
config[service]['emitatstartup'] = True
|
||||
if 'onchangeonly' not in config[service]:
|
||||
config[service]['onchangeonly'] = False
|
||||
if 'delay' not in config[service]:
|
||||
config[service]['delay'] = 0
|
||||
if not service_config:
|
||||
service_config = {}
|
||||
if 'oncleanshutdown' not in service_config:
|
||||
service_config['oncleanshutdown'] = False
|
||||
if 'emitatstartup' not in service_config:
|
||||
service_config['emitatstartup'] = True
|
||||
if 'onchangeonly' not in service_config:
|
||||
service_config['onchangeonly'] = False
|
||||
if 'delay' not in service_config:
|
||||
service_config['delay'] = 0
|
||||
|
||||
# We only want to report the nature of the shutdown
|
||||
# if the current running status is False
|
||||
# as well as if the config for the beacon asks for it
|
||||
if 'uncleanshutdown' in config[service] and not ret_dict[service]['running']:
|
||||
filename = config[service]['uncleanshutdown']
|
||||
if 'uncleanshutdown' in service_config and not ret_dict[service]['running']:
|
||||
filename = service_config['uncleanshutdown']
|
||||
ret_dict[service]['uncleanshutdown'] = True if os.path.exists(filename) else False
|
||||
if 'onchangeonly' in config[service] and config[service]['onchangeonly'] is True:
|
||||
if 'onchangeonly' in service_config and service_config['onchangeonly'] is True:
|
||||
if service not in LAST_STATUS:
|
||||
LAST_STATUS[service] = ret_dict[service]
|
||||
if config[service]['delay'] > 0:
|
||||
if service_config['delay'] > 0:
|
||||
LAST_STATUS[service]['time'] = currtime
|
||||
elif not config[service]['emitatstartup']:
|
||||
elif not service_config['emitatstartup']:
|
||||
continue
|
||||
else:
|
||||
ret.append(ret_dict)
|
||||
|
||||
if LAST_STATUS[service]['running'] != ret_dict[service]['running']:
|
||||
LAST_STATUS[service] = ret_dict[service]
|
||||
if config[service]['delay'] > 0:
|
||||
if service_config['delay'] > 0:
|
||||
LAST_STATUS[service]['time'] = currtime
|
||||
else:
|
||||
ret.append(ret_dict)
|
||||
|
||||
if 'time' in LAST_STATUS[service]:
|
||||
elapsedtime = int(round(currtime - LAST_STATUS[service]['time']))
|
||||
if elapsedtime > config[service]['delay']:
|
||||
if elapsedtime > service_config['delay']:
|
||||
del LAST_STATUS[service]['time']
|
||||
ret.append(ret_dict)
|
||||
else:
|
||||
|
@ -9,6 +9,7 @@ import time
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.path
|
||||
import salt.utils.vt
|
||||
|
||||
__virtualname__ = 'sh'
|
||||
@ -21,7 +22,7 @@ def __virtual__():
|
||||
'''
|
||||
Only load if strace is installed
|
||||
'''
|
||||
return __virtualname__ if salt.utils.which('strace') else False
|
||||
return __virtualname__ if salt.utils.path.which('strace') else False
|
||||
|
||||
|
||||
def _get_shells():
|
||||
@ -40,13 +41,13 @@ def _get_shells():
|
||||
return __context__['sh.shells']
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for sh beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for sh beacon must be a dictionary.')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for sh beacon must be a list.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -57,7 +58,7 @@ def beacon(config):
|
||||
.. code-block:: yaml
|
||||
|
||||
beacons:
|
||||
sh: {}
|
||||
sh: []
|
||||
'''
|
||||
ret = []
|
||||
pkey = 'sh.vt'
|
||||
|
@ -15,7 +15,7 @@ the minion config:
|
||||
.. code-block:: yaml
|
||||
|
||||
beacons:
|
||||
status: {}
|
||||
status: []
|
||||
|
||||
By default, all of the information from the following execution module
|
||||
functions will be returned:
|
||||
@ -96,19 +96,19 @@ import datetime
|
||||
import salt.exceptions
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.platform
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__virtualname__ = 'status'
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the the config is a dict
|
||||
'''
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for status beacon must be a dictionary.')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for status beacon must be a list.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -123,7 +123,7 @@ def beacon(config):
|
||||
log.debug(config)
|
||||
ctime = datetime.datetime.utcnow().isoformat()
|
||||
ret = {}
|
||||
if salt.utils.is_windows():
|
||||
if salt.utils.platform.is_windows():
|
||||
return [{
|
||||
'tag': ctime,
|
||||
'data': ret,
|
||||
|
@ -1,11 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Beacon to emit Telegram messages
|
||||
|
||||
Requires the python-telegram-bot library
|
||||
|
||||
'''
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# Import 3rd Party libs
|
||||
try:
|
||||
@ -28,20 +32,23 @@ def __virtual__():
|
||||
return False
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
if not isinstance(config, dict):
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for telegram_bot_msg '
|
||||
'beacon must be a dictionary.')
|
||||
'beacon must be a list.')
|
||||
|
||||
if not all(config.get(required_config)
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if not all(_config.get(required_config)
|
||||
for required_config in ['token', 'accept_from']):
|
||||
return False, ('Not all required configuration for '
|
||||
'telegram_bot_msg are set.')
|
||||
|
||||
if not isinstance(config.get('accept_from'), list):
|
||||
if not isinstance(_config.get('accept_from'), list):
|
||||
return False, ('Configuration for telegram_bot_msg, '
|
||||
'accept_from must be a list of usernames.')
|
||||
|
||||
@ -57,18 +64,22 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
telegram_bot_msg:
|
||||
token: "<bot access token>"
|
||||
accept_from:
|
||||
- token: "<bot access token>"
|
||||
- accept_from:
|
||||
- "<valid username>"
|
||||
interval: 10
|
||||
- interval: 10
|
||||
|
||||
'''
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
log.debug('telegram_bot_msg beacon starting')
|
||||
ret = []
|
||||
output = {}
|
||||
output['msgs'] = []
|
||||
|
||||
bot = telegram.Bot(config['token'])
|
||||
bot = telegram.Bot(_config['token'])
|
||||
updates = bot.get_updates(limit=100, timeout=0, network_delay=10)
|
||||
|
||||
log.debug('Num updates: {0}'.format(len(updates)))
|
||||
@ -83,7 +94,7 @@ def beacon(config):
|
||||
if update.update_id > latest_update_id:
|
||||
latest_update_id = update.update_id
|
||||
|
||||
if message.chat.username in config['accept_from']:
|
||||
if message.chat.username in _config['accept_from']:
|
||||
output['msgs'].append(message.to_dict())
|
||||
|
||||
# mark in the server that previous messages are processed
|
||||
|
@ -6,9 +6,16 @@ Beacon to emit Twilio text messages
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
# Import 3rd Party libs
|
||||
try:
|
||||
import twilio
|
||||
# Grab version, ensure elements are ints
|
||||
twilio_version = tuple([int(x) for x in twilio.__version_info__])
|
||||
if twilio_version > (5, ):
|
||||
from twilio.rest import Client as TwilioRestClient
|
||||
else:
|
||||
from twilio.rest import TwilioRestClient
|
||||
HAS_TWILIO = True
|
||||
except ImportError:
|
||||
@ -26,14 +33,24 @@ def __virtual__():
|
||||
return False
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for twilio_txt_msg beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for twilio_txt_msg beacon '
|
||||
'must be a dictionary.')
|
||||
'must be a list.')
|
||||
else:
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
if not all(x in _config for x in ('account_sid',
|
||||
'auth_token',
|
||||
'twilio_number')):
|
||||
return False, ('Configuration for twilio_txt_msg beacon '
|
||||
'must contain account_sid, auth_token '
|
||||
'and twilio_number items.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -46,20 +63,26 @@ def beacon(config):
|
||||
|
||||
beacons:
|
||||
twilio_txt_msg:
|
||||
account_sid: "<account sid>"
|
||||
auth_token: "<auth token>"
|
||||
twilio_number: "+15555555555"
|
||||
interval: 10
|
||||
- account_sid: "<account sid>"
|
||||
- auth_token: "<auth token>"
|
||||
- twilio_number: "+15555555555"
|
||||
- interval: 10
|
||||
|
||||
'''
|
||||
log.trace('twilio_txt_msg beacon starting')
|
||||
|
||||
_config = {}
|
||||
list(map(_config.update, config))
|
||||
|
||||
ret = []
|
||||
if not all([config['account_sid'], config['auth_token'], config['twilio_number']]):
|
||||
if not all([_config['account_sid'],
|
||||
_config['auth_token'],
|
||||
_config['twilio_number']]):
|
||||
return ret
|
||||
output = {}
|
||||
output['texts'] = []
|
||||
client = TwilioRestClient(config['account_sid'], config['auth_token'])
|
||||
messages = client.messages.list(to=config['twilio_number'])
|
||||
client = TwilioRestClient(_config['account_sid'], _config['auth_token'])
|
||||
messages = client.messages.list(to=_config['twilio_number'])
|
||||
log.trace('Num messages: {0}'.format(len(messages)))
|
||||
if len(messages) < 1:
|
||||
log.trace('Twilio beacon has no texts')
|
||||
|
@ -5,7 +5,7 @@ Beacon to fire events at login of users as registered in the wtmp file
|
||||
.. code-block:: yaml
|
||||
|
||||
beacons:
|
||||
wtmp: {}
|
||||
wtmp: []
|
||||
'''
|
||||
|
||||
# Import Python libs
|
||||
@ -16,6 +16,9 @@ import struct
|
||||
# Import salt libs
|
||||
import salt.utils.files
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
__virtualname__ = 'wtmp'
|
||||
WTMP = '/var/log/wtmp'
|
||||
FMT = 'hi32s4s32s256shhiii4i20x'
|
||||
@ -52,13 +55,13 @@ def _get_loc():
|
||||
return __context__[LOC_KEY]
|
||||
|
||||
|
||||
def __validate__(config):
|
||||
def validate(config):
|
||||
'''
|
||||
Validate the beacon configuration
|
||||
'''
|
||||
# Configuration for wtmp beacon should be a list of dicts
|
||||
if not isinstance(config, dict):
|
||||
return False, ('Configuration for wtmp beacon must be a dictionary.')
|
||||
if not isinstance(config, list):
|
||||
return False, ('Configuration for wtmp beacon must be a list.')
|
||||
return True, 'Valid beacon configuration'
|
||||
|
||||
|
||||
@ -70,7 +73,7 @@ def beacon(config):
|
||||
.. code-block:: yaml
|
||||
|
||||
beacons:
|
||||
wtmp: {}
|
||||
wtmp: []
|
||||
'''
|
||||
ret = []
|
||||
with salt.utils.files.fopen(WTMP, 'rb') as fp_:
|
||||
@ -90,7 +93,7 @@ def beacon(config):
|
||||
event = {}
|
||||
for ind, field in enumerate(FIELDS):
|
||||
event[field] = pack[ind]
|
||||
if isinstance(event[field], str):
|
||||
if isinstance(event[field], six.string_types):
|
||||
event[field] = event[field].strip('\x00')
|
||||
ret.append(event)
|
||||
return ret
|
||||
|
@ -11,14 +11,14 @@ import copy
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils # Can be removed once print_cli is moved
|
||||
import salt.client
|
||||
import salt.output
|
||||
import salt.exceptions
|
||||
from salt.utils import print_cli
|
||||
|
||||
# Import 3rd-party libs
|
||||
# pylint: disable=import-error,no-name-in-module,redefined-builtin
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
from salt.ext.six.moves import range
|
||||
# pylint: enable=import-error,no-name-in-module,redefined-builtin
|
||||
import logging
|
||||
@ -73,7 +73,7 @@ class Batch(object):
|
||||
m = next(six.iterkeys(ret))
|
||||
except StopIteration:
|
||||
if not self.quiet:
|
||||
print_cli('No minions matched the target.')
|
||||
salt.utils.print_cli('No minions matched the target.')
|
||||
break
|
||||
if m is not None:
|
||||
fret.add(m)
|
||||
@ -95,7 +95,7 @@ class Batch(object):
|
||||
return int(self.opts['batch'])
|
||||
except ValueError:
|
||||
if not self.quiet:
|
||||
print_cli('Invalid batch data sent: {0}\nData must be in the '
|
||||
salt.utils.print_cli('Invalid batch data sent: {0}\nData must be in the '
|
||||
'form of %10, 10% or 3'.format(self.opts['batch']))
|
||||
|
||||
def __update_wait(self, wait):
|
||||
@ -146,7 +146,7 @@ class Batch(object):
|
||||
# We already know some minions didn't respond to the ping, so inform
|
||||
# the user we won't be attempting to run a job on them
|
||||
for down_minion in self.down_minions:
|
||||
print_cli('Minion {0} did not respond. No job will be sent.'.format(down_minion))
|
||||
salt.utils.print_cli('Minion {0} did not respond. No job will be sent.'.format(down_minion))
|
||||
|
||||
# Iterate while we still have things to execute
|
||||
while len(ret) < len(self.minions):
|
||||
@ -171,7 +171,7 @@ class Batch(object):
|
||||
|
||||
if next_:
|
||||
if not self.quiet:
|
||||
print_cli('\nExecuting run on {0}\n'.format(sorted(next_)))
|
||||
salt.utils.print_cli('\nExecuting run on {0}\n'.format(sorted(next_)))
|
||||
# create a new iterator for this batch of minions
|
||||
new_iter = self.local.cmd_iter_no_block(
|
||||
*args,
|
||||
@ -218,14 +218,14 @@ class Batch(object):
|
||||
if part['data']['id'] in minion_tracker[queue]['minions']:
|
||||
minion_tracker[queue]['minions'].remove(part['data']['id'])
|
||||
else:
|
||||
print_cli('minion {0} was already deleted from tracker, probably a duplicate key'.format(part['id']))
|
||||
salt.utils.print_cli('minion {0} was already deleted from tracker, probably a duplicate key'.format(part['id']))
|
||||
else:
|
||||
parts.update(part)
|
||||
for id in part:
|
||||
if id in minion_tracker[queue]['minions']:
|
||||
minion_tracker[queue]['minions'].remove(id)
|
||||
else:
|
||||
print_cli('minion {0} was already deleted from tracker, probably a duplicate key'.format(id))
|
||||
salt.utils.print_cli('minion {0} was already deleted from tracker, probably a duplicate key'.format(id))
|
||||
except StopIteration:
|
||||
# if a iterator is done:
|
||||
# - set it to inactive
|
||||
|
@ -1,16 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
from __future__ import absolute_import, print_function
|
||||
import os
|
||||
|
||||
from salt.utils import parsers
|
||||
import salt.utils.parsers
|
||||
from salt.utils.verify import verify_log
|
||||
from salt.config import _expand_glob_path
|
||||
import salt.cli.caller
|
||||
import salt.defaults.exitcodes
|
||||
|
||||
|
||||
class SaltCall(parsers.SaltCallOptionParser):
|
||||
class SaltCall(salt.utils.parsers.SaltCallOptionParser):
|
||||
'''
|
||||
Used to locally execute a salt command
|
||||
'''
|
||||
|
@ -20,19 +20,17 @@ import salt.minion
|
||||
import salt.output
|
||||
import salt.payload
|
||||
import salt.transport
|
||||
import salt.utils # Can be removed once print_cli, activate_profile, and output_profile are moved
|
||||
import salt.utils.args
|
||||
import salt.utils.files
|
||||
import salt.utils.jid
|
||||
import salt.utils.kinds as kinds
|
||||
import salt.utils.minion
|
||||
import salt.defaults.exitcodes
|
||||
from salt.log import LOG_LEVELS
|
||||
from salt.utils import is_windows
|
||||
from salt.utils import print_cli
|
||||
from salt.utils import kinds
|
||||
from salt.utils import activate_profile
|
||||
from salt.utils import output_profile
|
||||
from salt.utils.process import MultiprocessingProcess
|
||||
from salt.cli import daemons
|
||||
from salt.log import LOG_LEVELS
|
||||
from salt.utils.platform import is_windows
|
||||
from salt.utils.process import MultiprocessingProcess
|
||||
|
||||
try:
|
||||
from raet import raeting, nacling
|
||||
@ -47,7 +45,7 @@ except ImportError:
|
||||
pass
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
|
||||
# Custom exceptions
|
||||
from salt.exceptions import (
|
||||
@ -115,7 +113,7 @@ class BaseCaller(object):
|
||||
docs[name] = func.__doc__
|
||||
for name in sorted(docs):
|
||||
if name.startswith(self.opts.get('fun', '')):
|
||||
print_cli('{0}:\n{1}\n'.format(name, docs[name]))
|
||||
salt.utils.print_cli('{0}:\n{1}\n'.format(name, docs[name]))
|
||||
|
||||
def print_grains(self):
|
||||
'''
|
||||
@ -130,13 +128,13 @@ class BaseCaller(object):
|
||||
'''
|
||||
profiling_enabled = self.opts.get('profiling_enabled', False)
|
||||
try:
|
||||
pr = activate_profile(profiling_enabled)
|
||||
pr = salt.utils.activate_profile(profiling_enabled)
|
||||
try:
|
||||
ret = self.call()
|
||||
finally:
|
||||
output_profile(pr,
|
||||
stats_path=self.opts.get('profiling_path',
|
||||
'/tmp/stats'),
|
||||
salt.utils.output_profile(
|
||||
pr,
|
||||
stats_path=self.opts.get('profiling_path', '/tmp/stats'),
|
||||
stop=True)
|
||||
out = ret.get('out', 'nested')
|
||||
if self.opts['print_metadata']:
|
||||
@ -211,7 +209,7 @@ class BaseCaller(object):
|
||||
ret['return'] = func(*args, **kwargs)
|
||||
except TypeError as exc:
|
||||
sys.stderr.write('\nPassed invalid arguments: {0}.\n\nUsage:\n'.format(exc))
|
||||
print_cli(func.__doc__)
|
||||
salt.utils.print_cli(func.__doc__)
|
||||
active_level = LOG_LEVELS.get(
|
||||
self.opts['log_level'].lower(), logging.ERROR)
|
||||
if active_level <= logging.DEBUG:
|
||||
|
@ -21,7 +21,9 @@ import salt.client
|
||||
import salt.utils.gzip_util
|
||||
import salt.utils.itertools
|
||||
import salt.utils.minions
|
||||
from salt.utils import parsers, to_bytes
|
||||
import salt.utils.parsers
|
||||
import salt.utils.platform
|
||||
import salt.utils.stringutils
|
||||
from salt.utils.verify import verify_log
|
||||
import salt.output
|
||||
|
||||
@ -31,7 +33,7 @@ from salt.ext import six
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SaltCPCli(parsers.SaltCPOptionParser):
|
||||
class SaltCPCli(salt.utils.parsers.SaltCPOptionParser):
|
||||
'''
|
||||
Run the salt-cp command line client
|
||||
'''
|
||||
@ -56,7 +58,7 @@ class SaltCP(object):
|
||||
'''
|
||||
def __init__(self, opts):
|
||||
self.opts = opts
|
||||
self.is_windows = salt.utils.is_windows()
|
||||
self.is_windows = salt.utils.platform.is_windows()
|
||||
|
||||
def _mode(self, path):
|
||||
if self.is_windows:
|
||||
@ -152,7 +154,7 @@ class SaltCP(object):
|
||||
index = 1
|
||||
failed = {}
|
||||
for chunk in reader(fn_, chunk_size=self.opts['salt_cp_chunk_size']):
|
||||
chunk = base64.b64encode(to_bytes(chunk))
|
||||
chunk = base64.b64encode(salt.utils.stringutils.to_bytes(chunk))
|
||||
append = index > 1
|
||||
log.debug(
|
||||
'Copying %s to %starget \'%s\' as %s%s',
|
||||
|
@ -41,10 +41,11 @@ import salt.log.setup
|
||||
# the try block below bypasses an issue at build time so that modules don't
|
||||
# cause the build to fail
|
||||
from salt.utils import migrations
|
||||
from salt.utils import kinds
|
||||
import salt.utils.kinds as kinds
|
||||
|
||||
try:
|
||||
from salt.utils import parsers, ip_bracket
|
||||
from salt.utils import ip_bracket
|
||||
import salt.utils.parsers
|
||||
from salt.utils.verify import check_user, verify_env, verify_socket
|
||||
except ImportError as exc:
|
||||
if exc.args[0] != 'No module named _msgpack':
|
||||
@ -109,7 +110,7 @@ class DaemonsMixin(object): # pylint: disable=no-init
|
||||
self.shutdown(error)
|
||||
|
||||
|
||||
class Master(parsers.MasterOptionParser, DaemonsMixin): # pylint: disable=no-init
|
||||
class Master(salt.utils.parsers.MasterOptionParser, DaemonsMixin): # pylint: disable=no-init
|
||||
'''
|
||||
Creates a master server
|
||||
'''
|
||||
@ -220,7 +221,7 @@ class Master(parsers.MasterOptionParser, DaemonsMixin): # pylint: disable=no-in
|
||||
super(Master, self).shutdown(exitcode, exitmsg)
|
||||
|
||||
|
||||
class Minion(parsers.MinionOptionParser, DaemonsMixin): # pylint: disable=no-init
|
||||
class Minion(salt.utils.parsers.MinionOptionParser, DaemonsMixin): # pylint: disable=no-init
|
||||
'''
|
||||
Create a minion server
|
||||
'''
|
||||
@ -398,7 +399,7 @@ class Minion(parsers.MinionOptionParser, DaemonsMixin): # pylint: disable=no-in
|
||||
# pylint: enable=no-member
|
||||
|
||||
|
||||
class ProxyMinion(parsers.ProxyMinionOptionParser, DaemonsMixin): # pylint: disable=no-init
|
||||
class ProxyMinion(salt.utils.parsers.ProxyMinionOptionParser, DaemonsMixin): # pylint: disable=no-init
|
||||
'''
|
||||
Create a proxy minion server
|
||||
'''
|
||||
@ -549,7 +550,7 @@ class ProxyMinion(parsers.ProxyMinionOptionParser, DaemonsMixin): # pylint: dis
|
||||
# pylint: enable=no-member
|
||||
|
||||
|
||||
class Syndic(parsers.SyndicOptionParser, DaemonsMixin): # pylint: disable=no-init
|
||||
class Syndic(salt.utils.parsers.SyndicOptionParser, DaemonsMixin): # pylint: disable=no-init
|
||||
'''
|
||||
Create a syndic server
|
||||
'''
|
||||
|
@ -3,11 +3,11 @@ from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
from salt.utils import parsers
|
||||
import salt.utils.parsers
|
||||
from salt.utils.verify import check_user, verify_log
|
||||
|
||||
|
||||
class SaltKey(parsers.SaltKeyOptionParser):
|
||||
class SaltKey(salt.utils.parsers.SaltKeyOptionParser):
|
||||
'''
|
||||
Initialize the Salt key manager
|
||||
'''
|
||||
|
@ -2,15 +2,14 @@
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
from salt.utils import parsers
|
||||
from salt.utils import activate_profile
|
||||
from salt.utils import output_profile
|
||||
import salt.utils # Can be removed once activate_profile and output_profile are moved
|
||||
import salt.utils.parsers
|
||||
from salt.utils.verify import check_user, verify_log
|
||||
from salt.exceptions import SaltClientError
|
||||
import salt.defaults.exitcodes # pylint: disable=W0611
|
||||
|
||||
|
||||
class SaltRun(parsers.SaltRunOptionParser):
|
||||
class SaltRun(salt.utils.parsers.SaltRunOptionParser):
|
||||
'''
|
||||
Used to execute Salt runners
|
||||
'''
|
||||
@ -36,7 +35,7 @@ class SaltRun(parsers.SaltRunOptionParser):
|
||||
# someone tries to use the runners via the python API
|
||||
try:
|
||||
if check_user(self.config['user']):
|
||||
pr = activate_profile(profiling_enabled)
|
||||
pr = salt.utils.activate_profile(profiling_enabled)
|
||||
try:
|
||||
ret = runner.run()
|
||||
# In older versions ret['data']['retcode'] was used
|
||||
@ -50,7 +49,7 @@ class SaltRun(parsers.SaltRunOptionParser):
|
||||
elif isinstance(ret, dict) and 'retcode' in ret.get('data', {}):
|
||||
self.exit(ret['data']['retcode'])
|
||||
finally:
|
||||
output_profile(
|
||||
salt.utils.output_profile(
|
||||
pr,
|
||||
stats_path=self.options.profiling_path,
|
||||
stop=True)
|
||||
|
@ -7,8 +7,8 @@ sys.modules['pkg_resources'] = None
|
||||
import os
|
||||
|
||||
# Import Salt libs
|
||||
from salt.ext.six import string_types
|
||||
from salt.utils import parsers, print_cli
|
||||
import salt.utils # Can be removed once print_cli is moved
|
||||
import salt.utils.parsers
|
||||
from salt.utils.args import yamlify_arg
|
||||
from salt.utils.verify import verify_log
|
||||
from salt.exceptions import (
|
||||
@ -18,10 +18,10 @@ from salt.exceptions import (
|
||||
)
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
|
||||
|
||||
class SaltCMD(parsers.SaltCMDOptionParser):
|
||||
class SaltCMD(salt.utils.parsers.SaltCMDOptionParser):
|
||||
'''
|
||||
The execution of a salt command happens here
|
||||
'''
|
||||
@ -93,7 +93,7 @@ class SaltCMD(parsers.SaltCMDOptionParser):
|
||||
# potentially switch to batch execution
|
||||
if self.options.batch_safe_limit > 1:
|
||||
if len(self._preview_target()) >= self.options.batch_safe_limit:
|
||||
print_cli('\nNOTICE: Too many minions targeted, switching to batch execution.')
|
||||
salt.utils.print_cli('\nNOTICE: Too many minions targeted, switching to batch execution.')
|
||||
self.options.batch = self.options.batch_safe_size
|
||||
self._run_batch()
|
||||
return
|
||||
@ -140,7 +140,7 @@ class SaltCMD(parsers.SaltCMDOptionParser):
|
||||
|
||||
if self.config['async']:
|
||||
jid = self.local_client.cmd_async(**kwargs)
|
||||
print_cli('Executed command with job ID: {0}'.format(jid))
|
||||
salt.utils.print_cli('Executed command with job ID: {0}'.format(jid))
|
||||
return
|
||||
|
||||
# local will be None when there was an error
|
||||
@ -279,12 +279,12 @@ class SaltCMD(parsers.SaltCMDOptionParser):
|
||||
|
||||
def _print_errors_summary(self, errors):
|
||||
if errors:
|
||||
print_cli('\n')
|
||||
print_cli('---------------------------')
|
||||
print_cli('Errors')
|
||||
print_cli('---------------------------')
|
||||
salt.utils.print_cli('\n')
|
||||
salt.utils.print_cli('---------------------------')
|
||||
salt.utils.print_cli('Errors')
|
||||
salt.utils.print_cli('---------------------------')
|
||||
for error in errors:
|
||||
print_cli(self._format_error(error))
|
||||
salt.utils.print_cli(self._format_error(error))
|
||||
|
||||
def _print_returns_summary(self, ret):
|
||||
'''
|
||||
@ -301,7 +301,7 @@ class SaltCMD(parsers.SaltCMDOptionParser):
|
||||
if isinstance(minion_ret, dict) and 'ret' in minion_ret:
|
||||
minion_ret = ret[each_minion].get('ret')
|
||||
if (
|
||||
isinstance(minion_ret, string_types)
|
||||
isinstance(minion_ret, six.string_types)
|
||||
and minion_ret.startswith("Minion did not return")
|
||||
):
|
||||
if "Not connected" in minion_ret:
|
||||
@ -314,22 +314,22 @@ class SaltCMD(parsers.SaltCMDOptionParser):
|
||||
return_counter += 1
|
||||
if self._get_retcode(ret[each_minion]):
|
||||
failed_minions.append(each_minion)
|
||||
print_cli('\n')
|
||||
print_cli('-------------------------------------------')
|
||||
print_cli('Summary')
|
||||
print_cli('-------------------------------------------')
|
||||
print_cli('# of minions targeted: {0}'.format(return_counter + not_return_counter))
|
||||
print_cli('# of minions returned: {0}'.format(return_counter))
|
||||
print_cli('# of minions that did not return: {0}'.format(not_return_counter))
|
||||
print_cli('# of minions with errors: {0}'.format(len(failed_minions)))
|
||||
salt.utils.print_cli('\n')
|
||||
salt.utils.print_cli('-------------------------------------------')
|
||||
salt.utils.print_cli('Summary')
|
||||
salt.utils.print_cli('-------------------------------------------')
|
||||
salt.utils.print_cli('# of minions targeted: {0}'.format(return_counter + not_return_counter))
|
||||
salt.utils.print_cli('# of minions returned: {0}'.format(return_counter))
|
||||
salt.utils.print_cli('# of minions that did not return: {0}'.format(not_return_counter))
|
||||
salt.utils.print_cli('# of minions with errors: {0}'.format(len(failed_minions)))
|
||||
if self.options.verbose:
|
||||
if not_connected_minions:
|
||||
print_cli('Minions not connected: {0}'.format(" ".join(not_connected_minions)))
|
||||
salt.utils.print_cli('Minions not connected: {0}'.format(" ".join(not_connected_minions)))
|
||||
if not_response_minions:
|
||||
print_cli('Minions not responding: {0}'.format(" ".join(not_response_minions)))
|
||||
salt.utils.print_cli('Minions not responding: {0}'.format(" ".join(not_response_minions)))
|
||||
if failed_minions:
|
||||
print_cli('Minions with failures: {0}'.format(" ".join(failed_minions)))
|
||||
print_cli('-------------------------------------------')
|
||||
salt.utils.print_cli('Minions with failures: {0}'.format(" ".join(failed_minions)))
|
||||
salt.utils.print_cli('-------------------------------------------')
|
||||
|
||||
def _progress_end(self, out):
|
||||
import salt.output
|
||||
@ -406,10 +406,10 @@ class SaltCMD(parsers.SaltCMDOptionParser):
|
||||
docs = {}
|
||||
if not ret:
|
||||
self.exit(2, 'No minions found to gather docs from\n')
|
||||
if isinstance(ret, str):
|
||||
if isinstance(ret, six.string_types):
|
||||
self.exit(2, '{0}\n'.format(ret))
|
||||
for host in ret:
|
||||
if isinstance(ret[host], string_types) \
|
||||
if isinstance(ret[host], six.string_types) \
|
||||
and (ret[host].startswith("Minion did not return")
|
||||
or ret[host] == 'VALUE TRIMMED'):
|
||||
continue
|
||||
@ -421,6 +421,6 @@ class SaltCMD(parsers.SaltCMDOptionParser):
|
||||
salt.output.display_output({fun: docs[fun]}, 'nested', self.config)
|
||||
else:
|
||||
for fun in sorted(docs):
|
||||
print_cli('{0}:'.format(fun))
|
||||
print_cli(docs[fun])
|
||||
print_cli('')
|
||||
salt.utils.print_cli('{0}:'.format(fun))
|
||||
salt.utils.print_cli(docs[fun])
|
||||
salt.utils.print_cli('')
|
||||
|
@ -2,17 +2,21 @@
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
import sys
|
||||
import salt.client.ssh
|
||||
from salt.utils import parsers
|
||||
import salt.utils.parsers
|
||||
from salt.utils.verify import verify_log
|
||||
|
||||
|
||||
class SaltSSH(parsers.SaltSSHOptionParser):
|
||||
class SaltSSH(salt.utils.parsers.SaltSSHOptionParser):
|
||||
'''
|
||||
Used to Execute the salt ssh routine
|
||||
'''
|
||||
|
||||
def run(self):
|
||||
if '-H' in sys.argv or '--hosts' in sys.argv:
|
||||
sys.argv += ['x', 'x'] # Hack: pass a mandatory two options
|
||||
# that won't be used anyways with -H or --hosts
|
||||
self.parse_args()
|
||||
self.setup_logfile_logger()
|
||||
verify_log(self.config)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,7 @@ def tokenify(cmd, token=None):
|
||||
Otherwise return cmd
|
||||
'''
|
||||
if token is not None:
|
||||
cmd['token'] = token
|
||||
cmd[u'token'] = token
|
||||
return cmd
|
||||
|
||||
|
||||
@ -50,19 +50,19 @@ class APIClient(object):
|
||||
if not opts:
|
||||
opts = salt.config.client_config(
|
||||
os.environ.get(
|
||||
'SALT_MASTER_CONFIG',
|
||||
os.path.join(syspaths.CONFIG_DIR, 'master')
|
||||
u'SALT_MASTER_CONFIG',
|
||||
os.path.join(syspaths.CONFIG_DIR, u'master')
|
||||
)
|
||||
)
|
||||
self.opts = opts
|
||||
self.localClient = salt.client.get_local_client(self.opts['conf_file'])
|
||||
self.localClient = salt.client.get_local_client(self.opts[u'conf_file'])
|
||||
self.runnerClient = salt.runner.RunnerClient(self.opts)
|
||||
self.wheelClient = salt.wheel.Wheel(self.opts)
|
||||
self.resolver = salt.auth.Resolver(self.opts)
|
||||
self.event = salt.utils.event.get_event(
|
||||
'master',
|
||||
self.opts['sock_dir'],
|
||||
self.opts['transport'],
|
||||
u'master',
|
||||
self.opts[u'sock_dir'],
|
||||
self.opts[u'transport'],
|
||||
opts=self.opts,
|
||||
listen=listen)
|
||||
|
||||
@ -118,20 +118,20 @@ class APIClient(object):
|
||||
|
||||
'''
|
||||
cmd = dict(cmd) # make copy
|
||||
client = 'minion' # default to local minion client
|
||||
mode = cmd.get('mode', 'async') # default to 'async'
|
||||
client = u'minion' # default to local minion client
|
||||
mode = cmd.get(u'mode', u'async') # default to 'async'
|
||||
|
||||
# check for wheel or runner prefix to fun name to use wheel or runner client
|
||||
funparts = cmd.get('fun', '').split('.')
|
||||
if len(funparts) > 2 and funparts[0] in ['wheel', 'runner']: # master
|
||||
funparts = cmd.get(u'fun', u'').split(u'.')
|
||||
if len(funparts) > 2 and funparts[0] in [u'wheel', u'runner']: # master
|
||||
client = funparts[0]
|
||||
cmd['fun'] = '.'.join(funparts[1:]) # strip prefix
|
||||
cmd[u'fun'] = u'.'.join(funparts[1:]) # strip prefix
|
||||
|
||||
if not ('token' in cmd or
|
||||
('eauth' in cmd and 'password' in cmd and 'username' in cmd)):
|
||||
raise EauthAuthenticationError('No authentication credentials given')
|
||||
if not (u'token' in cmd or
|
||||
(u'eauth' in cmd and u'password' in cmd and u'username' in cmd)):
|
||||
raise EauthAuthenticationError(u'No authentication credentials given')
|
||||
|
||||
executor = getattr(self, '{0}_{1}'.format(client, mode))
|
||||
executor = getattr(self, u'{0}_{1}'.format(client, mode))
|
||||
result = executor(**cmd)
|
||||
return result
|
||||
|
||||
@ -204,9 +204,9 @@ class APIClient(object):
|
||||
|
||||
Adds client per the command.
|
||||
'''
|
||||
cmd['client'] = 'minion'
|
||||
if len(cmd['module'].split('.')) > 2 and cmd['module'].split('.')[0] in ['runner', 'wheel']:
|
||||
cmd['client'] = 'master'
|
||||
cmd[u'client'] = u'minion'
|
||||
if len(cmd[u'module'].split(u'.')) > 2 and cmd[u'module'].split(u'.')[0] in [u'runner', u'wheel']:
|
||||
cmd[u'client'] = u'master'
|
||||
return self._signature(cmd)
|
||||
|
||||
def _signature(self, cmd):
|
||||
@ -216,20 +216,20 @@ class APIClient(object):
|
||||
'''
|
||||
result = {}
|
||||
|
||||
client = cmd.get('client', 'minion')
|
||||
if client == 'minion':
|
||||
cmd['fun'] = 'sys.argspec'
|
||||
cmd['kwarg'] = dict(module=cmd['module'])
|
||||
client = cmd.get(u'client', u'minion')
|
||||
if client == u'minion':
|
||||
cmd[u'fun'] = u'sys.argspec'
|
||||
cmd[u'kwarg'] = dict(module=cmd[u'module'])
|
||||
result = self.run(cmd)
|
||||
elif client == 'master':
|
||||
parts = cmd['module'].split('.')
|
||||
elif client == u'master':
|
||||
parts = cmd[u'module'].split(u'.')
|
||||
client = parts[0]
|
||||
module = '.'.join(parts[1:]) # strip prefix
|
||||
if client == 'wheel':
|
||||
module = u'.'.join(parts[1:]) # strip prefix
|
||||
if client == u'wheel':
|
||||
functions = self.wheelClient.functions
|
||||
elif client == 'runner':
|
||||
elif client == u'runner':
|
||||
functions = self.runnerClient.functions
|
||||
result = {'master': salt.utils.argspec_report(functions, module)}
|
||||
result = {u'master': salt.utils.argspec_report(functions, module)}
|
||||
return result
|
||||
|
||||
def create_token(self, creds):
|
||||
@ -274,20 +274,20 @@ class APIClient(object):
|
||||
tokenage = self.resolver.mk_token(creds)
|
||||
except Exception as ex:
|
||||
raise EauthAuthenticationError(
|
||||
"Authentication failed with {0}.".format(repr(ex)))
|
||||
u"Authentication failed with {0}.".format(repr(ex)))
|
||||
|
||||
if 'token' not in tokenage:
|
||||
raise EauthAuthenticationError("Authentication failed with provided credentials.")
|
||||
if u'token' not in tokenage:
|
||||
raise EauthAuthenticationError(u"Authentication failed with provided credentials.")
|
||||
|
||||
# Grab eauth config for the current backend for the current user
|
||||
tokenage_eauth = self.opts['external_auth'][tokenage['eauth']]
|
||||
if tokenage['name'] in tokenage_eauth:
|
||||
tokenage['perms'] = tokenage_eauth[tokenage['name']]
|
||||
tokenage_eauth = self.opts[u'external_auth'][tokenage[u'eauth']]
|
||||
if tokenage[u'name'] in tokenage_eauth:
|
||||
tokenage[u'perms'] = tokenage_eauth[tokenage[u'name']]
|
||||
else:
|
||||
tokenage['perms'] = tokenage_eauth['*']
|
||||
tokenage[u'perms'] = tokenage_eauth[u'*']
|
||||
|
||||
tokenage['user'] = tokenage['name']
|
||||
tokenage['username'] = tokenage['name']
|
||||
tokenage[u'user'] = tokenage[u'name']
|
||||
tokenage[u'username'] = tokenage[u'name']
|
||||
|
||||
return tokenage
|
||||
|
||||
@ -300,11 +300,11 @@ class APIClient(object):
|
||||
result = self.resolver.get_token(token)
|
||||
except Exception as ex:
|
||||
raise EauthAuthenticationError(
|
||||
"Token validation failed with {0}.".format(repr(ex)))
|
||||
u"Token validation failed with {0}.".format(repr(ex)))
|
||||
|
||||
return result
|
||||
|
||||
def get_event(self, wait=0.25, tag='', full=False):
|
||||
def get_event(self, wait=0.25, tag=u'', full=False):
|
||||
'''
|
||||
Get a single salt event.
|
||||
If no events are available, then block for up to ``wait`` seconds.
|
||||
@ -322,4 +322,4 @@ class APIClient(object):
|
||||
Need to convert this to a master call with appropriate authentication
|
||||
|
||||
'''
|
||||
return self.event.fire_event(data, tagify(tag, 'wui'))
|
||||
return self.event.fire_event(data, tagify(tag, u'wui'))
|
||||
|
@ -23,10 +23,12 @@ import salt.utils.event
|
||||
import salt.utils.jid
|
||||
import salt.utils.job
|
||||
import salt.utils.lazy
|
||||
import salt.utils.platform
|
||||
import salt.utils.process
|
||||
import salt.utils.versions
|
||||
import salt.transport
|
||||
import salt.log.setup
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
|
||||
# Import 3rd-party libs
|
||||
import tornado.stack_context
|
||||
@ -34,18 +36,18 @@ import tornado.stack_context
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
CLIENT_INTERNAL_KEYWORDS = frozenset([
|
||||
'client',
|
||||
'cmd',
|
||||
'eauth',
|
||||
'fun',
|
||||
'kwarg',
|
||||
'match',
|
||||
'token',
|
||||
'__jid__',
|
||||
'__tag__',
|
||||
'__user__',
|
||||
'username',
|
||||
'password'
|
||||
u'client',
|
||||
u'cmd',
|
||||
u'eauth',
|
||||
u'fun',
|
||||
u'kwarg',
|
||||
u'match',
|
||||
u'token',
|
||||
u'__jid__',
|
||||
u'__tag__',
|
||||
u'__user__',
|
||||
u'username',
|
||||
u'password'
|
||||
])
|
||||
|
||||
|
||||
@ -77,9 +79,9 @@ class ClientFuncsDict(collections.MutableMapping):
|
||||
raise KeyError
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
low = {'fun': key,
|
||||
'args': args,
|
||||
'kwargs': kwargs,
|
||||
low = {u'fun': key,
|
||||
u'args': args,
|
||||
u'kwargs': kwargs,
|
||||
}
|
||||
pub_data = {}
|
||||
# Copy kwargs keys so we can iterate over and pop the pub data
|
||||
@ -87,18 +89,18 @@ class ClientFuncsDict(collections.MutableMapping):
|
||||
|
||||
# pull out pub_data if you have it
|
||||
for kwargs_key in kwargs_keys:
|
||||
if kwargs_key.startswith('__pub_'):
|
||||
if kwargs_key.startswith(u'__pub_'):
|
||||
pub_data[kwargs_key] = kwargs.pop(kwargs_key)
|
||||
|
||||
async_pub = self.client._gen_async_pub(pub_data.get('__pub_jid'))
|
||||
async_pub = self.client._gen_async_pub(pub_data.get(u'__pub_jid'))
|
||||
|
||||
user = salt.utils.get_specific_user()
|
||||
return self.client._proc_function(
|
||||
key,
|
||||
low,
|
||||
user,
|
||||
async_pub['tag'], # TODO: fix
|
||||
async_pub['jid'], # TODO: fix
|
||||
async_pub[u'tag'], # TODO: fix
|
||||
async_pub[u'jid'], # TODO: fix
|
||||
False, # Don't daemonize
|
||||
)
|
||||
return wrapper
|
||||
@ -129,14 +131,14 @@ class SyncClientMixin(object):
|
||||
Execute a function through the master network interface.
|
||||
'''
|
||||
load = kwargs
|
||||
load['cmd'] = self.client
|
||||
load[u'cmd'] = self.client
|
||||
channel = salt.transport.Channel.factory(self.opts,
|
||||
crypt='clear',
|
||||
usage='master_call')
|
||||
crypt=u'clear',
|
||||
usage=u'master_call')
|
||||
ret = channel.send(load)
|
||||
if isinstance(ret, collections.Mapping):
|
||||
if 'error' in ret:
|
||||
salt.utils.error.raise_error(**ret['error'])
|
||||
if u'error' in ret:
|
||||
salt.utils.error.raise_error(**ret[u'error'])
|
||||
return ret
|
||||
|
||||
def cmd_sync(self, low, timeout=None, full_return=False):
|
||||
@ -155,19 +157,19 @@ class SyncClientMixin(object):
|
||||
'eauth': 'pam',
|
||||
})
|
||||
'''
|
||||
event = salt.utils.event.get_master_event(self.opts, self.opts['sock_dir'], listen=True)
|
||||
event = salt.utils.event.get_master_event(self.opts, self.opts[u'sock_dir'], listen=True)
|
||||
job = self.master_call(**low)
|
||||
ret_tag = salt.utils.event.tagify('ret', base=job['tag'])
|
||||
ret_tag = salt.utils.event.tagify(u'ret', base=job[u'tag'])
|
||||
|
||||
if timeout is None:
|
||||
timeout = self.opts.get('rest_timeout', 300)
|
||||
timeout = self.opts.get(u'rest_timeout', 300)
|
||||
ret = event.get_event(tag=ret_tag, full=True, wait=timeout, auto_reconnect=True)
|
||||
if ret is None:
|
||||
raise salt.exceptions.SaltClientTimeout(
|
||||
"RunnerClient job '{0}' timed out".format(job['jid']),
|
||||
jid=job['jid'])
|
||||
u"RunnerClient job '{0}' timed out".format(job[u'jid']),
|
||||
jid=job[u'jid'])
|
||||
|
||||
return ret if full_return else ret['data']['return']
|
||||
return ret if full_return else ret[u'data'][u'return']
|
||||
|
||||
def cmd(self, fun, arg=None, pub_data=None, kwarg=None, print_event=True, full_return=False):
|
||||
'''
|
||||
@ -202,40 +204,40 @@ class SyncClientMixin(object):
|
||||
arg = tuple()
|
||||
if not isinstance(arg, list) and not isinstance(arg, tuple):
|
||||
raise salt.exceptions.SaltInvocationError(
|
||||
'arg must be formatted as a list/tuple'
|
||||
u'arg must be formatted as a list/tuple'
|
||||
)
|
||||
if pub_data is None:
|
||||
pub_data = {}
|
||||
if not isinstance(pub_data, dict):
|
||||
raise salt.exceptions.SaltInvocationError(
|
||||
'pub_data must be formatted as a dictionary'
|
||||
u'pub_data must be formatted as a dictionary'
|
||||
)
|
||||
if kwarg is None:
|
||||
kwarg = {}
|
||||
if not isinstance(kwarg, dict):
|
||||
raise salt.exceptions.SaltInvocationError(
|
||||
'kwarg must be formatted as a dictionary'
|
||||
u'kwarg must be formatted as a dictionary'
|
||||
)
|
||||
arglist = salt.utils.args.parse_input(
|
||||
arg,
|
||||
no_parse=self.opts.get('no_parse', []))
|
||||
no_parse=self.opts.get(u'no_parse', []))
|
||||
|
||||
# if you were passed kwarg, add it to arglist
|
||||
if kwarg:
|
||||
kwarg['__kwarg__'] = True
|
||||
kwarg[u'__kwarg__'] = True
|
||||
arglist.append(kwarg)
|
||||
|
||||
args, kwargs = salt.minion.load_args_and_kwargs(
|
||||
self.functions[fun], arglist, pub_data
|
||||
)
|
||||
low = {'fun': fun,
|
||||
'arg': args,
|
||||
'kwarg': kwargs}
|
||||
low = {u'fun': fun,
|
||||
u'arg': args,
|
||||
u'kwarg': kwargs}
|
||||
return self.low(fun, low, print_event=print_event, full_return=full_return)
|
||||
|
||||
@property
|
||||
def mminion(self):
|
||||
if not hasattr(self, '_mminion'):
|
||||
if not hasattr(self, u'_mminion'):
|
||||
self._mminion = salt.minion.MasterMinion(self.opts, states=False, rend=False)
|
||||
return self._mminion
|
||||
|
||||
@ -244,15 +246,15 @@ class SyncClientMixin(object):
|
||||
Check for deprecated usage and allow until Salt Oxygen.
|
||||
'''
|
||||
msg = []
|
||||
if 'args' in low:
|
||||
msg.append('call with arg instead')
|
||||
low['arg'] = low.pop('args')
|
||||
if 'kwargs' in low:
|
||||
msg.append('call with kwarg instead')
|
||||
low['kwarg'] = low.pop('kwargs')
|
||||
if u'args' in low:
|
||||
msg.append(u'call with arg instead')
|
||||
low[u'arg'] = low.pop(u'args')
|
||||
if u'kwargs' in low:
|
||||
msg.append(u'call with kwarg instead')
|
||||
low[u'kwarg'] = low.pop(u'kwargs')
|
||||
|
||||
if msg:
|
||||
salt.utils.warn_until('Oxygen', ' '.join(msg))
|
||||
salt.utils.versions.warn_until(u'Oxygen', u' '.join(msg))
|
||||
|
||||
return self._low(fun, low, print_event=print_event, full_return=full_return)
|
||||
|
||||
@ -266,13 +268,13 @@ class SyncClientMixin(object):
|
||||
class_name = self.__class__.__name__.lower()
|
||||
except AttributeError:
|
||||
log.warning(
|
||||
'Unable to determine class name',
|
||||
u'Unable to determine class name',
|
||||
exc_info_on_loglevel=logging.DEBUG
|
||||
)
|
||||
return True
|
||||
|
||||
try:
|
||||
return self.opts['{0}_returns'.format(class_name)]
|
||||
return self.opts[u'{0}_returns'.format(class_name)]
|
||||
except KeyError:
|
||||
# No such option, assume this isn't one we care about gating and
|
||||
# just return True.
|
||||
@ -295,24 +297,24 @@ class SyncClientMixin(object):
|
||||
# this is not to clutter the output with the module loading
|
||||
# if we have a high debug level.
|
||||
self.mminion # pylint: disable=W0104
|
||||
jid = low.get('__jid__', salt.utils.jid.gen_jid())
|
||||
tag = low.get('__tag__', salt.utils.event.tagify(jid, prefix=self.tag_prefix))
|
||||
jid = low.get(u'__jid__', salt.utils.jid.gen_jid())
|
||||
tag = low.get(u'__tag__', salt.utils.event.tagify(jid, prefix=self.tag_prefix))
|
||||
|
||||
data = {'fun': '{0}.{1}'.format(self.client, fun),
|
||||
'jid': jid,
|
||||
'user': low.get('__user__', 'UNKNOWN'),
|
||||
data = {u'fun': u'{0}.{1}'.format(self.client, fun),
|
||||
u'jid': jid,
|
||||
u'user': low.get(u'__user__', u'UNKNOWN'),
|
||||
}
|
||||
|
||||
event = salt.utils.event.get_event(
|
||||
'master',
|
||||
self.opts['sock_dir'],
|
||||
self.opts['transport'],
|
||||
u'master',
|
||||
self.opts[u'sock_dir'],
|
||||
self.opts[u'transport'],
|
||||
opts=self.opts,
|
||||
listen=False)
|
||||
|
||||
if print_event:
|
||||
print_func = self.print_async_event \
|
||||
if hasattr(self, 'print_async_event') \
|
||||
if hasattr(self, u'print_async_event') \
|
||||
else None
|
||||
else:
|
||||
# Suppress printing of return event (this keeps us from printing
|
||||
@ -327,12 +329,12 @@ class SyncClientMixin(object):
|
||||
|
||||
# TODO: document these, and test that they exist
|
||||
# TODO: Other things to inject??
|
||||
func_globals = {'__jid__': jid,
|
||||
'__user__': data['user'],
|
||||
'__tag__': tag,
|
||||
func_globals = {u'__jid__': jid,
|
||||
u'__user__': data[u'user'],
|
||||
u'__tag__': tag,
|
||||
# weak ref to avoid the Exception in interpreter
|
||||
# teardown of event
|
||||
'__jid_event__': weakref.proxy(namespaced_event),
|
||||
u'__jid_event__': weakref.proxy(namespaced_event),
|
||||
}
|
||||
|
||||
try:
|
||||
@ -344,9 +346,9 @@ class SyncClientMixin(object):
|
||||
completed_funcs = []
|
||||
|
||||
for mod_name in six.iterkeys(self_functions):
|
||||
if '.' not in mod_name:
|
||||
if u'.' not in mod_name:
|
||||
continue
|
||||
mod, _ = mod_name.split('.', 1)
|
||||
mod, _ = mod_name.split(u'.', 1)
|
||||
if mod in completed_funcs:
|
||||
continue
|
||||
completed_funcs.append(mod)
|
||||
@ -362,86 +364,87 @@ class SyncClientMixin(object):
|
||||
# we make the transition we will load "kwargs" using format_call if
|
||||
# there are no kwargs in the low object passed in
|
||||
f_call = None
|
||||
if 'arg' not in low:
|
||||
if u'arg' not in low:
|
||||
f_call = salt.utils.format_call(
|
||||
self.functions[fun],
|
||||
low,
|
||||
expected_extra_kws=CLIENT_INTERNAL_KEYWORDS
|
||||
)
|
||||
args = f_call.get('args', ())
|
||||
args = f_call.get(u'args', ())
|
||||
else:
|
||||
args = low['arg']
|
||||
args = low[u'arg']
|
||||
|
||||
if 'kwarg' not in low:
|
||||
if u'kwarg' not in low:
|
||||
log.critical(
|
||||
'kwargs must be passed inside the low data within the '
|
||||
'\'kwarg\' key. See usage of '
|
||||
'salt.utils.args.parse_input() and '
|
||||
'salt.minion.load_args_and_kwargs() elsewhere in the '
|
||||
'codebase.'
|
||||
u'kwargs must be passed inside the low data within the '
|
||||
u'\'kwarg\' key. See usage of '
|
||||
u'salt.utils.args.parse_input() and '
|
||||
u'salt.minion.load_args_and_kwargs() elsewhere in the '
|
||||
u'codebase.'
|
||||
)
|
||||
kwargs = {}
|
||||
else:
|
||||
kwargs = low['kwarg']
|
||||
kwargs = low[u'kwarg']
|
||||
|
||||
# Update the event data with loaded args and kwargs
|
||||
data['fun_args'] = list(args) + ([kwargs] if kwargs else [])
|
||||
func_globals['__jid_event__'].fire_event(data, 'new')
|
||||
data[u'fun_args'] = list(args) + ([kwargs] if kwargs else [])
|
||||
func_globals[u'__jid_event__'].fire_event(data, u'new')
|
||||
|
||||
# Initialize a context for executing the method.
|
||||
with tornado.stack_context.StackContext(self.functions.context_dict.clone):
|
||||
data['return'] = self.functions[fun](*args, **kwargs)
|
||||
data['success'] = True
|
||||
if isinstance(data['return'], dict) and 'data' in data['return']:
|
||||
data[u'return'] = self.functions[fun](*args, **kwargs)
|
||||
data[u'success'] = True
|
||||
if isinstance(data[u'return'], dict) and u'data' in data[u'return']:
|
||||
# some functions can return boolean values
|
||||
data['success'] = salt.utils.check_state_result(data['return']['data'])
|
||||
data[u'success'] = salt.utils.check_state_result(data[u'return'][u'data'])
|
||||
except (Exception, SystemExit) as ex:
|
||||
if isinstance(ex, salt.exceptions.NotImplemented):
|
||||
data['return'] = str(ex)
|
||||
data[u'return'] = str(ex)
|
||||
else:
|
||||
data['return'] = 'Exception occurred in {0} {1}: {2}'.format(
|
||||
data[u'return'] = u'Exception occurred in {0} {1}: {2}'.format(
|
||||
self.client,
|
||||
fun,
|
||||
traceback.format_exc(),
|
||||
)
|
||||
data['success'] = False
|
||||
|
||||
namespaced_event.fire_event(data, 'ret')
|
||||
data[u'success'] = False
|
||||
|
||||
if self.store_job:
|
||||
try:
|
||||
salt.utils.job.store_job(
|
||||
self.opts,
|
||||
{
|
||||
'id': self.opts['id'],
|
||||
'tgt': self.opts['id'],
|
||||
'jid': data['jid'],
|
||||
'return': data,
|
||||
u'id': self.opts[u'id'],
|
||||
u'tgt': self.opts[u'id'],
|
||||
u'jid': data[u'jid'],
|
||||
u'return': data,
|
||||
},
|
||||
event=None,
|
||||
mminion=self.mminion,
|
||||
)
|
||||
except salt.exceptions.SaltCacheError:
|
||||
log.error('Could not store job cache info. '
|
||||
'Job details for this run may be unavailable.')
|
||||
log.error(u'Could not store job cache info. '
|
||||
u'Job details for this run may be unavailable.')
|
||||
|
||||
# Outputters _can_ mutate data so write to the job cache first!
|
||||
namespaced_event.fire_event(data, u'ret')
|
||||
|
||||
# if we fired an event, make sure to delete the event object.
|
||||
# This will ensure that we call destroy, which will do the 0MQ linger
|
||||
log.info('Runner completed: {0}'.format(data['jid']))
|
||||
log.info(u'Runner completed: %s', data[u'jid'])
|
||||
del event
|
||||
del namespaced_event
|
||||
return data if full_return else data['return']
|
||||
return data if full_return else data[u'return']
|
||||
|
||||
def get_docs(self, arg=None):
|
||||
'''
|
||||
Return a dictionary of functions and the inline documentation for each
|
||||
'''
|
||||
if arg:
|
||||
if '*' in arg:
|
||||
if u'*' in arg:
|
||||
target_mod = arg
|
||||
_use_fnmatch = True
|
||||
else:
|
||||
target_mod = arg + '.' if not arg.endswith('.') else arg
|
||||
target_mod = arg + u'.' if not arg.endswith(u'.') else arg
|
||||
if _use_fnmatch:
|
||||
docs = [(fun, self.functions[fun].__doc__)
|
||||
for fun in fnmatch.filter(self.functions, target_mod)]
|
||||
@ -468,7 +471,7 @@ class AsyncClientMixin(object):
|
||||
Run this method in a multiprocess target to execute the function in a
|
||||
multiprocess and fire the return data on the event bus
|
||||
'''
|
||||
if daemonize and not salt.utils.is_windows():
|
||||
if daemonize and not salt.utils.platform.is_windows():
|
||||
# Shutdown the multiprocessing before daemonizing
|
||||
salt.log.setup.shutdown_multiprocessing_logging()
|
||||
|
||||
@ -478,9 +481,9 @@ class AsyncClientMixin(object):
|
||||
salt.log.setup.setup_multiprocessing_logging()
|
||||
|
||||
# pack a few things into low
|
||||
low['__jid__'] = jid
|
||||
low['__user__'] = user
|
||||
low['__tag__'] = tag
|
||||
low[u'__jid__'] = jid
|
||||
low[u'__user__'] = user
|
||||
low[u'__tag__'] = tag
|
||||
|
||||
return self.low(fun, low, full_return=False)
|
||||
|
||||
@ -508,9 +511,9 @@ class AsyncClientMixin(object):
|
||||
if jid is None:
|
||||
jid = salt.utils.jid.gen_jid()
|
||||
tag = salt.utils.event.tagify(jid, prefix=self.tag_prefix)
|
||||
return {'tag': tag, 'jid': jid}
|
||||
return {u'tag': tag, u'jid': jid}
|
||||
|
||||
def async(self, fun, low, user='UNKNOWN', pub=None):
|
||||
def async(self, fun, low, user=u'UNKNOWN', pub=None):
|
||||
'''
|
||||
Execute the function in a multiprocess and return the event tag to use
|
||||
to watch for the return
|
||||
@ -519,7 +522,7 @@ class AsyncClientMixin(object):
|
||||
|
||||
proc = salt.utils.process.SignalHandlingMultiprocessingProcess(
|
||||
target=self._proc_function,
|
||||
args=(fun, low, user, async_pub['tag'], async_pub['jid']))
|
||||
args=(fun, low, user, async_pub[u'tag'], async_pub[u'jid']))
|
||||
with salt.utils.process.default_signals(signal.SIGINT, signal.SIGTERM):
|
||||
# Reset current signals before starting the process in
|
||||
# order not to inherit the current signal handlers
|
||||
@ -535,29 +538,29 @@ class AsyncClientMixin(object):
|
||||
return
|
||||
|
||||
# if we are "quiet", don't print
|
||||
if self.opts.get('quiet', False):
|
||||
if self.opts.get(u'quiet', False):
|
||||
return
|
||||
|
||||
# some suffixes we don't want to print
|
||||
if suffix in ('new',):
|
||||
if suffix in (u'new',):
|
||||
return
|
||||
|
||||
try:
|
||||
outputter = self.opts.get('output', event.get('outputter', None) or event.get('return').get('outputter'))
|
||||
outputter = self.opts.get(u'output', event.get(u'outputter', None) or event.get(u'return').get(u'outputter'))
|
||||
except AttributeError:
|
||||
outputter = None
|
||||
|
||||
# if this is a ret, we have our own set of rules
|
||||
if suffix == 'ret':
|
||||
if suffix == u'ret':
|
||||
# Check if outputter was passed in the return data. If this is the case,
|
||||
# then the return data will be a dict two keys: 'data' and 'outputter'
|
||||
if isinstance(event.get('return'), dict) \
|
||||
and set(event['return']) == set(('data', 'outputter')):
|
||||
event_data = event['return']['data']
|
||||
outputter = event['return']['outputter']
|
||||
if isinstance(event.get(u'return'), dict) \
|
||||
and set(event[u'return']) == set((u'data', u'outputter')):
|
||||
event_data = event[u'return'][u'data']
|
||||
outputter = event[u'return'][u'outputter']
|
||||
else:
|
||||
event_data = event['return']
|
||||
event_data = event[u'return']
|
||||
else:
|
||||
event_data = {'suffix': suffix, 'event': event}
|
||||
event_data = {u'suffix': suffix, u'event': event}
|
||||
|
||||
salt.output.display_output(event_data, outputter, self.opts)
|
||||
|
@ -20,7 +20,7 @@ class NetapiClient(object):
|
||||
'''
|
||||
def __init__(self, opts):
|
||||
self.opts = opts
|
||||
self.process_manager = salt.utils.process.ProcessManager(name='NetAPIProcessManager')
|
||||
self.process_manager = salt.utils.process.ProcessManager(name=u'NetAPIProcessManager')
|
||||
self.netapi = salt.loader.netapi(self.opts)
|
||||
|
||||
def run(self):
|
||||
@ -28,11 +28,11 @@ class NetapiClient(object):
|
||||
Load and start all available api modules
|
||||
'''
|
||||
if not len(self.netapi):
|
||||
log.error("Did not find any netapi configurations, nothing to start")
|
||||
log.error(u"Did not find any netapi configurations, nothing to start")
|
||||
|
||||
for fun in self.netapi:
|
||||
if fun.endswith('.start'):
|
||||
log.info('Starting {0} netapi module'.format(fun))
|
||||
if fun.endswith(u'.start'):
|
||||
log.info(u'Starting %s netapi module', fun)
|
||||
self.process_manager.add_process(self.netapi[fun])
|
||||
|
||||
# Install the SIGINT/SIGTERM handlers if not done so far
|
||||
|
@ -12,9 +12,9 @@ import logging
|
||||
# Import Salt libs
|
||||
import salt.config
|
||||
import salt.client
|
||||
import salt.utils
|
||||
import salt.utils.kinds as kinds
|
||||
import salt.utils.versions
|
||||
import salt.syspaths as syspaths
|
||||
from salt.utils import kinds
|
||||
|
||||
try:
|
||||
from raet import raeting, nacling
|
||||
@ -32,7 +32,7 @@ class LocalClient(salt.client.LocalClient):
|
||||
The RAET LocalClient
|
||||
'''
|
||||
def __init__(self,
|
||||
c_path=os.path.join(syspaths.CONFIG_DIR, 'master'),
|
||||
c_path=os.path.join(syspaths.CONFIG_DIR, u'master'),
|
||||
mopts=None):
|
||||
|
||||
salt.client.LocalClient.__init__(self, c_path, mopts)
|
||||
@ -41,22 +41,22 @@ class LocalClient(salt.client.LocalClient):
|
||||
tgt,
|
||||
fun,
|
||||
arg=(),
|
||||
tgt_type='glob',
|
||||
ret='',
|
||||
jid='',
|
||||
tgt_type=u'glob',
|
||||
ret=u'',
|
||||
jid=u'',
|
||||
timeout=5,
|
||||
**kwargs):
|
||||
'''
|
||||
Publish the command!
|
||||
'''
|
||||
if 'expr_form' in kwargs:
|
||||
salt.utils.warn_until(
|
||||
'Fluorine',
|
||||
'The target type should be passed using the \'tgt_type\' '
|
||||
'argument instead of \'expr_form\'. Support for using '
|
||||
'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
if u'expr_form' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
u'Fluorine',
|
||||
u'The target type should be passed using the \'tgt_type\' '
|
||||
u'argument instead of \'expr_form\'. Support for using '
|
||||
u'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
)
|
||||
tgt_type = kwargs.pop('expr_form')
|
||||
tgt_type = kwargs.pop(u'expr_form')
|
||||
|
||||
payload_kwargs = self._prep_pub(
|
||||
tgt,
|
||||
@ -68,21 +68,21 @@ class LocalClient(salt.client.LocalClient):
|
||||
timeout=timeout,
|
||||
**kwargs)
|
||||
|
||||
kind = self.opts['__role']
|
||||
kind = self.opts[u'__role']
|
||||
if kind not in kinds.APPL_KINDS:
|
||||
emsg = ("Invalid application kind = '{0}' for Raet LocalClient.".format(kind))
|
||||
log.error(emsg + "\n")
|
||||
emsg = (u"Invalid application kind = '{0}' for Raet LocalClient.".format(kind))
|
||||
log.error(emsg + u"\n")
|
||||
raise ValueError(emsg)
|
||||
if kind in [kinds.APPL_KIND_NAMES[kinds.applKinds.master],
|
||||
kinds.APPL_KIND_NAMES[kinds.applKinds.syndic]]:
|
||||
lanename = 'master'
|
||||
lanename = u'master'
|
||||
else:
|
||||
emsg = ("Unsupported application kind '{0}' for Raet LocalClient.".format(kind))
|
||||
log.error(emsg + '\n')
|
||||
emsg = (u"Unsupported application kind '{0}' for Raet LocalClient.".format(kind))
|
||||
log.error(emsg + u'\n')
|
||||
raise ValueError(emsg)
|
||||
|
||||
sockdirpath = self.opts['sock_dir']
|
||||
name = 'client' + nacling.uuid(size=18)
|
||||
sockdirpath = self.opts[u'sock_dir']
|
||||
name = u'client' + nacling.uuid(size=18)
|
||||
stack = LaneStack(
|
||||
name=name,
|
||||
lanename=lanename,
|
||||
@ -91,12 +91,12 @@ class LocalClient(salt.client.LocalClient):
|
||||
manor_yard = RemoteYard(
|
||||
stack=stack,
|
||||
lanename=lanename,
|
||||
name='manor',
|
||||
name=u'manor',
|
||||
dirpath=sockdirpath)
|
||||
stack.addRemote(manor_yard)
|
||||
route = {'dst': (None, manor_yard.name, 'local_cmd'),
|
||||
'src': (None, stack.local.name, None)}
|
||||
msg = {'route': route, 'load': payload_kwargs}
|
||||
route = {u'dst': (None, manor_yard.name, u'local_cmd'),
|
||||
u'src': (None, stack.local.name, None)}
|
||||
msg = {u'route': route, u'load': payload_kwargs}
|
||||
stack.transmit(msg)
|
||||
stack.serviceAll()
|
||||
while True:
|
||||
@ -104,9 +104,9 @@ class LocalClient(salt.client.LocalClient):
|
||||
stack.serviceAll()
|
||||
while stack.rxMsgs:
|
||||
msg, sender = stack.rxMsgs.popleft()
|
||||
ret = msg.get('return', {})
|
||||
if 'ret' in ret:
|
||||
ret = msg.get(u'return', {})
|
||||
if u'ret' in ret:
|
||||
stack.server.close()
|
||||
return ret['ret']
|
||||
return ret[u'ret']
|
||||
stack.server.close()
|
||||
return ret
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@ import random
|
||||
|
||||
# Import Salt libs
|
||||
import salt.config
|
||||
import salt.utils.versions
|
||||
import salt.syspaths as syspaths
|
||||
from salt.exceptions import SaltClientError # Temporary
|
||||
|
||||
@ -22,7 +23,7 @@ class SSHClient(object):
|
||||
.. versionadded:: 2015.5.0
|
||||
'''
|
||||
def __init__(self,
|
||||
c_path=os.path.join(syspaths.CONFIG_DIR, 'master'),
|
||||
c_path=os.path.join(syspaths.CONFIG_DIR, u'master'),
|
||||
mopts=None,
|
||||
disable_custom_roster=False):
|
||||
if mopts:
|
||||
@ -30,15 +31,14 @@ class SSHClient(object):
|
||||
else:
|
||||
if os.path.isdir(c_path):
|
||||
log.warning(
|
||||
'{0} expects a file path not a directory path({1}) to '
|
||||
'it\'s \'c_path\' keyword argument'.format(
|
||||
u'%s expects a file path not a directory path(%s) to '
|
||||
u'its \'c_path\' keyword argument',
|
||||
self.__class__.__name__, c_path
|
||||
)
|
||||
)
|
||||
self.opts = salt.config.client_config(c_path)
|
||||
|
||||
# Salt API should never offer a custom roster!
|
||||
self.opts['__disable_custom_roster'] = disable_custom_roster
|
||||
self.opts[u'__disable_custom_roster'] = disable_custom_roster
|
||||
|
||||
def _prep_ssh(
|
||||
self,
|
||||
@ -46,30 +46,30 @@ class SSHClient(object):
|
||||
fun,
|
||||
arg=(),
|
||||
timeout=None,
|
||||
tgt_type='glob',
|
||||
tgt_type=u'glob',
|
||||
kwarg=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Prepare the arguments
|
||||
'''
|
||||
if 'expr_form' in kwargs:
|
||||
salt.utils.warn_until(
|
||||
'Fluorine',
|
||||
'The target type should be passed using the \'tgt_type\' '
|
||||
'argument instead of \'expr_form\'. Support for using '
|
||||
'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
if u'expr_form' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
u'Fluorine',
|
||||
u'The target type should be passed using the \'tgt_type\' '
|
||||
u'argument instead of \'expr_form\'. Support for using '
|
||||
u'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
)
|
||||
tgt_type = kwargs.pop('expr_form')
|
||||
tgt_type = kwargs.pop(u'expr_form')
|
||||
|
||||
opts = copy.deepcopy(self.opts)
|
||||
opts.update(kwargs)
|
||||
if timeout:
|
||||
opts['timeout'] = timeout
|
||||
opts[u'timeout'] = timeout
|
||||
arg = salt.utils.args.condition_input(arg, kwarg)
|
||||
opts['argv'] = [fun] + arg
|
||||
opts['selected_target_option'] = tgt_type
|
||||
opts['tgt'] = tgt
|
||||
opts['arg'] = arg
|
||||
opts[u'argv'] = [fun] + arg
|
||||
opts[u'selected_target_option'] = tgt_type
|
||||
opts[u'tgt'] = tgt
|
||||
opts[u'arg'] = arg
|
||||
return salt.client.ssh.SSH(opts)
|
||||
|
||||
def cmd_iter(
|
||||
@ -78,8 +78,8 @@ class SSHClient(object):
|
||||
fun,
|
||||
arg=(),
|
||||
timeout=None,
|
||||
tgt_type='glob',
|
||||
ret='',
|
||||
tgt_type=u'glob',
|
||||
ret=u'',
|
||||
kwarg=None,
|
||||
**kwargs):
|
||||
'''
|
||||
@ -88,14 +88,14 @@ class SSHClient(object):
|
||||
|
||||
.. versionadded:: 2015.5.0
|
||||
'''
|
||||
if 'expr_form' in kwargs:
|
||||
salt.utils.warn_until(
|
||||
'Fluorine',
|
||||
'The target type should be passed using the \'tgt_type\' '
|
||||
'argument instead of \'expr_form\'. Support for using '
|
||||
'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
if u'expr_form' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
u'Fluorine',
|
||||
u'The target type should be passed using the \'tgt_type\' '
|
||||
u'argument instead of \'expr_form\'. Support for using '
|
||||
u'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
)
|
||||
tgt_type = kwargs.pop('expr_form')
|
||||
tgt_type = kwargs.pop(u'expr_form')
|
||||
|
||||
ssh = self._prep_ssh(
|
||||
tgt,
|
||||
@ -105,7 +105,7 @@ class SSHClient(object):
|
||||
tgt_type,
|
||||
kwarg,
|
||||
**kwargs)
|
||||
for ret in ssh.run_iter(jid=kwargs.get('jid', None)):
|
||||
for ret in ssh.run_iter(jid=kwargs.get(u'jid', None)):
|
||||
yield ret
|
||||
|
||||
def cmd(self,
|
||||
@ -113,7 +113,7 @@ class SSHClient(object):
|
||||
fun,
|
||||
arg=(),
|
||||
timeout=None,
|
||||
tgt_type='glob',
|
||||
tgt_type=u'glob',
|
||||
kwarg=None,
|
||||
**kwargs):
|
||||
'''
|
||||
@ -122,14 +122,14 @@ class SSHClient(object):
|
||||
|
||||
.. versionadded:: 2015.5.0
|
||||
'''
|
||||
if 'expr_form' in kwargs:
|
||||
salt.utils.warn_until(
|
||||
'Fluorine',
|
||||
'The target type should be passed using the \'tgt_type\' '
|
||||
'argument instead of \'expr_form\'. Support for using '
|
||||
'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
if u'expr_form' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
u'Fluorine',
|
||||
u'The target type should be passed using the \'tgt_type\' '
|
||||
u'argument instead of \'expr_form\'. Support for using '
|
||||
u'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
)
|
||||
tgt_type = kwargs.pop('expr_form')
|
||||
tgt_type = kwargs.pop(u'expr_form')
|
||||
|
||||
ssh = self._prep_ssh(
|
||||
tgt,
|
||||
@ -140,7 +140,7 @@ class SSHClient(object):
|
||||
kwarg,
|
||||
**kwargs)
|
||||
final = {}
|
||||
for ret in ssh.run_iter(jid=kwargs.get('jid', None)):
|
||||
for ret in ssh.run_iter(jid=kwargs.get(u'jid', None)):
|
||||
final.update(ret)
|
||||
return final
|
||||
|
||||
@ -166,16 +166,16 @@ class SSHClient(object):
|
||||
|
||||
kwargs = copy.deepcopy(low)
|
||||
|
||||
for ignore in ['tgt', 'fun', 'arg', 'timeout', 'tgt_type', 'kwarg']:
|
||||
for ignore in [u'tgt', u'fun', u'arg', u'timeout', u'tgt_type', u'kwarg']:
|
||||
if ignore in kwargs:
|
||||
del kwargs[ignore]
|
||||
|
||||
return self.cmd(low['tgt'],
|
||||
low['fun'],
|
||||
low.get('arg', []),
|
||||
low.get('timeout'),
|
||||
low.get('tgt_type'),
|
||||
low.get('kwarg'),
|
||||
return self.cmd(low[u'tgt'],
|
||||
low[u'fun'],
|
||||
low.get(u'arg', []),
|
||||
low.get(u'timeout'),
|
||||
low.get(u'tgt_type'),
|
||||
low.get(u'kwarg'),
|
||||
**kwargs)
|
||||
|
||||
def cmd_async(self, low, timeout=None):
|
||||
@ -204,8 +204,8 @@ class SSHClient(object):
|
||||
fun,
|
||||
arg=(),
|
||||
timeout=None,
|
||||
tgt_type='glob',
|
||||
ret='',
|
||||
tgt_type=u'glob',
|
||||
ret=u'',
|
||||
kwarg=None,
|
||||
sub=3,
|
||||
**kwargs):
|
||||
@ -226,24 +226,24 @@ class SSHClient(object):
|
||||
|
||||
.. versionadded:: 2017.7.0
|
||||
'''
|
||||
if 'expr_form' in kwargs:
|
||||
salt.utils.warn_until(
|
||||
'Fluorine',
|
||||
'The target type should be passed using the \'tgt_type\' '
|
||||
'argument instead of \'expr_form\'. Support for using '
|
||||
'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
if u'expr_form' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
u'Fluorine',
|
||||
u'The target type should be passed using the \'tgt_type\' '
|
||||
u'argument instead of \'expr_form\'. Support for using '
|
||||
u'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
)
|
||||
tgt_type = kwargs.pop('expr_form')
|
||||
tgt_type = kwargs.pop(u'expr_form')
|
||||
minion_ret = self.cmd(tgt,
|
||||
'sys.list_functions',
|
||||
u'sys.list_functions',
|
||||
tgt_type=tgt_type,
|
||||
**kwargs)
|
||||
minions = list(minion_ret)
|
||||
random.shuffle(minions)
|
||||
f_tgt = []
|
||||
for minion in minions:
|
||||
if fun in minion_ret[minion]['return']:
|
||||
if fun in minion_ret[minion][u'return']:
|
||||
f_tgt.append(minion)
|
||||
if len(f_tgt) >= sub:
|
||||
break
|
||||
return self.cmd_iter(f_tgt, fun, arg, timeout, tgt_type='list', ret=ret, kwarg=kwarg, **kwargs)
|
||||
return self.cmd_iter(f_tgt, fun, arg, timeout, tgt_type=u'list', ret=ret, kwarg=kwarg, **kwargs)
|
||||
|
@ -21,12 +21,12 @@ import salt.utils.vt
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
SSH_PASSWORD_PROMPT_RE = re.compile(r'(?:.*)[Pp]assword(?: for .*)?:', re.M)
|
||||
KEY_VALID_RE = re.compile(r'.*\(yes\/no\).*')
|
||||
SSH_PASSWORD_PROMPT_RE = re.compile(r'(?:.*)[Pp]assword(?: for .*)?:', re.M) # future lint: disable=non-unicode-string
|
||||
KEY_VALID_RE = re.compile(r'.*\(yes\/no\).*') # future lint: disable=non-unicode-string
|
||||
|
||||
# Keep these in sync with ./__init__.py
|
||||
RSTR = '_edbc7885e4f9aac9b83b35999b68d015148caf467b78fa39c05f669c0ff89878'
|
||||
RSTR_RE = re.compile(r'(?:^|\r?\n)' + RSTR + r'(?:\r?\n|$)')
|
||||
RSTR = u'_edbc7885e4f9aac9b83b35999b68d015148caf467b78fa39c05f669c0ff89878'
|
||||
RSTR_RE = re.compile(r'(?:^|\r?\n)' + RSTR + r'(?:\r?\n|$)') # future lint: disable=non-unicode-string
|
||||
|
||||
|
||||
class NoPasswdError(Exception):
|
||||
@ -41,7 +41,7 @@ def gen_key(path):
|
||||
'''
|
||||
Generate a key for use with salt-ssh
|
||||
'''
|
||||
cmd = 'ssh-keygen -P "" -f {0} -t rsa -q'.format(path)
|
||||
cmd = u'ssh-keygen -P "" -f {0} -t rsa -q'.format(path)
|
||||
if not os.path.isdir(os.path.dirname(path)):
|
||||
os.makedirs(os.path.dirname(path))
|
||||
subprocess.call(cmd, shell=True)
|
||||
@ -51,12 +51,12 @@ def gen_shell(opts, **kwargs):
|
||||
'''
|
||||
Return the correct shell interface for the target system
|
||||
'''
|
||||
if kwargs['winrm']:
|
||||
if kwargs[u'winrm']:
|
||||
try:
|
||||
import saltwinshell
|
||||
shell = saltwinshell.Shell(opts, **kwargs)
|
||||
except ImportError:
|
||||
log.error('The saltwinshell library is not available')
|
||||
log.error(u'The saltwinshell library is not available')
|
||||
sys.exit(salt.defaults.exitcodes.EX_GENERIC)
|
||||
else:
|
||||
shell = Shell(opts, **kwargs)
|
||||
@ -86,7 +86,7 @@ class Shell(object):
|
||||
ssh_options=None):
|
||||
self.opts = opts
|
||||
# ssh <ipv6>, but scp [<ipv6]:/path
|
||||
self.host = host.strip('[]')
|
||||
self.host = host.strip(u'[]')
|
||||
self.user = user
|
||||
self.port = port
|
||||
self.passwd = str(passwd) if passwd else passwd
|
||||
@ -97,18 +97,18 @@ class Shell(object):
|
||||
self.mods = mods
|
||||
self.identities_only = identities_only
|
||||
self.remote_port_forwards = remote_port_forwards
|
||||
self.ssh_options = '' if ssh_options is None else ssh_options
|
||||
self.ssh_options = u'' if ssh_options is None else ssh_options
|
||||
|
||||
def get_error(self, errstr):
|
||||
'''
|
||||
Parse out an error and return a targeted error string
|
||||
'''
|
||||
for line in errstr.split('\n'):
|
||||
if line.startswith('ssh:'):
|
||||
for line in errstr.split(u'\n'):
|
||||
if line.startswith(u'ssh:'):
|
||||
return line
|
||||
if line.startswith('Pseudo-terminal'):
|
||||
if line.startswith(u'Pseudo-terminal'):
|
||||
continue
|
||||
if 'to the list of known hosts.' in line:
|
||||
if u'to the list of known hosts.' in line:
|
||||
continue
|
||||
return line
|
||||
return errstr
|
||||
@ -118,36 +118,36 @@ class Shell(object):
|
||||
Return options for the ssh command base for Salt to call
|
||||
'''
|
||||
options = [
|
||||
'KbdInteractiveAuthentication=no',
|
||||
u'KbdInteractiveAuthentication=no',
|
||||
]
|
||||
if self.passwd:
|
||||
options.append('PasswordAuthentication=yes')
|
||||
options.append(u'PasswordAuthentication=yes')
|
||||
else:
|
||||
options.append('PasswordAuthentication=no')
|
||||
if self.opts.get('_ssh_version', (0,)) > (4, 9):
|
||||
options.append('GSSAPIAuthentication=no')
|
||||
options.append('ConnectTimeout={0}'.format(self.timeout))
|
||||
if self.opts.get('ignore_host_keys'):
|
||||
options.append('StrictHostKeyChecking=no')
|
||||
if self.opts.get('no_host_keys'):
|
||||
options.extend(['StrictHostKeyChecking=no',
|
||||
'UserKnownHostsFile=/dev/null'])
|
||||
known_hosts = self.opts.get('known_hosts_file')
|
||||
options.append(u'PasswordAuthentication=no')
|
||||
if self.opts.get(u'_ssh_version', (0,)) > (4, 9):
|
||||
options.append(u'GSSAPIAuthentication=no')
|
||||
options.append(u'ConnectTimeout={0}'.format(self.timeout))
|
||||
if self.opts.get(u'ignore_host_keys'):
|
||||
options.append(u'StrictHostKeyChecking=no')
|
||||
if self.opts.get(u'no_host_keys'):
|
||||
options.extend([u'StrictHostKeyChecking=no',
|
||||
u'UserKnownHostsFile=/dev/null'])
|
||||
known_hosts = self.opts.get(u'known_hosts_file')
|
||||
if known_hosts and os.path.isfile(known_hosts):
|
||||
options.append('UserKnownHostsFile={0}'.format(known_hosts))
|
||||
options.append(u'UserKnownHostsFile={0}'.format(known_hosts))
|
||||
if self.port:
|
||||
options.append('Port={0}'.format(self.port))
|
||||
options.append(u'Port={0}'.format(self.port))
|
||||
if self.priv:
|
||||
options.append('IdentityFile={0}'.format(self.priv))
|
||||
options.append(u'IdentityFile={0}'.format(self.priv))
|
||||
if self.user:
|
||||
options.append('User={0}'.format(self.user))
|
||||
options.append(u'User={0}'.format(self.user))
|
||||
if self.identities_only:
|
||||
options.append('IdentitiesOnly=yes')
|
||||
options.append(u'IdentitiesOnly=yes')
|
||||
|
||||
ret = []
|
||||
for option in options:
|
||||
ret.append('-o {0} '.format(option))
|
||||
return ''.join(ret)
|
||||
ret.append(u'-o {0} '.format(option))
|
||||
return u''.join(ret)
|
||||
|
||||
def _passwd_opts(self):
|
||||
'''
|
||||
@ -156,41 +156,41 @@ class Shell(object):
|
||||
# TODO ControlMaster does not work without ControlPath
|
||||
# user could take advantage of it if they set ControlPath in their
|
||||
# ssh config. Also, ControlPersist not widely available.
|
||||
options = ['ControlMaster=auto',
|
||||
'StrictHostKeyChecking=no',
|
||||
options = [u'ControlMaster=auto',
|
||||
u'StrictHostKeyChecking=no',
|
||||
]
|
||||
if self.opts['_ssh_version'] > (4, 9):
|
||||
options.append('GSSAPIAuthentication=no')
|
||||
options.append('ConnectTimeout={0}'.format(self.timeout))
|
||||
if self.opts.get('ignore_host_keys'):
|
||||
options.append('StrictHostKeyChecking=no')
|
||||
if self.opts.get('no_host_keys'):
|
||||
options.extend(['StrictHostKeyChecking=no',
|
||||
'UserKnownHostsFile=/dev/null'])
|
||||
if self.opts[u'_ssh_version'] > (4, 9):
|
||||
options.append(u'GSSAPIAuthentication=no')
|
||||
options.append(u'ConnectTimeout={0}'.format(self.timeout))
|
||||
if self.opts.get(u'ignore_host_keys'):
|
||||
options.append(u'StrictHostKeyChecking=no')
|
||||
if self.opts.get(u'no_host_keys'):
|
||||
options.extend([u'StrictHostKeyChecking=no',
|
||||
u'UserKnownHostsFile=/dev/null'])
|
||||
|
||||
if self.passwd:
|
||||
options.extend(['PasswordAuthentication=yes',
|
||||
'PubkeyAuthentication=yes'])
|
||||
options.extend([u'PasswordAuthentication=yes',
|
||||
u'PubkeyAuthentication=yes'])
|
||||
else:
|
||||
options.extend(['PasswordAuthentication=no',
|
||||
'PubkeyAuthentication=yes',
|
||||
'KbdInteractiveAuthentication=no',
|
||||
'ChallengeResponseAuthentication=no',
|
||||
'BatchMode=yes'])
|
||||
options.extend([u'PasswordAuthentication=no',
|
||||
u'PubkeyAuthentication=yes',
|
||||
u'KbdInteractiveAuthentication=no',
|
||||
u'ChallengeResponseAuthentication=no',
|
||||
u'BatchMode=yes'])
|
||||
if self.port:
|
||||
options.append('Port={0}'.format(self.port))
|
||||
options.append(u'Port={0}'.format(self.port))
|
||||
if self.user:
|
||||
options.append('User={0}'.format(self.user))
|
||||
options.append(u'User={0}'.format(self.user))
|
||||
if self.identities_only:
|
||||
options.append('IdentitiesOnly=yes')
|
||||
options.append(u'IdentitiesOnly=yes')
|
||||
|
||||
ret = []
|
||||
for option in options:
|
||||
ret.append('-o {0} '.format(option))
|
||||
return ''.join(ret)
|
||||
ret.append(u'-o {0} '.format(option))
|
||||
return u''.join(ret)
|
||||
|
||||
def _ssh_opts(self):
|
||||
return ' '.join(['-o {0}'.format(opt)
|
||||
return u' '.join([u'-o {0}'.format(opt)
|
||||
for opt in self.ssh_options])
|
||||
|
||||
def _copy_id_str_old(self):
|
||||
@ -200,9 +200,9 @@ class Shell(object):
|
||||
if self.passwd:
|
||||
# Using single quotes prevents shell expansion and
|
||||
# passwords containing '$'
|
||||
return "{0} {1} '{2} -p {3} {4} {5}@{6}'".format(
|
||||
'ssh-copy-id',
|
||||
'-i {0}.pub'.format(self.priv),
|
||||
return u"{0} {1} '{2} -p {3} {4} {5}@{6}'".format(
|
||||
u'ssh-copy-id',
|
||||
u'-i {0}.pub'.format(self.priv),
|
||||
self._passwd_opts(),
|
||||
self.port,
|
||||
self._ssh_opts(),
|
||||
@ -218,9 +218,9 @@ class Shell(object):
|
||||
if self.passwd:
|
||||
# Using single quotes prevents shell expansion and
|
||||
# passwords containing '$'
|
||||
return "{0} {1} {2} -p {3} {4} {5}@{6}".format(
|
||||
'ssh-copy-id',
|
||||
'-i {0}.pub'.format(self.priv),
|
||||
return u"{0} {1} {2} -p {3} {4} {5}@{6}".format(
|
||||
u'ssh-copy-id',
|
||||
u'-i {0}.pub'.format(self.priv),
|
||||
self._passwd_opts(),
|
||||
self.port,
|
||||
self._ssh_opts(),
|
||||
@ -233,11 +233,11 @@ class Shell(object):
|
||||
Execute ssh-copy-id to plant the id file on the target
|
||||
'''
|
||||
stdout, stderr, retcode = self._run_cmd(self._copy_id_str_old())
|
||||
if salt.defaults.exitcodes.EX_OK != retcode and 'Usage' in stderr:
|
||||
if salt.defaults.exitcodes.EX_OK != retcode and u'Usage' in stderr:
|
||||
stdout, stderr, retcode = self._run_cmd(self._copy_id_str_new())
|
||||
return stdout, stderr, retcode
|
||||
|
||||
def _cmd_str(self, cmd, ssh='ssh'):
|
||||
def _cmd_str(self, cmd, ssh=u'ssh'):
|
||||
'''
|
||||
Return the cmd string to execute
|
||||
'''
|
||||
@ -246,21 +246,21 @@ class Shell(object):
|
||||
# need to deliver the SHIM to the remote host and execute it there
|
||||
|
||||
command = [ssh]
|
||||
if ssh != 'scp':
|
||||
if ssh != u'scp':
|
||||
command.append(self.host)
|
||||
if self.tty and ssh == 'ssh':
|
||||
command.append('-t -t')
|
||||
if self.tty and ssh == u'ssh':
|
||||
command.append(u'-t -t')
|
||||
if self.passwd or self.priv:
|
||||
command.append(self.priv and self._key_opts() or self._passwd_opts())
|
||||
if ssh != 'scp' and self.remote_port_forwards:
|
||||
command.append(' '.join(['-R {0}'.format(item)
|
||||
for item in self.remote_port_forwards.split(',')]))
|
||||
if ssh != u'scp' and self.remote_port_forwards:
|
||||
command.append(u' '.join([u'-R {0}'.format(item)
|
||||
for item in self.remote_port_forwards.split(u',')]))
|
||||
if self.ssh_options:
|
||||
command.append(self._ssh_opts())
|
||||
|
||||
command.append(cmd)
|
||||
|
||||
return ' '.join(command)
|
||||
return u' '.join(command)
|
||||
|
||||
def _old_run_cmd(self, cmd):
|
||||
'''
|
||||
@ -277,7 +277,7 @@ class Shell(object):
|
||||
data = proc.communicate()
|
||||
return data[0], data[1], proc.returncode
|
||||
except Exception:
|
||||
return ('local', 'Unknown Error', None)
|
||||
return (u'local', u'Unknown Error', None)
|
||||
|
||||
def _run_nb_cmd(self, cmd):
|
||||
'''
|
||||
@ -301,7 +301,7 @@ class Shell(object):
|
||||
err = self.get_error(err)
|
||||
yield out, err, rcode
|
||||
except Exception:
|
||||
yield ('', 'Unknown Error', None)
|
||||
yield (u'', u'Unknown Error', None)
|
||||
|
||||
def exec_nb_cmd(self, cmd):
|
||||
'''
|
||||
@ -312,9 +312,9 @@ class Shell(object):
|
||||
rcode = None
|
||||
cmd = self._cmd_str(cmd)
|
||||
|
||||
logmsg = 'Executing non-blocking command: {0}'.format(cmd)
|
||||
logmsg = u'Executing non-blocking command: {0}'.format(cmd)
|
||||
if self.passwd:
|
||||
logmsg = logmsg.replace(self.passwd, ('*' * 6))
|
||||
logmsg = logmsg.replace(self.passwd, (u'*' * 6))
|
||||
log.debug(logmsg)
|
||||
|
||||
for out, err, rcode in self._run_nb_cmd(cmd):
|
||||
@ -323,7 +323,7 @@ class Shell(object):
|
||||
if err is not None:
|
||||
r_err.append(err)
|
||||
yield None, None, None
|
||||
yield ''.join(r_out), ''.join(r_err), rcode
|
||||
yield u''.join(r_out), u''.join(r_err), rcode
|
||||
|
||||
def exec_cmd(self, cmd):
|
||||
'''
|
||||
@ -331,11 +331,11 @@ class Shell(object):
|
||||
'''
|
||||
cmd = self._cmd_str(cmd)
|
||||
|
||||
logmsg = 'Executing command: {0}'.format(cmd)
|
||||
logmsg = u'Executing command: {0}'.format(cmd)
|
||||
if self.passwd:
|
||||
logmsg = logmsg.replace(self.passwd, ('*' * 6))
|
||||
if 'decode("base64")' in logmsg or 'base64.b64decode(' in logmsg:
|
||||
log.debug('Executed SHIM command. Command logged to TRACE')
|
||||
logmsg = logmsg.replace(self.passwd, (u'*' * 6))
|
||||
if u'decode("base64")' in logmsg or u'base64.b64decode(' in logmsg:
|
||||
log.debug(u'Executed SHIM command. Command logged to TRACE')
|
||||
log.trace(logmsg)
|
||||
else:
|
||||
log.debug(logmsg)
|
||||
@ -348,19 +348,19 @@ class Shell(object):
|
||||
scp a file or files to a remote system
|
||||
'''
|
||||
if makedirs:
|
||||
self.exec_cmd('mkdir -p {0}'.format(os.path.dirname(remote)))
|
||||
self.exec_cmd(u'mkdir -p {0}'.format(os.path.dirname(remote)))
|
||||
|
||||
# scp needs [<ipv6}
|
||||
host = self.host
|
||||
if ':' in host:
|
||||
host = '[{0}]'.format(host)
|
||||
if u':' in host:
|
||||
host = u'[{0}]'.format(host)
|
||||
|
||||
cmd = '{0} {1}:{2}'.format(local, host, remote)
|
||||
cmd = self._cmd_str(cmd, ssh='scp')
|
||||
cmd = u'{0} {1}:{2}'.format(local, host, remote)
|
||||
cmd = self._cmd_str(cmd, ssh=u'scp')
|
||||
|
||||
logmsg = 'Executing command: {0}'.format(cmd)
|
||||
logmsg = u'Executing command: {0}'.format(cmd)
|
||||
if self.passwd:
|
||||
logmsg = logmsg.replace(self.passwd, ('*' * 6))
|
||||
logmsg = logmsg.replace(self.passwd, (u'*' * 6))
|
||||
log.debug(logmsg)
|
||||
|
||||
return self._run_cmd(cmd)
|
||||
@ -374,16 +374,16 @@ class Shell(object):
|
||||
cmd,
|
||||
shell=True,
|
||||
log_stdout=True,
|
||||
log_stdout_level='trace',
|
||||
log_stdout_level=u'trace',
|
||||
log_stderr=True,
|
||||
log_stderr_level='trace',
|
||||
log_stderr_level=u'trace',
|
||||
stream_stdout=False,
|
||||
stream_stderr=False)
|
||||
sent_passwd = 0
|
||||
send_password = True
|
||||
ret_stdout = ''
|
||||
ret_stderr = ''
|
||||
old_stdout = ''
|
||||
ret_stdout = u''
|
||||
ret_stderr = u''
|
||||
old_stdout = u''
|
||||
|
||||
try:
|
||||
while term.has_unread_data:
|
||||
@ -400,26 +400,26 @@ class Shell(object):
|
||||
send_password = False
|
||||
if buff and SSH_PASSWORD_PROMPT_RE.search(buff) and send_password:
|
||||
if not self.passwd:
|
||||
return '', 'Permission denied, no authentication information', 254
|
||||
return u'', u'Permission denied, no authentication information', 254
|
||||
if sent_passwd < passwd_retries:
|
||||
term.sendline(self.passwd)
|
||||
sent_passwd += 1
|
||||
continue
|
||||
else:
|
||||
# asking for a password, and we can't seem to send it
|
||||
return '', 'Password authentication failed', 254
|
||||
return u'', u'Password authentication failed', 254
|
||||
elif buff and KEY_VALID_RE.search(buff):
|
||||
if key_accept:
|
||||
term.sendline('yes')
|
||||
term.sendline(u'yes')
|
||||
continue
|
||||
else:
|
||||
term.sendline('no')
|
||||
ret_stdout = ('The host key needs to be accepted, to '
|
||||
'auto accept run salt-ssh with the -i '
|
||||
'flag:\n{0}').format(stdout)
|
||||
return ret_stdout, '', 254
|
||||
elif buff and buff.endswith('_||ext_mods||_'):
|
||||
mods_raw = json.dumps(self.mods, separators=(',', ':')) + '|_E|0|'
|
||||
term.sendline(u'no')
|
||||
ret_stdout = (u'The host key needs to be accepted, to '
|
||||
u'auto accept run salt-ssh with the -i '
|
||||
u'flag:\n{0}').format(stdout)
|
||||
return ret_stdout, u'', 254
|
||||
elif buff and buff.endswith(u'_||ext_mods||_'):
|
||||
mods_raw = json.dumps(self.mods, separators=(u',', u':')) + u'|_E|0|'
|
||||
term.sendline(mods_raw)
|
||||
if stdout:
|
||||
old_stdout = stdout
|
||||
|
@ -18,8 +18,8 @@ import os
|
||||
import stat
|
||||
import subprocess
|
||||
|
||||
THIN_ARCHIVE = 'salt-thin.tgz'
|
||||
EXT_ARCHIVE = 'salt-ext_mods.tgz'
|
||||
THIN_ARCHIVE = u'salt-thin.tgz'
|
||||
EXT_ARCHIVE = u'salt-ext_mods.tgz'
|
||||
|
||||
# Keep these in sync with salt/defaults/exitcodes.py
|
||||
EX_THIN_DEPLOY = 11
|
||||
@ -30,7 +30,9 @@ EX_CANTCREAT = 73
|
||||
|
||||
|
||||
class OBJ(object):
|
||||
"""An empty class for holding instance attribute values."""
|
||||
'''
|
||||
An empty class for holding instance attribute values.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
@ -52,7 +54,7 @@ def get_system_encoding():
|
||||
# and reset to None
|
||||
encoding = None
|
||||
|
||||
if not sys.platform.startswith('win') and sys.stdin is not None:
|
||||
if not sys.platform.startswith(u'win') and sys.stdin is not None:
|
||||
# On linux we can rely on sys.stdin for the encoding since it
|
||||
# most commonly matches the filesystem encoding. This however
|
||||
# does not apply to windows
|
||||
@ -78,16 +80,16 @@ def get_system_encoding():
|
||||
# the way back to ascii
|
||||
encoding = sys.getdefaultencoding()
|
||||
if not encoding:
|
||||
if sys.platform.startswith('darwin'):
|
||||
if sys.platform.startswith(u'darwin'):
|
||||
# Mac OS X uses UTF-8
|
||||
encoding = 'utf-8'
|
||||
elif sys.platform.startswith('win'):
|
||||
encoding = u'utf-8'
|
||||
elif sys.platform.startswith(u'win'):
|
||||
# Windows uses a configurable encoding; on Windows, Python uses the name "mbcs"
|
||||
# to refer to whatever the currently configured encoding is.
|
||||
encoding = 'mbcs'
|
||||
encoding = u'mbcs'
|
||||
else:
|
||||
# On linux default to ascii as a last resort
|
||||
encoding = 'ascii'
|
||||
encoding = u'ascii'
|
||||
return encoding
|
||||
|
||||
|
||||
@ -95,14 +97,14 @@ def is_windows():
|
||||
'''
|
||||
Simple function to return if a host is Windows or not
|
||||
'''
|
||||
return sys.platform.startswith('win')
|
||||
return sys.platform.startswith(u'win')
|
||||
|
||||
|
||||
def need_deployment():
|
||||
"""
|
||||
'''
|
||||
Salt thin needs to be deployed - prep the target directory and emit the
|
||||
delimeter and exit code that signals a required deployment.
|
||||
"""
|
||||
'''
|
||||
if os.path.exists(OPTIONS.saltdir):
|
||||
shutil.rmtree(OPTIONS.saltdir)
|
||||
old_umask = os.umask(0o077)
|
||||
@ -119,39 +121,43 @@ def need_deployment():
|
||||
# Attack detected
|
||||
need_deployment()
|
||||
# If SUDOing then also give the super user group write permissions
|
||||
sudo_gid = os.environ.get('SUDO_GID')
|
||||
sudo_gid = os.environ.get(u'SUDO_GID')
|
||||
if sudo_gid:
|
||||
try:
|
||||
os.chown(OPTIONS.saltdir, -1, int(sudo_gid))
|
||||
stt = os.stat(OPTIONS.saltdir)
|
||||
os.chmod(OPTIONS.saltdir, stt.st_mode | stat.S_IWGRP | stat.S_IRGRP | stat.S_IXGRP)
|
||||
except OSError:
|
||||
sys.stdout.write('\n\nUnable to set permissions on thin directory.\nIf sudo_user is set '
|
||||
'and is not root, be certain the user is in the same group\nas the login user')
|
||||
sys.stdout.write(u'\n\nUnable to set permissions on thin directory.\nIf sudo_user is set '
|
||||
u'and is not root, be certain the user is in the same group\nas the login user')
|
||||
sys.exit(1)
|
||||
|
||||
# Delimiter emitted on stdout *only* to indicate shim message to master.
|
||||
sys.stdout.write("{0}\ndeploy\n".format(OPTIONS.delimiter))
|
||||
sys.stdout.write(u"{0}\ndeploy\n".format(OPTIONS.delimiter))
|
||||
sys.exit(EX_THIN_DEPLOY)
|
||||
|
||||
|
||||
# Adapted from salt.utils.get_hash()
|
||||
def get_hash(path, form='sha1', chunk_size=4096):
|
||||
"""Generate a hash digest string for a file."""
|
||||
def get_hash(path, form=u'sha1', chunk_size=4096):
|
||||
'''
|
||||
Generate a hash digest string for a file.
|
||||
'''
|
||||
try:
|
||||
hash_type = getattr(hashlib, form)
|
||||
except AttributeError:
|
||||
raise ValueError('Invalid hash type: {0}'.format(form))
|
||||
with open(path, 'rb') as ifile:
|
||||
raise ValueError(u'Invalid hash type: {0}'.format(form))
|
||||
with open(path, u'rb') as ifile:
|
||||
hash_obj = hash_type()
|
||||
# read the file in in chunks, not the entire file
|
||||
for chunk in iter(lambda: ifile.read(chunk_size), b''):
|
||||
for chunk in iter(lambda: ifile.read(chunk_size), b''): # future lint: disable=non-unicode-string
|
||||
hash_obj.update(chunk)
|
||||
return hash_obj.hexdigest()
|
||||
|
||||
|
||||
def unpack_thin(thin_path):
|
||||
"""Unpack the Salt thin archive."""
|
||||
'''
|
||||
Unpack the Salt thin archive.
|
||||
'''
|
||||
tfile = tarfile.TarFile.gzopen(thin_path)
|
||||
old_umask = os.umask(0o077)
|
||||
tfile.extractall(path=OPTIONS.saltdir)
|
||||
@ -161,34 +167,40 @@ def unpack_thin(thin_path):
|
||||
|
||||
|
||||
def need_ext():
|
||||
"""Signal that external modules need to be deployed."""
|
||||
sys.stdout.write("{0}\next_mods\n".format(OPTIONS.delimiter))
|
||||
'''
|
||||
Signal that external modules need to be deployed.
|
||||
'''
|
||||
sys.stdout.write(u"{0}\next_mods\n".format(OPTIONS.delimiter))
|
||||
sys.exit(EX_MOD_DEPLOY)
|
||||
|
||||
|
||||
def unpack_ext(ext_path):
|
||||
"""Unpack the external modules."""
|
||||
'''
|
||||
Unpack the external modules.
|
||||
'''
|
||||
modcache = os.path.join(
|
||||
OPTIONS.saltdir,
|
||||
'running_data',
|
||||
'var',
|
||||
'cache',
|
||||
'salt',
|
||||
'minion',
|
||||
'extmods')
|
||||
u'running_data',
|
||||
u'var',
|
||||
u'cache',
|
||||
u'salt',
|
||||
u'minion',
|
||||
u'extmods')
|
||||
tfile = tarfile.TarFile.gzopen(ext_path)
|
||||
old_umask = os.umask(0o077)
|
||||
tfile.extractall(path=modcache)
|
||||
tfile.close()
|
||||
os.umask(old_umask)
|
||||
os.unlink(ext_path)
|
||||
ver_path = os.path.join(modcache, 'ext_version')
|
||||
ver_dst = os.path.join(OPTIONS.saltdir, 'ext_version')
|
||||
ver_path = os.path.join(modcache, u'ext_version')
|
||||
ver_dst = os.path.join(OPTIONS.saltdir, u'ext_version')
|
||||
shutil.move(ver_path, ver_dst)
|
||||
|
||||
|
||||
def main(argv): # pylint: disable=W0613
|
||||
"""Main program body"""
|
||||
'''
|
||||
Main program body
|
||||
'''
|
||||
thin_path = os.path.join(OPTIONS.saltdir, THIN_ARCHIVE)
|
||||
if os.path.isfile(thin_path):
|
||||
if OPTIONS.checksum != get_hash(thin_path, OPTIONS.hashfunc):
|
||||
@ -196,8 +208,8 @@ def main(argv): # pylint: disable=W0613
|
||||
unpack_thin(thin_path)
|
||||
# Salt thin now is available to use
|
||||
else:
|
||||
if not sys.platform.startswith('win'):
|
||||
scpstat = subprocess.Popen(['/bin/sh', '-c', 'command -v scp']).wait()
|
||||
if not sys.platform.startswith(u'win'):
|
||||
scpstat = subprocess.Popen([u'/bin/sh', u'-c', u'command -v scp']).wait()
|
||||
if scpstat != 0:
|
||||
sys.exit(EX_SCP_NOT_FOUND)
|
||||
|
||||
@ -206,46 +218,46 @@ def main(argv): # pylint: disable=W0613
|
||||
|
||||
if not os.path.isdir(OPTIONS.saltdir):
|
||||
sys.stderr.write(
|
||||
'ERROR: salt path "{0}" exists but is'
|
||||
' not a directory\n'.format(OPTIONS.saltdir)
|
||||
u'ERROR: salt path "{0}" exists but is'
|
||||
u' not a directory\n'.format(OPTIONS.saltdir)
|
||||
)
|
||||
sys.exit(EX_CANTCREAT)
|
||||
|
||||
version_path = os.path.normpath(os.path.join(OPTIONS.saltdir, 'version'))
|
||||
version_path = os.path.normpath(os.path.join(OPTIONS.saltdir, u'version'))
|
||||
if not os.path.exists(version_path) or not os.path.isfile(version_path):
|
||||
sys.stderr.write(
|
||||
'WARNING: Unable to locate current thin '
|
||||
' version: {0}.\n'.format(version_path)
|
||||
u'WARNING: Unable to locate current thin '
|
||||
u' version: {0}.\n'.format(version_path)
|
||||
)
|
||||
need_deployment()
|
||||
with open(version_path, 'r') as vpo:
|
||||
with open(version_path, u'r') as vpo:
|
||||
cur_version = vpo.readline().strip()
|
||||
if cur_version != OPTIONS.version:
|
||||
sys.stderr.write(
|
||||
'WARNING: current thin version {0}'
|
||||
' is not up-to-date with {1}.\n'.format(
|
||||
u'WARNING: current thin version {0}'
|
||||
u' is not up-to-date with {1}.\n'.format(
|
||||
cur_version, OPTIONS.version
|
||||
)
|
||||
)
|
||||
need_deployment()
|
||||
# Salt thin exists and is up-to-date - fall through and use it
|
||||
|
||||
salt_call_path = os.path.join(OPTIONS.saltdir, 'salt-call')
|
||||
salt_call_path = os.path.join(OPTIONS.saltdir, u'salt-call')
|
||||
if not os.path.isfile(salt_call_path):
|
||||
sys.stderr.write('ERROR: thin is missing "{0}"\n'.format(salt_call_path))
|
||||
sys.stderr.write(u'ERROR: thin is missing "{0}"\n'.format(salt_call_path))
|
||||
need_deployment()
|
||||
|
||||
with open(os.path.join(OPTIONS.saltdir, 'minion'), 'w') as config:
|
||||
config.write(OPTIONS.config + '\n')
|
||||
with open(os.path.join(OPTIONS.saltdir, u'minion'), u'w') as config:
|
||||
config.write(OPTIONS.config + u'\n')
|
||||
if OPTIONS.ext_mods:
|
||||
ext_path = os.path.join(OPTIONS.saltdir, EXT_ARCHIVE)
|
||||
if os.path.exists(ext_path):
|
||||
unpack_ext(ext_path)
|
||||
else:
|
||||
version_path = os.path.join(OPTIONS.saltdir, 'ext_version')
|
||||
version_path = os.path.join(OPTIONS.saltdir, u'ext_version')
|
||||
if not os.path.exists(version_path) or not os.path.isfile(version_path):
|
||||
need_ext()
|
||||
with open(version_path, 'r') as vpo:
|
||||
with open(version_path, u'r') as vpo:
|
||||
cur_version = vpo.readline().strip()
|
||||
if cur_version != OPTIONS.ext_mods:
|
||||
need_ext()
|
||||
@ -258,38 +270,38 @@ def main(argv): # pylint: disable=W0613
|
||||
salt_argv = [
|
||||
sys.executable,
|
||||
salt_call_path,
|
||||
'--retcode-passthrough',
|
||||
'--local',
|
||||
'--metadata',
|
||||
'--out', 'json',
|
||||
'-l', 'quiet',
|
||||
'-c', OPTIONS.saltdir
|
||||
u'--retcode-passthrough',
|
||||
u'--local',
|
||||
u'--metadata',
|
||||
u'--out', u'json',
|
||||
u'-l', u'quiet',
|
||||
u'-c', OPTIONS.saltdir
|
||||
]
|
||||
|
||||
try:
|
||||
if argv_prepared[-1].startswith('--no-parse='):
|
||||
if argv_prepared[-1].startswith(u'--no-parse='):
|
||||
salt_argv.append(argv_prepared.pop(-1))
|
||||
except (IndexError, TypeError):
|
||||
pass
|
||||
|
||||
salt_argv.append('--')
|
||||
salt_argv.append(u'--')
|
||||
salt_argv.extend(argv_prepared)
|
||||
|
||||
sys.stderr.write('SALT_ARGV: {0}\n'.format(salt_argv))
|
||||
sys.stderr.write(u'SALT_ARGV: {0}\n'.format(salt_argv))
|
||||
|
||||
# Only emit the delimiter on *both* stdout and stderr when completely successful.
|
||||
# Yes, the flush() is necessary.
|
||||
sys.stdout.write(OPTIONS.delimiter + '\n')
|
||||
sys.stdout.write(OPTIONS.delimiter + u'\n')
|
||||
sys.stdout.flush()
|
||||
if not OPTIONS.tty:
|
||||
sys.stderr.write(OPTIONS.delimiter + '\n')
|
||||
sys.stderr.write(OPTIONS.delimiter + u'\n')
|
||||
sys.stderr.flush()
|
||||
if OPTIONS.cmd_umask is not None:
|
||||
old_umask = os.umask(OPTIONS.cmd_umask)
|
||||
if OPTIONS.tty:
|
||||
# Returns bytes instead of string on python 3
|
||||
stdout, _ = subprocess.Popen(salt_argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
||||
sys.stdout.write(stdout.decode(encoding=get_system_encoding(), errors="replace"))
|
||||
sys.stdout.write(stdout.decode(encoding=get_system_encoding(), errors=u"replace"))
|
||||
sys.stdout.flush()
|
||||
if OPTIONS.wipe:
|
||||
shutil.rmtree(OPTIONS.saltdir)
|
||||
@ -301,5 +313,5 @@ def main(argv): # pylint: disable=W0613
|
||||
if OPTIONS.cmd_umask is not None:
|
||||
os.umask(old_umask)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == u'__main__':
|
||||
sys.exit(main(sys.argv))
|
||||
|
@ -24,6 +24,9 @@ import salt.state
|
||||
import salt.loader
|
||||
import salt.minion
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -82,35 +85,33 @@ class SSHHighState(salt.state.BaseHighState):
|
||||
'''
|
||||
Evaluate master_tops locally
|
||||
'''
|
||||
if 'id' not in self.opts:
|
||||
log.error('Received call for external nodes without an id')
|
||||
if u'id' not in self.opts:
|
||||
log.error(u'Received call for external nodes without an id')
|
||||
return {}
|
||||
if not salt.utils.verify.valid_id(self.opts, self.opts['id']):
|
||||
if not salt.utils.verify.valid_id(self.opts, self.opts[u'id']):
|
||||
return {}
|
||||
# Evaluate all configured master_tops interfaces
|
||||
|
||||
grains = {}
|
||||
ret = {}
|
||||
|
||||
if 'grains' in self.opts:
|
||||
grains = self.opts['grains']
|
||||
if u'grains' in self.opts:
|
||||
grains = self.opts[u'grains']
|
||||
for fun in self.tops:
|
||||
if fun not in self.opts.get('master_tops', {}):
|
||||
if fun not in self.opts.get(u'master_tops', {}):
|
||||
continue
|
||||
try:
|
||||
ret.update(self.tops[fun](opts=self.opts, grains=grains))
|
||||
except Exception as exc:
|
||||
# If anything happens in the top generation, log it and move on
|
||||
log.error(
|
||||
'Top function {0} failed with error {1} for minion '
|
||||
'{2}'.format(
|
||||
fun, exc, self.opts['id']
|
||||
)
|
||||
u'Top function %s failed with error %s for minion %s',
|
||||
fun, exc, self.opts[u'id']
|
||||
)
|
||||
return ret
|
||||
|
||||
|
||||
def lowstate_file_refs(chunks, extras=''):
|
||||
def lowstate_file_refs(chunks, extras=u''):
|
||||
'''
|
||||
Create a list of file ref objects to reconcile
|
||||
'''
|
||||
@ -118,12 +119,12 @@ def lowstate_file_refs(chunks, extras=''):
|
||||
for chunk in chunks:
|
||||
if not isinstance(chunk, dict):
|
||||
continue
|
||||
saltenv = 'base'
|
||||
saltenv = u'base'
|
||||
crefs = []
|
||||
for state in chunk:
|
||||
if state == '__env__':
|
||||
if state == u'__env__':
|
||||
saltenv = chunk[state]
|
||||
elif state.startswith('__'):
|
||||
elif state.startswith(u'__'):
|
||||
continue
|
||||
crefs.extend(salt_refs(chunk[state]))
|
||||
if crefs:
|
||||
@ -131,7 +132,7 @@ def lowstate_file_refs(chunks, extras=''):
|
||||
refs[saltenv] = []
|
||||
refs[saltenv].append(crefs)
|
||||
if extras:
|
||||
extra_refs = extras.split(',')
|
||||
extra_refs = extras.split(u',')
|
||||
if extra_refs:
|
||||
for env in refs:
|
||||
for x in extra_refs:
|
||||
@ -143,10 +144,10 @@ def salt_refs(data, ret=None):
|
||||
'''
|
||||
Pull salt file references out of the states
|
||||
'''
|
||||
proto = 'salt://'
|
||||
proto = u'salt://'
|
||||
if ret is None:
|
||||
ret = []
|
||||
if isinstance(data, str):
|
||||
if isinstance(data, six.string_types):
|
||||
if data.startswith(proto) and data not in ret:
|
||||
ret.append(data)
|
||||
if isinstance(data, list):
|
||||
@ -165,38 +166,38 @@ def prep_trans_tar(opts, file_client, chunks, file_refs, pillar=None, id_=None,
|
||||
'''
|
||||
gendir = tempfile.mkdtemp()
|
||||
trans_tar = salt.utils.files.mkstemp()
|
||||
lowfn = os.path.join(gendir, 'lowstate.json')
|
||||
pillarfn = os.path.join(gendir, 'pillar.json')
|
||||
roster_grainsfn = os.path.join(gendir, 'roster_grains.json')
|
||||
lowfn = os.path.join(gendir, u'lowstate.json')
|
||||
pillarfn = os.path.join(gendir, u'pillar.json')
|
||||
roster_grainsfn = os.path.join(gendir, u'roster_grains.json')
|
||||
sync_refs = [
|
||||
[salt.utils.url.create('_modules')],
|
||||
[salt.utils.url.create('_states')],
|
||||
[salt.utils.url.create('_grains')],
|
||||
[salt.utils.url.create('_renderers')],
|
||||
[salt.utils.url.create('_returners')],
|
||||
[salt.utils.url.create('_output')],
|
||||
[salt.utils.url.create('_utils')],
|
||||
[salt.utils.url.create(u'_modules')],
|
||||
[salt.utils.url.create(u'_states')],
|
||||
[salt.utils.url.create(u'_grains')],
|
||||
[salt.utils.url.create(u'_renderers')],
|
||||
[salt.utils.url.create(u'_returners')],
|
||||
[salt.utils.url.create(u'_output')],
|
||||
[salt.utils.url.create(u'_utils')],
|
||||
]
|
||||
with salt.utils.files.fopen(lowfn, 'w+') as fp_:
|
||||
with salt.utils.files.fopen(lowfn, u'w+') as fp_:
|
||||
fp_.write(json.dumps(chunks))
|
||||
if pillar:
|
||||
with salt.utils.files.fopen(pillarfn, 'w+') as fp_:
|
||||
with salt.utils.files.fopen(pillarfn, u'w+') as fp_:
|
||||
fp_.write(json.dumps(pillar))
|
||||
if roster_grains:
|
||||
with salt.utils.files.fopen(roster_grainsfn, 'w+') as fp_:
|
||||
with salt.utils.files.fopen(roster_grainsfn, u'w+') as fp_:
|
||||
fp_.write(json.dumps(roster_grains))
|
||||
|
||||
if id_ is None:
|
||||
id_ = ''
|
||||
id_ = u''
|
||||
try:
|
||||
cachedir = os.path.join('salt-ssh', id_).rstrip(os.sep)
|
||||
cachedir = os.path.join(u'salt-ssh', id_).rstrip(os.sep)
|
||||
except AttributeError:
|
||||
# Minion ID should always be a str, but don't let an int break this
|
||||
cachedir = os.path.join('salt-ssh', str(id_)).rstrip(os.sep)
|
||||
cachedir = os.path.join(u'salt-ssh', str(id_)).rstrip(os.sep)
|
||||
|
||||
for saltenv in file_refs:
|
||||
# Location where files in this saltenv will be cached
|
||||
cache_dest_root = os.path.join(cachedir, 'files', saltenv)
|
||||
cache_dest_root = os.path.join(cachedir, u'files', saltenv)
|
||||
file_refs[saltenv].extend(sync_refs)
|
||||
env_root = os.path.join(gendir, saltenv)
|
||||
if not os.path.isdir(env_root):
|
||||
@ -208,7 +209,7 @@ def prep_trans_tar(opts, file_client, chunks, file_refs, pillar=None, id_=None,
|
||||
try:
|
||||
path = file_client.cache_file(name, saltenv, cachedir=cachedir)
|
||||
except IOError:
|
||||
path = ''
|
||||
path = u''
|
||||
if path:
|
||||
tgt = os.path.join(env_root, short)
|
||||
tgt_dir = os.path.dirname(tgt)
|
||||
@ -219,10 +220,10 @@ def prep_trans_tar(opts, file_client, chunks, file_refs, pillar=None, id_=None,
|
||||
try:
|
||||
files = file_client.cache_dir(name, saltenv, cachedir=cachedir)
|
||||
except IOError:
|
||||
files = ''
|
||||
files = u''
|
||||
if files:
|
||||
for filename in files:
|
||||
fn = filename[len(file_client.get_cachedir(cache_dest)):].strip('/')
|
||||
fn = filename[len(file_client.get_cachedir(cache_dest)):].strip(u'/')
|
||||
tgt = os.path.join(
|
||||
env_root,
|
||||
short,
|
||||
@ -239,7 +240,7 @@ def prep_trans_tar(opts, file_client, chunks, file_refs, pillar=None, id_=None,
|
||||
except OSError:
|
||||
cwd = None
|
||||
os.chdir(gendir)
|
||||
with closing(tarfile.open(trans_tar, 'w:gz')) as tfp:
|
||||
with closing(tarfile.open(trans_tar, u'w:gz')) as tfp:
|
||||
for root, dirs, files in os.walk(gendir):
|
||||
for name in files:
|
||||
full = os.path.join(root, name)
|
||||
|
@ -17,7 +17,7 @@ import salt.utils
|
||||
import salt.client.ssh
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
|
||||
|
||||
class FunctionWrapper(object):
|
||||
@ -42,8 +42,8 @@ class FunctionWrapper(object):
|
||||
self.wfuncs = wfuncs if isinstance(wfuncs, dict) else {}
|
||||
self.opts = opts
|
||||
self.mods = mods if isinstance(mods, dict) else {}
|
||||
self.kwargs = {'id_': id_,
|
||||
'host': host}
|
||||
self.kwargs = {u'id_': id_,
|
||||
u'host': host}
|
||||
self.fsclient = fsclient
|
||||
self.kwargs.update(kwargs)
|
||||
self.aliases = aliases
|
||||
@ -67,14 +67,14 @@ class FunctionWrapper(object):
|
||||
'''
|
||||
Return the function call to simulate the salt local lookup system
|
||||
'''
|
||||
if '.' not in cmd and not self.cmd_prefix:
|
||||
if u'.' not in cmd and not self.cmd_prefix:
|
||||
# Form of salt.cmd.run in Jinja -- it's expecting a subdictionary
|
||||
# containing only 'cmd' module calls, in that case. Create a new
|
||||
# FunctionWrapper which contains the prefix 'cmd' (again, for the
|
||||
# salt.cmd.run example)
|
||||
kwargs = copy.deepcopy(self.kwargs)
|
||||
id_ = kwargs.pop('id_')
|
||||
host = kwargs.pop('host')
|
||||
id_ = kwargs.pop(u'id_')
|
||||
host = kwargs.pop(u'host')
|
||||
return FunctionWrapper(self.opts,
|
||||
id_,
|
||||
host,
|
||||
@ -90,7 +90,7 @@ class FunctionWrapper(object):
|
||||
# We're in an inner FunctionWrapper as created by the code block
|
||||
# above. Reconstruct the original cmd in the form 'cmd.run' and
|
||||
# then evaluate as normal
|
||||
cmd = '{0}.{1}'.format(self.cmd_prefix, cmd)
|
||||
cmd = u'{0}.{1}'.format(self.cmd_prefix, cmd)
|
||||
|
||||
if cmd in self.wfuncs:
|
||||
return self.wfuncs[cmd]
|
||||
@ -104,7 +104,7 @@ class FunctionWrapper(object):
|
||||
'''
|
||||
argv = [cmd]
|
||||
argv.extend([json.dumps(arg) for arg in args])
|
||||
argv.extend(['{0}={1}'.format(key, json.dumps(val)) for key, val in six.iteritems(kwargs)])
|
||||
argv.extend([u'{0}={1}'.format(key, json.dumps(val)) for key, val in six.iteritems(kwargs)])
|
||||
single = salt.client.ssh.Single(
|
||||
self.opts,
|
||||
argv,
|
||||
@ -115,21 +115,21 @@ class FunctionWrapper(object):
|
||||
**self.kwargs
|
||||
)
|
||||
stdout, stderr, retcode = single.cmd_block()
|
||||
if stderr.count('Permission Denied'):
|
||||
return {'_error': 'Permission Denied',
|
||||
'stdout': stdout,
|
||||
'stderr': stderr,
|
||||
'retcode': retcode}
|
||||
if stderr.count(u'Permission Denied'):
|
||||
return {u'_error': u'Permission Denied',
|
||||
u'stdout': stdout,
|
||||
u'stderr': stderr,
|
||||
u'retcode': retcode}
|
||||
try:
|
||||
ret = json.loads(stdout, object_hook=salt.utils.decode_dict)
|
||||
if len(ret) < 2 and 'local' in ret:
|
||||
ret = ret['local']
|
||||
ret = ret.get('return', {})
|
||||
if len(ret) < 2 and u'local' in ret:
|
||||
ret = ret[u'local']
|
||||
ret = ret.get(u'return', {})
|
||||
except ValueError:
|
||||
ret = {'_error': 'Failed to return clean data',
|
||||
'stderr': stderr,
|
||||
'stdout': stdout,
|
||||
'retcode': retcode}
|
||||
ret = {u'_error': u'Failed to return clean data',
|
||||
u'stderr': stderr,
|
||||
u'stdout': stdout,
|
||||
u'retcode': retcode}
|
||||
return ret
|
||||
return caller
|
||||
|
||||
@ -137,18 +137,18 @@ class FunctionWrapper(object):
|
||||
'''
|
||||
Set aliases for functions
|
||||
'''
|
||||
if '.' not in cmd and not self.cmd_prefix:
|
||||
if u'.' not in cmd and not self.cmd_prefix:
|
||||
# Form of salt.cmd.run in Jinja -- it's expecting a subdictionary
|
||||
# containing only 'cmd' module calls, in that case. We don't
|
||||
# support assigning directly to prefixes in this way
|
||||
raise KeyError('Cannot assign to module key {0} in the '
|
||||
'FunctionWrapper'.format(cmd))
|
||||
raise KeyError(u'Cannot assign to module key {0} in the '
|
||||
u'FunctionWrapper'.format(cmd))
|
||||
|
||||
if self.cmd_prefix:
|
||||
# We're in an inner FunctionWrapper as created by the first code
|
||||
# block in __getitem__. Reconstruct the original cmd in the form
|
||||
# 'cmd.run' and then evaluate as normal
|
||||
cmd = '{0}.{1}'.format(self.cmd_prefix, cmd)
|
||||
cmd = u'{0}.{1}'.format(self.cmd_prefix, cmd)
|
||||
|
||||
if cmd in self.wfuncs:
|
||||
self.wfuncs[cmd] = value
|
||||
|
@ -13,47 +13,47 @@ import salt.utils
|
||||
import salt.syspaths as syspaths
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
|
||||
# Set up the default values for all systems
|
||||
DEFAULTS = {'mongo.db': 'salt',
|
||||
'mongo.host': 'salt',
|
||||
'mongo.password': '',
|
||||
'mongo.port': 27017,
|
||||
'mongo.user': '',
|
||||
'redis.db': '0',
|
||||
'redis.host': 'salt',
|
||||
'redis.port': 6379,
|
||||
'test.foo': 'unconfigured',
|
||||
'ca.cert_base_path': '/etc/pki',
|
||||
'solr.cores': [],
|
||||
'solr.host': 'localhost',
|
||||
'solr.port': '8983',
|
||||
'solr.baseurl': '/solr',
|
||||
'solr.type': 'master',
|
||||
'solr.request_timeout': None,
|
||||
'solr.init_script': '/etc/rc.d/solr',
|
||||
'solr.dih.import_options': {'clean': False, 'optimize': True,
|
||||
'commit': True, 'verbose': False},
|
||||
'solr.backup_path': None,
|
||||
'solr.num_backups': 1,
|
||||
'poudriere.config': '/usr/local/etc/poudriere.conf',
|
||||
'poudriere.config_dir': '/usr/local/etc/poudriere.d',
|
||||
'ldap.server': 'localhost',
|
||||
'ldap.port': '389',
|
||||
'ldap.tls': False,
|
||||
'ldap.scope': 2,
|
||||
'ldap.attrs': None,
|
||||
'ldap.binddn': '',
|
||||
'ldap.bindpw': '',
|
||||
'hosts.file': '/etc/hosts',
|
||||
'aliases.file': '/etc/aliases',
|
||||
'virt.images': os.path.join(syspaths.SRV_ROOT_DIR, 'salt-images'),
|
||||
'virt.tunnel': False,
|
||||
DEFAULTS = {u'mongo.db': u'salt',
|
||||
u'mongo.host': u'salt',
|
||||
u'mongo.password': u'',
|
||||
u'mongo.port': 27017,
|
||||
u'mongo.user': u'',
|
||||
u'redis.db': u'0',
|
||||
u'redis.host': u'salt',
|
||||
u'redis.port': 6379,
|
||||
u'test.foo': u'unconfigured',
|
||||
u'ca.cert_base_path': u'/etc/pki',
|
||||
u'solr.cores': [],
|
||||
u'solr.host': u'localhost',
|
||||
u'solr.port': u'8983',
|
||||
u'solr.baseurl': u'/solr',
|
||||
u'solr.type': u'master',
|
||||
u'solr.request_timeout': None,
|
||||
u'solr.init_script': u'/etc/rc.d/solr',
|
||||
u'solr.dih.import_options': {u'clean': False, u'optimize': True,
|
||||
u'commit': True, u'verbose': False},
|
||||
u'solr.backup_path': None,
|
||||
u'solr.num_backups': 1,
|
||||
u'poudriere.config': u'/usr/local/etc/poudriere.conf',
|
||||
u'poudriere.config_dir': u'/usr/local/etc/poudriere.d',
|
||||
u'ldap.server': u'localhost',
|
||||
u'ldap.port': u'389',
|
||||
u'ldap.tls': False,
|
||||
u'ldap.scope': 2,
|
||||
u'ldap.attrs': None,
|
||||
u'ldap.binddn': u'',
|
||||
u'ldap.bindpw': u'',
|
||||
u'hosts.file': u'/etc/hosts',
|
||||
u'aliases.file': u'/etc/aliases',
|
||||
u'virt.images': os.path.join(syspaths.SRV_ROOT_DIR, u'salt-images'),
|
||||
u'virt.tunnel': False,
|
||||
}
|
||||
|
||||
|
||||
def backup_mode(backup=''):
|
||||
def backup_mode(backup=u''):
|
||||
'''
|
||||
Return the backup mode
|
||||
|
||||
@ -65,7 +65,7 @@ def backup_mode(backup=''):
|
||||
'''
|
||||
if backup:
|
||||
return backup
|
||||
return option('backup_mode')
|
||||
return option(u'backup_mode')
|
||||
|
||||
|
||||
def manage_mode(mode):
|
||||
@ -96,14 +96,14 @@ def valid_fileproto(uri):
|
||||
salt '*' config.valid_fileproto salt://path/to/file
|
||||
'''
|
||||
try:
|
||||
return bool(re.match('^(?:salt|https?|ftp)://', uri))
|
||||
return bool(re.match(u'^(?:salt|https?|ftp)://', uri))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def option(
|
||||
value,
|
||||
default='',
|
||||
default=u'',
|
||||
omit_opts=False,
|
||||
omit_master=False,
|
||||
omit_pillar=False):
|
||||
@ -120,8 +120,8 @@ def option(
|
||||
if value in __opts__:
|
||||
return __opts__[value]
|
||||
if not omit_master:
|
||||
if value in __pillar__.get('master', {}):
|
||||
return __pillar__['master'][value]
|
||||
if value in __pillar__.get(u'master', {}):
|
||||
return __pillar__[u'master'][value]
|
||||
if not omit_pillar:
|
||||
if value in __pillar__:
|
||||
return __pillar__[value]
|
||||
@ -131,7 +131,7 @@ def option(
|
||||
|
||||
|
||||
def merge(value,
|
||||
default='',
|
||||
default=u'',
|
||||
omit_opts=False,
|
||||
omit_master=False,
|
||||
omit_pillar=False):
|
||||
@ -151,14 +151,14 @@ def merge(value,
|
||||
if not omit_opts:
|
||||
if value in __opts__:
|
||||
ret = __opts__[value]
|
||||
if isinstance(ret, str):
|
||||
if isinstance(ret, six.string_types):
|
||||
return ret
|
||||
if not omit_master:
|
||||
if value in __pillar__.get('master', {}):
|
||||
tmp = __pillar__['master'][value]
|
||||
if value in __pillar__.get(u'master', {}):
|
||||
tmp = __pillar__[u'master'][value]
|
||||
if ret is None:
|
||||
ret = tmp
|
||||
if isinstance(ret, str):
|
||||
if isinstance(ret, six.string_types):
|
||||
return ret
|
||||
elif isinstance(ret, dict) and isinstance(tmp, dict):
|
||||
tmp.update(ret)
|
||||
@ -171,7 +171,7 @@ def merge(value,
|
||||
tmp = __pillar__[value]
|
||||
if ret is None:
|
||||
ret = tmp
|
||||
if isinstance(ret, str):
|
||||
if isinstance(ret, six.string_types):
|
||||
return ret
|
||||
elif isinstance(ret, dict) and isinstance(tmp, dict):
|
||||
tmp.update(ret)
|
||||
@ -184,7 +184,7 @@ def merge(value,
|
||||
return ret or default
|
||||
|
||||
|
||||
def get(key, default=''):
|
||||
def get(key, default=u''):
|
||||
'''
|
||||
.. versionadded: 0.14.0
|
||||
|
||||
@ -215,17 +215,17 @@ def get(key, default=''):
|
||||
|
||||
salt '*' config.get pkg:apache
|
||||
'''
|
||||
ret = salt.utils.traverse_dict_and_list(__opts__, key, '_|-')
|
||||
if ret != '_|-':
|
||||
ret = salt.utils.traverse_dict_and_list(__opts__, key, u'_|-')
|
||||
if ret != u'_|-':
|
||||
return ret
|
||||
ret = salt.utils.traverse_dict_and_list(__grains__, key, '_|-')
|
||||
if ret != '_|-':
|
||||
ret = salt.utils.traverse_dict_and_list(__grains__, key, u'_|-')
|
||||
if ret != u'_|-':
|
||||
return ret
|
||||
ret = salt.utils.traverse_dict_and_list(__pillar__, key, '_|-')
|
||||
if ret != '_|-':
|
||||
ret = salt.utils.traverse_dict_and_list(__pillar__, key, u'_|-')
|
||||
if ret != u'_|-':
|
||||
return ret
|
||||
ret = salt.utils.traverse_dict_and_list(__pillar__.get('master', {}), key, '_|-')
|
||||
if ret != '_|-':
|
||||
ret = salt.utils.traverse_dict_and_list(__pillar__.get(u'master', {}), key, u'_|-')
|
||||
if ret != u'_|-':
|
||||
return ret
|
||||
return default
|
||||
|
||||
@ -242,10 +242,10 @@ def dot_vals(value):
|
||||
salt '*' config.dot_vals host
|
||||
'''
|
||||
ret = {}
|
||||
for key, val in six.iteritems(__pillar__.get('master', {})):
|
||||
if key.startswith('{0}.'.format(value)):
|
||||
for key, val in six.iteritems(__pillar__.get(u'master', {})):
|
||||
if key.startswith(u'{0}.'.format(value)):
|
||||
ret[key] = val
|
||||
for key, val in six.iteritems(__opts__):
|
||||
if key.startswith('{0}.'.format(value)):
|
||||
if key.startswith(u'{0}.'.format(value)):
|
||||
ret[key] = val
|
||||
return ret
|
||||
|
@ -18,7 +18,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
def get_file(path,
|
||||
dest,
|
||||
saltenv='base',
|
||||
saltenv=u'base',
|
||||
makedirs=False,
|
||||
template=None,
|
||||
gzip=None):
|
||||
@ -31,83 +31,83 @@ def get_file(path,
|
||||
cp.get_file. The argument is only accepted for interface compatibility.
|
||||
'''
|
||||
if gzip is not None:
|
||||
log.warning('The gzip argument to cp.get_file in salt-ssh is '
|
||||
'unsupported')
|
||||
log.warning(u'The gzip argument to cp.get_file in salt-ssh is '
|
||||
u'unsupported')
|
||||
|
||||
if template is not None:
|
||||
(path, dest) = _render_filenames(path, dest, saltenv, template)
|
||||
|
||||
src = __context__['fileclient'].cache_file(
|
||||
src = __context__[u'fileclient'].cache_file(
|
||||
path,
|
||||
saltenv,
|
||||
cachedir=os.path.join('salt-ssh', __salt__.kwargs['id_']))
|
||||
cachedir=os.path.join(u'salt-ssh', __salt__.kwargs[u'id_']))
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
'',
|
||||
u'',
|
||||
**__salt__.kwargs)
|
||||
ret = single.shell.send(src, dest, makedirs)
|
||||
return not ret[2]
|
||||
|
||||
|
||||
def get_dir(path, dest, saltenv='base'):
|
||||
def get_dir(path, dest, saltenv=u'base'):
|
||||
'''
|
||||
Transfer a directory down
|
||||
'''
|
||||
src = __context__['fileclient'].cache_dir(
|
||||
src = __context__[u'fileclient'].cache_dir(
|
||||
path,
|
||||
saltenv,
|
||||
cachedir=os.path.join('salt-ssh', __salt__.kwargs['id_']))
|
||||
src = ' '.join(src)
|
||||
cachedir=os.path.join(u'salt-ssh', __salt__.kwargs[u'id_']))
|
||||
src = u' '.join(src)
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
'',
|
||||
u'',
|
||||
**__salt__.kwargs)
|
||||
ret = single.shell.send(src, dest)
|
||||
return not ret[2]
|
||||
|
||||
|
||||
def get_url(path, dest, saltenv='base'):
|
||||
def get_url(path, dest, saltenv=u'base'):
|
||||
'''
|
||||
retrieve a URL
|
||||
'''
|
||||
src = __context__['fileclient'].cache_file(
|
||||
src = __context__[u'fileclient'].cache_file(
|
||||
path,
|
||||
saltenv,
|
||||
cachedir=os.path.join('salt-ssh', __salt__.kwargs['id_']))
|
||||
cachedir=os.path.join(u'salt-ssh', __salt__.kwargs[u'id_']))
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
'',
|
||||
u'',
|
||||
**__salt__.kwargs)
|
||||
ret = single.shell.send(src, dest)
|
||||
return not ret[2]
|
||||
|
||||
|
||||
def list_states(saltenv='base'):
|
||||
def list_states(saltenv=u'base'):
|
||||
'''
|
||||
List all the available state modules in an environment
|
||||
'''
|
||||
return __context__['fileclient'].list_states(saltenv)
|
||||
return __context__[u'fileclient'].list_states(saltenv)
|
||||
|
||||
|
||||
def list_master(saltenv='base', prefix=''):
|
||||
def list_master(saltenv=u'base', prefix=u''):
|
||||
'''
|
||||
List all of the files stored on the master
|
||||
'''
|
||||
return __context__['fileclient'].file_list(saltenv, prefix)
|
||||
return __context__[u'fileclient'].file_list(saltenv, prefix)
|
||||
|
||||
|
||||
def list_master_dirs(saltenv='base', prefix=''):
|
||||
def list_master_dirs(saltenv=u'base', prefix=u''):
|
||||
'''
|
||||
List all of the directories stored on the master
|
||||
'''
|
||||
return __context__['fileclient'].dir_list(saltenv, prefix)
|
||||
return __context__[u'fileclient'].dir_list(saltenv, prefix)
|
||||
|
||||
|
||||
def list_master_symlinks(saltenv='base', prefix=''):
|
||||
def list_master_symlinks(saltenv=u'base', prefix=u''):
|
||||
'''
|
||||
List all of the symlinks stored on the master
|
||||
'''
|
||||
return __context__['fileclient'].symlink_list(saltenv, prefix)
|
||||
return __context__[u'fileclient'].symlink_list(saltenv, prefix)
|
||||
|
||||
|
||||
def _render_filenames(path, dest, saltenv, template):
|
||||
@ -122,16 +122,16 @@ def _render_filenames(path, dest, saltenv, template):
|
||||
# render the path as a template using path_template_engine as the engine
|
||||
if template not in salt.utils.templates.TEMPLATE_REGISTRY:
|
||||
raise CommandExecutionError(
|
||||
'Attempted to render file paths with unavailable engine '
|
||||
'{0}'.format(template)
|
||||
u'Attempted to render file paths with unavailable engine '
|
||||
u'{0}'.format(template)
|
||||
)
|
||||
|
||||
kwargs = {}
|
||||
kwargs['salt'] = __salt__
|
||||
kwargs['pillar'] = __pillar__
|
||||
kwargs['grains'] = __grains__
|
||||
kwargs['opts'] = __opts__
|
||||
kwargs['saltenv'] = saltenv
|
||||
kwargs[u'salt'] = __salt__
|
||||
kwargs[u'pillar'] = __pillar__
|
||||
kwargs[u'grains'] = __grains__
|
||||
kwargs[u'opts'] = __opts__
|
||||
kwargs[u'saltenv'] = saltenv
|
||||
|
||||
def _render(contents):
|
||||
'''
|
||||
@ -140,7 +140,7 @@ def _render_filenames(path, dest, saltenv, template):
|
||||
'''
|
||||
# write out path to temp file
|
||||
tmp_path_fn = salt.utils.files.mkstemp()
|
||||
with salt.utils.files.fopen(tmp_path_fn, 'w+') as fp_:
|
||||
with salt.utils.files.fopen(tmp_path_fn, u'w+') as fp_:
|
||||
fp_.write(contents)
|
||||
data = salt.utils.templates.TEMPLATE_REGISTRY[template](
|
||||
tmp_path_fn,
|
||||
@ -148,15 +148,15 @@ def _render_filenames(path, dest, saltenv, template):
|
||||
**kwargs
|
||||
)
|
||||
salt.utils.files.safe_rm(tmp_path_fn)
|
||||
if not data['result']:
|
||||
if not data[u'result']:
|
||||
# Failed to render the template
|
||||
raise CommandExecutionError(
|
||||
'Failed to render file path with error: {0}'.format(
|
||||
data['data']
|
||||
u'Failed to render file path with error: {0}'.format(
|
||||
data[u'data']
|
||||
)
|
||||
)
|
||||
else:
|
||||
return data['data']
|
||||
return data[u'data']
|
||||
|
||||
path = _render(path)
|
||||
dest = _render(dest)
|
||||
|
@ -17,38 +17,40 @@ from salt.defaults import DEFAULT_TARGET_DELIM
|
||||
from salt.exceptions import SaltException
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
|
||||
# Seed the grains dict so cython will build
|
||||
__grains__ = {}
|
||||
|
||||
|
||||
def _serial_sanitizer(instr):
|
||||
'''Replaces the last 1/4 of a string with X's'''
|
||||
'''
|
||||
Replaces the last 1/4 of a string with X's
|
||||
'''
|
||||
length = len(instr)
|
||||
index = int(math.floor(length * .75))
|
||||
return '{0}{1}'.format(instr[:index], 'X' * (length - index))
|
||||
return u'{0}{1}'.format(instr[:index], u'X' * (length - index))
|
||||
|
||||
|
||||
_FQDN_SANITIZER = lambda x: 'MINION.DOMAINNAME'
|
||||
_HOSTNAME_SANITIZER = lambda x: 'MINION'
|
||||
_DOMAINNAME_SANITIZER = lambda x: 'DOMAINNAME'
|
||||
_FQDN_SANITIZER = lambda x: u'MINION.DOMAINNAME'
|
||||
_HOSTNAME_SANITIZER = lambda x: u'MINION'
|
||||
_DOMAINNAME_SANITIZER = lambda x: u'DOMAINNAME'
|
||||
|
||||
|
||||
# A dictionary of grain -> function mappings for sanitizing grain output. This
|
||||
# is used when the 'sanitize' flag is given.
|
||||
_SANITIZERS = {
|
||||
'serialnumber': _serial_sanitizer,
|
||||
'domain': _DOMAINNAME_SANITIZER,
|
||||
'fqdn': _FQDN_SANITIZER,
|
||||
'id': _FQDN_SANITIZER,
|
||||
'host': _HOSTNAME_SANITIZER,
|
||||
'localhost': _HOSTNAME_SANITIZER,
|
||||
'nodename': _HOSTNAME_SANITIZER,
|
||||
u'serialnumber': _serial_sanitizer,
|
||||
u'domain': _DOMAINNAME_SANITIZER,
|
||||
u'fqdn': _FQDN_SANITIZER,
|
||||
u'id': _FQDN_SANITIZER,
|
||||
u'host': _HOSTNAME_SANITIZER,
|
||||
u'localhost': _HOSTNAME_SANITIZER,
|
||||
u'nodename': _HOSTNAME_SANITIZER,
|
||||
}
|
||||
|
||||
|
||||
def get(key, default='', delimiter=DEFAULT_TARGET_DELIM, ordered=True):
|
||||
def get(key, default=u'', delimiter=DEFAULT_TARGET_DELIM, ordered=True):
|
||||
'''
|
||||
Attempt to retrieve the named value from grains, if the named value is not
|
||||
available return the passed default. The default return is an empty string.
|
||||
@ -149,7 +151,7 @@ def item(*args, **kwargs):
|
||||
ret[arg] = __grains__[arg]
|
||||
except KeyError:
|
||||
pass
|
||||
if salt.utils.is_true(kwargs.get('sanitize')):
|
||||
if salt.utils.is_true(kwargs.get(u'sanitize')):
|
||||
for arg, func in six.iteritems(_SANITIZERS):
|
||||
if arg in ret:
|
||||
ret[arg] = func(ret[arg])
|
||||
@ -170,9 +172,9 @@ def ls(): # pylint: disable=C0103
|
||||
|
||||
|
||||
def filter_by(lookup_dict,
|
||||
grain='os_family',
|
||||
grain=u'os_family',
|
||||
merge=None,
|
||||
default='default',
|
||||
default=u'default',
|
||||
base=None):
|
||||
'''
|
||||
.. versionadded:: 0.17.0
|
||||
@ -266,12 +268,12 @@ def filter_by(lookup_dict,
|
||||
|
||||
elif isinstance(base_values, collections.Mapping):
|
||||
if not isinstance(ret, collections.Mapping):
|
||||
raise SaltException('filter_by default and look-up values must both be dictionaries.')
|
||||
raise SaltException(u'filter_by default and look-up values must both be dictionaries.')
|
||||
ret = salt.utils.dictupdate.update(copy.deepcopy(base_values), ret)
|
||||
|
||||
if merge:
|
||||
if not isinstance(merge, collections.Mapping):
|
||||
raise SaltException('filter_by merge argument must be a dictionary.')
|
||||
raise SaltException(u'filter_by merge argument must be a dictionary.')
|
||||
else:
|
||||
if ret is None:
|
||||
ret = merge
|
||||
|
@ -14,7 +14,7 @@ import copy
|
||||
import salt.client.ssh
|
||||
|
||||
|
||||
def get(tgt, fun, tgt_type='glob', roster='flat'):
|
||||
def get(tgt, fun, tgt_type=u'glob', roster=u'flat'):
|
||||
'''
|
||||
Get data from the mine based on the target, function and tgt_type
|
||||
|
||||
@ -36,15 +36,15 @@ def get(tgt, fun, tgt_type='glob', roster='flat'):
|
||||
salt-ssh '*' mine.get '192.168.5.0' network.ipaddrs roster=scan
|
||||
'''
|
||||
# Set up opts for the SSH object
|
||||
opts = copy.deepcopy(__context__['master_opts'])
|
||||
opts = copy.deepcopy(__context__[u'master_opts'])
|
||||
minopts = copy.deepcopy(__opts__)
|
||||
opts.update(minopts)
|
||||
if roster:
|
||||
opts['roster'] = roster
|
||||
opts['argv'] = [fun]
|
||||
opts['selected_target_option'] = tgt_type
|
||||
opts['tgt'] = tgt
|
||||
opts['arg'] = []
|
||||
opts[u'roster'] = roster
|
||||
opts[u'argv'] = [fun]
|
||||
opts[u'selected_target_option'] = tgt_type
|
||||
opts[u'tgt'] = tgt
|
||||
opts[u'arg'] = []
|
||||
|
||||
# Create the SSH object to handle the actual call
|
||||
ssh = salt.client.ssh.SSH(opts)
|
||||
@ -56,8 +56,8 @@ def get(tgt, fun, tgt_type='glob', roster='flat'):
|
||||
|
||||
cret = {}
|
||||
for host in rets:
|
||||
if 'return' in rets[host]:
|
||||
cret[host] = rets[host]['return']
|
||||
if u'return' in rets[host]:
|
||||
cret[host] = rets[host][u'return']
|
||||
else:
|
||||
cret[host] = rets[host]
|
||||
return cret
|
||||
|
@ -13,7 +13,7 @@ import salt.utils
|
||||
from salt.defaults import DEFAULT_TARGET_DELIM
|
||||
|
||||
|
||||
def get(key, default='', merge=False, delimiter=DEFAULT_TARGET_DELIM):
|
||||
def get(key, default=u'', merge=False, delimiter=DEFAULT_TARGET_DELIM):
|
||||
'''
|
||||
.. versionadded:: 0.14
|
||||
|
||||
@ -130,10 +130,10 @@ def keys(key, delimiter=DEFAULT_TARGET_DELIM):
|
||||
__pillar__, key, KeyError, delimiter)
|
||||
|
||||
if ret is KeyError:
|
||||
raise KeyError("Pillar key not found: {0}".format(key))
|
||||
raise KeyError(u"Pillar key not found: {0}".format(key))
|
||||
|
||||
if not isinstance(ret, dict):
|
||||
raise ValueError("Pillar value in key {0} is not a dict".format(key))
|
||||
raise ValueError(u"Pillar value in key {0} is not a dict".format(key))
|
||||
|
||||
return ret.keys()
|
||||
|
||||
|
@ -17,6 +17,8 @@ import logging
|
||||
# Import salt libs
|
||||
import salt.client.ssh
|
||||
import salt.runner
|
||||
import salt.utils.args
|
||||
import salt.utils.versions
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -24,10 +26,10 @@ log = logging.getLogger(__name__)
|
||||
def _publish(tgt,
|
||||
fun,
|
||||
arg=None,
|
||||
tgt_type='glob',
|
||||
returner='',
|
||||
tgt_type=u'glob',
|
||||
returner=u'',
|
||||
timeout=None,
|
||||
form='clean',
|
||||
form=u'clean',
|
||||
roster=None):
|
||||
'''
|
||||
Publish a command "from the minion out to other minions". In reality, the
|
||||
@ -53,13 +55,13 @@ def _publish(tgt,
|
||||
|
||||
salt-ssh system.example.com publish.publish '*' cmd.run 'ls -la /tmp'
|
||||
'''
|
||||
if fun.startswith('publish.'):
|
||||
log.info('Cannot publish publish calls. Returning {}')
|
||||
if fun.startswith(u'publish.'):
|
||||
log.info(u'Cannot publish publish calls. Returning {}')
|
||||
return {}
|
||||
|
||||
# TODO: implement returners? Do they make sense for salt-ssh calls?
|
||||
if returner:
|
||||
log.warning('Returners currently not supported in salt-ssh publish')
|
||||
log.warning(u'Returners currently not supported in salt-ssh publish')
|
||||
|
||||
# Make sure args have been processed
|
||||
if arg is None:
|
||||
@ -72,17 +74,17 @@ def _publish(tgt,
|
||||
arg = []
|
||||
|
||||
# Set up opts for the SSH object
|
||||
opts = copy.deepcopy(__context__['master_opts'])
|
||||
opts = copy.deepcopy(__context__[u'master_opts'])
|
||||
minopts = copy.deepcopy(__opts__)
|
||||
opts.update(minopts)
|
||||
if roster:
|
||||
opts['roster'] = roster
|
||||
opts[u'roster'] = roster
|
||||
if timeout:
|
||||
opts['timeout'] = timeout
|
||||
opts['argv'] = [fun] + arg
|
||||
opts['selected_target_option'] = tgt_type
|
||||
opts['tgt'] = tgt
|
||||
opts['arg'] = arg
|
||||
opts[u'timeout'] = timeout
|
||||
opts[u'argv'] = [fun] + arg
|
||||
opts[u'selected_target_option'] = tgt_type
|
||||
opts[u'tgt'] = tgt
|
||||
opts[u'arg'] = arg
|
||||
|
||||
# Create the SSH object to handle the actual call
|
||||
ssh = salt.client.ssh.SSH(opts)
|
||||
@ -92,11 +94,11 @@ def _publish(tgt,
|
||||
for ret in ssh.run_iter():
|
||||
rets.update(ret)
|
||||
|
||||
if form == 'clean':
|
||||
if form == u'clean':
|
||||
cret = {}
|
||||
for host in rets:
|
||||
if 'return' in rets[host]:
|
||||
cret[host] = rets[host]['return']
|
||||
if u'return' in rets[host]:
|
||||
cret[host] = rets[host][u'return']
|
||||
else:
|
||||
cret[host] = rets[host]
|
||||
return cret
|
||||
@ -107,8 +109,8 @@ def _publish(tgt,
|
||||
def publish(tgt,
|
||||
fun,
|
||||
arg=None,
|
||||
tgt_type='glob',
|
||||
returner='',
|
||||
tgt_type=u'glob',
|
||||
returner=u'',
|
||||
timeout=5,
|
||||
roster=None,
|
||||
expr_form=None):
|
||||
@ -173,11 +175,11 @@ def publish(tgt,
|
||||
# remember to remove the expr_form argument from this function when
|
||||
# performing the cleanup on this deprecation.
|
||||
if expr_form is not None:
|
||||
salt.utils.warn_until(
|
||||
'Fluorine',
|
||||
'the target type should be passed using the \'tgt_type\' '
|
||||
'argument instead of \'expr_form\'. Support for using '
|
||||
'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
salt.utils.versions.warn_until(
|
||||
u'Fluorine',
|
||||
u'the target type should be passed using the \'tgt_type\' '
|
||||
u'argument instead of \'expr_form\'. Support for using '
|
||||
u'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
)
|
||||
tgt_type = expr_form
|
||||
|
||||
@ -187,15 +189,15 @@ def publish(tgt,
|
||||
tgt_type=tgt_type,
|
||||
returner=returner,
|
||||
timeout=timeout,
|
||||
form='clean',
|
||||
form=u'clean',
|
||||
roster=roster)
|
||||
|
||||
|
||||
def full_data(tgt,
|
||||
fun,
|
||||
arg=None,
|
||||
tgt_type='glob',
|
||||
returner='',
|
||||
tgt_type=u'glob',
|
||||
returner=u'',
|
||||
timeout=5,
|
||||
roster=None,
|
||||
expr_form=None):
|
||||
@ -223,11 +225,11 @@ def full_data(tgt,
|
||||
# remember to remove the expr_form argument from this function when
|
||||
# performing the cleanup on this deprecation.
|
||||
if expr_form is not None:
|
||||
salt.utils.warn_until(
|
||||
'Fluorine',
|
||||
'the target type should be passed using the \'tgt_type\' '
|
||||
'argument instead of \'expr_form\'. Support for using '
|
||||
'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
salt.utils.versions.warn_until(
|
||||
u'Fluorine',
|
||||
u'the target type should be passed using the \'tgt_type\' '
|
||||
u'argument instead of \'expr_form\'. Support for using '
|
||||
u'\'expr_form\' will be removed in Salt Fluorine.'
|
||||
)
|
||||
tgt_type = expr_form
|
||||
|
||||
@ -237,7 +239,7 @@ def full_data(tgt,
|
||||
tgt_type=tgt_type,
|
||||
returner=returner,
|
||||
timeout=timeout,
|
||||
form='full',
|
||||
form=u'full',
|
||||
roster=roster)
|
||||
|
||||
|
||||
@ -260,5 +262,5 @@ def runner(fun, arg=None, timeout=5):
|
||||
arg = []
|
||||
|
||||
# Create and run the runner
|
||||
runner = salt.runner.RunnerClient(__opts__['__master_opts__'])
|
||||
runner = salt.runner.RunnerClient(__opts__[u'__master_opts__'])
|
||||
return runner.cmd(fun, arg)
|
||||
|
@ -20,10 +20,12 @@ import salt.state
|
||||
import salt.loader
|
||||
import salt.minion
|
||||
import salt.log
|
||||
from salt.ext.six import string_types
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
__func_alias__ = {
|
||||
'apply_': 'apply'
|
||||
u'apply_': u'apply'
|
||||
}
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -34,37 +36,37 @@ def _merge_extra_filerefs(*args):
|
||||
'''
|
||||
ret = []
|
||||
for arg in args:
|
||||
if isinstance(arg, string_types):
|
||||
if isinstance(arg, six.string_types):
|
||||
if arg:
|
||||
ret.extend(arg.split(','))
|
||||
ret.extend(arg.split(u','))
|
||||
elif isinstance(arg, list):
|
||||
if arg:
|
||||
ret.extend(arg)
|
||||
return ','.join(ret)
|
||||
return u','.join(ret)
|
||||
|
||||
|
||||
def sls(mods, saltenv='base', test=None, exclude=None, **kwargs):
|
||||
def sls(mods, saltenv=u'base', test=None, exclude=None, **kwargs):
|
||||
'''
|
||||
Create the seed file for a state.sls run
|
||||
'''
|
||||
st_kwargs = __salt__.kwargs
|
||||
__opts__['grains'] = __grains__
|
||||
__pillar__.update(kwargs.get('pillar', {}))
|
||||
__opts__[u'grains'] = __grains__
|
||||
__pillar__.update(kwargs.get(u'pillar', {}))
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
if isinstance(mods, str):
|
||||
mods = mods.split(',')
|
||||
__context__[u'fileclient'])
|
||||
if isinstance(mods, six.string_types):
|
||||
mods = mods.split(u',')
|
||||
high_data, errors = st_.render_highstate({saltenv: mods})
|
||||
if exclude:
|
||||
if isinstance(exclude, str):
|
||||
exclude = exclude.split(',')
|
||||
if '__exclude__' in high_data:
|
||||
high_data['__exclude__'].extend(exclude)
|
||||
if isinstance(exclude, six.string_types):
|
||||
exclude = exclude.split(u',')
|
||||
if u'__exclude__' in high_data:
|
||||
high_data[u'__exclude__'].extend(exclude)
|
||||
else:
|
||||
high_data['__exclude__'] = exclude
|
||||
high_data[u'__exclude__'] = exclude
|
||||
high_data, ext_errors = st_.state.reconcile_extend(high_data)
|
||||
errors += ext_errors
|
||||
errors += st_.state.verify_high(high_data)
|
||||
@ -81,38 +83,38 @@ def sls(mods, saltenv='base', test=None, exclude=None, **kwargs):
|
||||
file_refs = salt.client.ssh.state.lowstate_file_refs(
|
||||
chunks,
|
||||
_merge_extra_filerefs(
|
||||
kwargs.get('extra_filerefs', ''),
|
||||
__opts__.get('extra_filerefs', '')
|
||||
kwargs.get(u'extra_filerefs', u''),
|
||||
__opts__.get(u'extra_filerefs', u'')
|
||||
)
|
||||
)
|
||||
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get('roster', 'flat'))
|
||||
roster_grains = roster.opts['grains']
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get(u'roster', u'flat'))
|
||||
roster_grains = roster.opts[u'grains']
|
||||
|
||||
# Create the tar containing the state pkg and relevant files.
|
||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||
__opts__,
|
||||
__context__['fileclient'],
|
||||
__context__[u'fileclient'],
|
||||
chunks,
|
||||
file_refs,
|
||||
__pillar__,
|
||||
st_kwargs['id_'],
|
||||
st_kwargs[u'id_'],
|
||||
roster_grains)
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__['hash_type'])
|
||||
cmd = 'state.pkg {0}/salt_state.tgz test={1} pkg_sum={2} hash_type={3}'.format(
|
||||
__opts__['thin_dir'],
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__[u'hash_type'])
|
||||
cmd = u'state.pkg {0}/salt_state.tgz test={1} pkg_sum={2} hash_type={3}'.format(
|
||||
__opts__[u'thin_dir'],
|
||||
test,
|
||||
trans_tar_sum,
|
||||
__opts__['hash_type'])
|
||||
__opts__[u'hash_type'])
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
cmd,
|
||||
fsclient=__context__['fileclient'],
|
||||
fsclient=__context__[u'fileclient'],
|
||||
minion_opts=__salt__.minion_opts,
|
||||
**st_kwargs)
|
||||
single.shell.send(
|
||||
trans_tar,
|
||||
'{0}/salt_state.tgz'.format(__opts__['thin_dir']))
|
||||
u'{0}/salt_state.tgz'.format(__opts__[u'thin_dir']))
|
||||
stdout, stderr, _ = single.cmd_block()
|
||||
|
||||
# Clean up our tar
|
||||
@ -125,7 +127,7 @@ def sls(mods, saltenv='base', test=None, exclude=None, **kwargs):
|
||||
try:
|
||||
return json.loads(stdout, object_hook=salt.utils.decode_dict)
|
||||
except Exception as e:
|
||||
log.error("JSON Render failed for: {0}\n{1}".format(stdout, stderr))
|
||||
log.error(u"JSON Render failed for: %s\n%s", stdout, stderr)
|
||||
log.error(str(e))
|
||||
|
||||
# If for some reason the json load fails, return the stdout
|
||||
@ -144,51 +146,51 @@ def low(data, **kwargs):
|
||||
salt '*' state.low '{"state": "pkg", "fun": "installed", "name": "vi"}'
|
||||
'''
|
||||
st_kwargs = __salt__.kwargs
|
||||
__opts__['grains'] = __grains__
|
||||
__opts__[u'grains'] = __grains__
|
||||
chunks = [data]
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
__context__[u'fileclient'])
|
||||
for chunk in chunks:
|
||||
chunk['__id__'] = chunk['name'] if not chunk.get('__id__') else chunk['__id__']
|
||||
chunk[u'__id__'] = chunk[u'name'] if not chunk.get(u'__id__') else chunk[u'__id__']
|
||||
err = st_.state.verify_data(data)
|
||||
if err:
|
||||
return err
|
||||
file_refs = salt.client.ssh.state.lowstate_file_refs(
|
||||
chunks,
|
||||
_merge_extra_filerefs(
|
||||
kwargs.get('extra_filerefs', ''),
|
||||
__opts__.get('extra_filerefs', '')
|
||||
kwargs.get(u'extra_filerefs', u''),
|
||||
__opts__.get(u'extra_filerefs', u'')
|
||||
)
|
||||
)
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get('roster', 'flat'))
|
||||
roster_grains = roster.opts['grains']
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get(u'roster', u'flat'))
|
||||
roster_grains = roster.opts[u'grains']
|
||||
|
||||
# Create the tar containing the state pkg and relevant files.
|
||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||
__opts__,
|
||||
__context__['fileclient'],
|
||||
__context__[u'fileclient'],
|
||||
chunks,
|
||||
file_refs,
|
||||
__pillar__,
|
||||
st_kwargs['id_'],
|
||||
st_kwargs[u'id_'],
|
||||
roster_grains)
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__['hash_type'])
|
||||
cmd = 'state.pkg {0}/salt_state.tgz pkg_sum={1} hash_type={2}'.format(
|
||||
__opts__['thin_dir'],
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__[u'hash_type'])
|
||||
cmd = u'state.pkg {0}/salt_state.tgz pkg_sum={1} hash_type={2}'.format(
|
||||
__opts__[u'thin_dir'],
|
||||
trans_tar_sum,
|
||||
__opts__['hash_type'])
|
||||
__opts__[u'hash_type'])
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
cmd,
|
||||
fsclient=__context__['fileclient'],
|
||||
fsclient=__context__[u'fileclient'],
|
||||
minion_opts=__salt__.minion_opts,
|
||||
**st_kwargs)
|
||||
single.shell.send(
|
||||
trans_tar,
|
||||
'{0}/salt_state.tgz'.format(__opts__['thin_dir']))
|
||||
u'{0}/salt_state.tgz'.format(__opts__[u'thin_dir']))
|
||||
stdout, stderr, _ = single.cmd_block()
|
||||
|
||||
# Clean up our tar
|
||||
@ -201,7 +203,7 @@ def low(data, **kwargs):
|
||||
try:
|
||||
return json.loads(stdout, object_hook=salt.utils.decode_dict)
|
||||
except Exception as e:
|
||||
log.error("JSON Render failed for: {0}\n{1}".format(stdout, stderr))
|
||||
log.error(u"JSON Render failed for: %s\n%s", stdout, stderr)
|
||||
log.error(str(e))
|
||||
|
||||
# If for some reason the json load fails, return the stdout
|
||||
@ -219,49 +221,49 @@ def high(data, **kwargs):
|
||||
|
||||
salt '*' state.high '{"vim": {"pkg": ["installed"]}}'
|
||||
'''
|
||||
__pillar__.update(kwargs.get('pillar', {}))
|
||||
__pillar__.update(kwargs.get(u'pillar', {}))
|
||||
st_kwargs = __salt__.kwargs
|
||||
__opts__['grains'] = __grains__
|
||||
__opts__[u'grains'] = __grains__
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
__context__[u'fileclient'])
|
||||
chunks = st_.state.compile_high_data(data)
|
||||
file_refs = salt.client.ssh.state.lowstate_file_refs(
|
||||
chunks,
|
||||
_merge_extra_filerefs(
|
||||
kwargs.get('extra_filerefs', ''),
|
||||
__opts__.get('extra_filerefs', '')
|
||||
kwargs.get(u'extra_filerefs', u''),
|
||||
__opts__.get(u'extra_filerefs', u'')
|
||||
)
|
||||
)
|
||||
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get('roster', 'flat'))
|
||||
roster_grains = roster.opts['grains']
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get(u'roster', u'flat'))
|
||||
roster_grains = roster.opts[u'grains']
|
||||
|
||||
# Create the tar containing the state pkg and relevant files.
|
||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||
__opts__,
|
||||
__context__['fileclient'],
|
||||
__context__[u'fileclient'],
|
||||
chunks,
|
||||
file_refs,
|
||||
__pillar__,
|
||||
st_kwargs['id_'],
|
||||
st_kwargs[u'id_'],
|
||||
roster_grains)
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__['hash_type'])
|
||||
cmd = 'state.pkg {0}/salt_state.tgz pkg_sum={1} hash_type={2}'.format(
|
||||
__opts__['thin_dir'],
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__[u'hash_type'])
|
||||
cmd = u'state.pkg {0}/salt_state.tgz pkg_sum={1} hash_type={2}'.format(
|
||||
__opts__[u'thin_dir'],
|
||||
trans_tar_sum,
|
||||
__opts__['hash_type'])
|
||||
__opts__[u'hash_type'])
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
cmd,
|
||||
fsclient=__context__['fileclient'],
|
||||
fsclient=__context__[u'fileclient'],
|
||||
minion_opts=__salt__.minion_opts,
|
||||
**st_kwargs)
|
||||
single.shell.send(
|
||||
trans_tar,
|
||||
'{0}/salt_state.tgz'.format(__opts__['thin_dir']))
|
||||
u'{0}/salt_state.tgz'.format(__opts__[u'thin_dir']))
|
||||
stdout, stderr, _ = single.cmd_block()
|
||||
|
||||
# Clean up our tar
|
||||
@ -274,7 +276,7 @@ def high(data, **kwargs):
|
||||
try:
|
||||
return json.loads(stdout, object_hook=salt.utils.decode_dict)
|
||||
except Exception as e:
|
||||
log.error("JSON Render failed for: {0}\n{1}".format(stdout, stderr))
|
||||
log.error(u"JSON Render failed for: %s\n%s", stdout, stderr)
|
||||
log.error(str(e))
|
||||
|
||||
# If for some reason the json load fails, return the stdout
|
||||
@ -316,56 +318,56 @@ def highstate(test=None, **kwargs):
|
||||
salt '*' state.highstate exclude=sls_to_exclude
|
||||
salt '*' state.highstate exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
|
||||
'''
|
||||
__pillar__.update(kwargs.get('pillar', {}))
|
||||
__pillar__.update(kwargs.get(u'pillar', {}))
|
||||
st_kwargs = __salt__.kwargs
|
||||
__opts__['grains'] = __grains__
|
||||
__opts__[u'grains'] = __grains__
|
||||
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
__context__[u'fileclient'])
|
||||
chunks = st_.compile_low_chunks()
|
||||
file_refs = salt.client.ssh.state.lowstate_file_refs(
|
||||
chunks,
|
||||
_merge_extra_filerefs(
|
||||
kwargs.get('extra_filerefs', ''),
|
||||
__opts__.get('extra_filerefs', '')
|
||||
kwargs.get(u'extra_filerefs', u''),
|
||||
__opts__.get(u'extra_filerefs', u'')
|
||||
)
|
||||
)
|
||||
# Check for errors
|
||||
for chunk in chunks:
|
||||
if not isinstance(chunk, dict):
|
||||
__context__['retcode'] = 1
|
||||
__context__[u'retcode'] = 1
|
||||
return chunks
|
||||
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get('roster', 'flat'))
|
||||
roster_grains = roster.opts['grains']
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get(u'roster', u'flat'))
|
||||
roster_grains = roster.opts[u'grains']
|
||||
|
||||
# Create the tar containing the state pkg and relevant files.
|
||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||
__opts__,
|
||||
__context__['fileclient'],
|
||||
__context__[u'fileclient'],
|
||||
chunks,
|
||||
file_refs,
|
||||
__pillar__,
|
||||
st_kwargs['id_'],
|
||||
st_kwargs[u'id_'],
|
||||
roster_grains)
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__['hash_type'])
|
||||
cmd = 'state.pkg {0}/salt_state.tgz test={1} pkg_sum={2} hash_type={3}'.format(
|
||||
__opts__['thin_dir'],
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__[u'hash_type'])
|
||||
cmd = u'state.pkg {0}/salt_state.tgz test={1} pkg_sum={2} hash_type={3}'.format(
|
||||
__opts__[u'thin_dir'],
|
||||
test,
|
||||
trans_tar_sum,
|
||||
__opts__['hash_type'])
|
||||
__opts__[u'hash_type'])
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
cmd,
|
||||
fsclient=__context__['fileclient'],
|
||||
fsclient=__context__[u'fileclient'],
|
||||
minion_opts=__salt__.minion_opts,
|
||||
**st_kwargs)
|
||||
single.shell.send(
|
||||
trans_tar,
|
||||
'{0}/salt_state.tgz'.format(__opts__['thin_dir']))
|
||||
u'{0}/salt_state.tgz'.format(__opts__[u'thin_dir']))
|
||||
stdout, stderr, _ = single.cmd_block()
|
||||
|
||||
# Clean up our tar
|
||||
@ -378,7 +380,7 @@ def highstate(test=None, **kwargs):
|
||||
try:
|
||||
return json.loads(stdout, object_hook=salt.utils.decode_dict)
|
||||
except Exception as e:
|
||||
log.error("JSON Render failed for: {0}\n{1}".format(stdout, stderr))
|
||||
log.error(u"JSON Render failed for: %s\n%s", stdout, stderr)
|
||||
log.error(str(e))
|
||||
|
||||
# If for some reason the json load fails, return the stdout
|
||||
@ -397,55 +399,55 @@ def top(topfn, test=None, **kwargs):
|
||||
salt '*' state.top reverse_top.sls exclude=sls_to_exclude
|
||||
salt '*' state.top reverse_top.sls exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
|
||||
'''
|
||||
__pillar__.update(kwargs.get('pillar', {}))
|
||||
__pillar__.update(kwargs.get(u'pillar', {}))
|
||||
st_kwargs = __salt__.kwargs
|
||||
__opts__['grains'] = __grains__
|
||||
__opts__[u'grains'] = __grains__
|
||||
if salt.utils.test_mode(test=test, **kwargs):
|
||||
__opts__['test'] = True
|
||||
__opts__[u'test'] = True
|
||||
else:
|
||||
__opts__['test'] = __opts__.get('test', None)
|
||||
__opts__[u'test'] = __opts__.get(u'test', None)
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
st_.opts['state_top'] = os.path.join('salt://', topfn)
|
||||
__context__[u'fileclient'])
|
||||
st_.opts[u'state_top'] = os.path.join(u'salt://', topfn)
|
||||
chunks = st_.compile_low_chunks()
|
||||
file_refs = salt.client.ssh.state.lowstate_file_refs(
|
||||
chunks,
|
||||
_merge_extra_filerefs(
|
||||
kwargs.get('extra_filerefs', ''),
|
||||
__opts__.get('extra_filerefs', '')
|
||||
kwargs.get(u'extra_filerefs', u''),
|
||||
__opts__.get(u'extra_filerefs', u'')
|
||||
)
|
||||
)
|
||||
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get('roster', 'flat'))
|
||||
roster_grains = roster.opts['grains']
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get(u'roster', u'flat'))
|
||||
roster_grains = roster.opts[u'grains']
|
||||
|
||||
# Create the tar containing the state pkg and relevant files.
|
||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||
__opts__,
|
||||
__context__['fileclient'],
|
||||
__context__[u'fileclient'],
|
||||
chunks,
|
||||
file_refs,
|
||||
__pillar__,
|
||||
st_kwargs['id_'],
|
||||
st_kwargs[u'id_'],
|
||||
roster_grains)
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__['hash_type'])
|
||||
cmd = 'state.pkg {0}/salt_state.tgz test={1} pkg_sum={2} hash_type={3}'.format(
|
||||
__opts__['thin_dir'],
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__[u'hash_type'])
|
||||
cmd = u'state.pkg {0}/salt_state.tgz test={1} pkg_sum={2} hash_type={3}'.format(
|
||||
__opts__[u'thin_dir'],
|
||||
test,
|
||||
trans_tar_sum,
|
||||
__opts__['hash_type'])
|
||||
__opts__[u'hash_type'])
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
cmd,
|
||||
fsclient=__context__['fileclient'],
|
||||
fsclient=__context__[u'fileclient'],
|
||||
minion_opts=__salt__.minion_opts,
|
||||
**st_kwargs)
|
||||
single.shell.send(
|
||||
trans_tar,
|
||||
'{0}/salt_state.tgz'.format(__opts__['thin_dir']))
|
||||
u'{0}/salt_state.tgz'.format(__opts__[u'thin_dir']))
|
||||
stdout, stderr, _ = single.cmd_block()
|
||||
|
||||
# Clean up our tar
|
||||
@ -458,7 +460,7 @@ def top(topfn, test=None, **kwargs):
|
||||
try:
|
||||
return json.loads(stdout, object_hook=salt.utils.decode_dict)
|
||||
except Exception as e:
|
||||
log.error("JSON Render failed for: {0}\n{1}".format(stdout, stderr))
|
||||
log.error(u"JSON Render failed for: %s\n%s", stdout, stderr)
|
||||
log.error(str(e))
|
||||
|
||||
# If for some reason the json load fails, return the stdout
|
||||
@ -475,12 +477,12 @@ def show_highstate():
|
||||
|
||||
salt '*' state.show_highstate
|
||||
'''
|
||||
__opts__['grains'] = __grains__
|
||||
__opts__[u'grains'] = __grains__
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
__context__[u'fileclient'])
|
||||
return st_.compile_highstate()
|
||||
|
||||
|
||||
@ -494,16 +496,16 @@ def show_lowstate():
|
||||
|
||||
salt '*' state.show_lowstate
|
||||
'''
|
||||
__opts__['grains'] = __grains__
|
||||
__opts__[u'grains'] = __grains__
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
__context__[u'fileclient'])
|
||||
return st_.compile_low_chunks()
|
||||
|
||||
|
||||
def show_sls(mods, saltenv='base', test=None, **kwargs):
|
||||
def show_sls(mods, saltenv=u'base', test=None, **kwargs):
|
||||
'''
|
||||
Display the state data from a specific sls or list of sls files on the
|
||||
master
|
||||
@ -514,20 +516,20 @@ def show_sls(mods, saltenv='base', test=None, **kwargs):
|
||||
|
||||
salt '*' state.show_sls core,edit.vim dev
|
||||
'''
|
||||
__pillar__.update(kwargs.get('pillar', {}))
|
||||
__opts__['grains'] = __grains__
|
||||
__pillar__.update(kwargs.get(u'pillar', {}))
|
||||
__opts__[u'grains'] = __grains__
|
||||
opts = copy.copy(__opts__)
|
||||
if salt.utils.test_mode(test=test, **kwargs):
|
||||
opts['test'] = True
|
||||
opts[u'test'] = True
|
||||
else:
|
||||
opts['test'] = __opts__.get('test', None)
|
||||
opts[u'test'] = __opts__.get(u'test', None)
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
if isinstance(mods, string_types):
|
||||
mods = mods.split(',')
|
||||
__context__[u'fileclient'])
|
||||
if isinstance(mods, six.string_types):
|
||||
mods = mods.split(u',')
|
||||
high_data, errors = st_.render_highstate({saltenv: mods})
|
||||
high_data, ext_errors = st_.state.reconcile_extend(high_data)
|
||||
errors += ext_errors
|
||||
@ -543,7 +545,7 @@ def show_sls(mods, saltenv='base', test=None, **kwargs):
|
||||
return high_data
|
||||
|
||||
|
||||
def show_low_sls(mods, saltenv='base', test=None, **kwargs):
|
||||
def show_low_sls(mods, saltenv=u'base', test=None, **kwargs):
|
||||
'''
|
||||
Display the low state data from a specific sls or list of sls files on the
|
||||
master.
|
||||
@ -556,21 +558,21 @@ def show_low_sls(mods, saltenv='base', test=None, **kwargs):
|
||||
|
||||
salt '*' state.show_sls core,edit.vim dev
|
||||
'''
|
||||
__pillar__.update(kwargs.get('pillar', {}))
|
||||
__opts__['grains'] = __grains__
|
||||
__pillar__.update(kwargs.get(u'pillar', {}))
|
||||
__opts__[u'grains'] = __grains__
|
||||
|
||||
opts = copy.copy(__opts__)
|
||||
if salt.utils.test_mode(test=test, **kwargs):
|
||||
opts['test'] = True
|
||||
opts[u'test'] = True
|
||||
else:
|
||||
opts['test'] = __opts__.get('test', None)
|
||||
opts[u'test'] = __opts__.get(u'test', None)
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
if isinstance(mods, string_types):
|
||||
mods = mods.split(',')
|
||||
__context__[u'fileclient'])
|
||||
if isinstance(mods, six.string_types):
|
||||
mods = mods.split(u',')
|
||||
high_data, errors = st_.render_highstate({saltenv: mods})
|
||||
high_data, ext_errors = st_.state.reconcile_extend(high_data)
|
||||
errors += ext_errors
|
||||
@ -597,12 +599,12 @@ def show_top():
|
||||
|
||||
salt '*' state.show_top
|
||||
'''
|
||||
__opts__['grains'] = __grains__
|
||||
__opts__[u'grains'] = __grains__
|
||||
st_ = salt.client.ssh.state.SSHHighState(
|
||||
__opts__,
|
||||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
__context__[u'fileclient'])
|
||||
top_data = st_.get_top()
|
||||
errors = []
|
||||
errors += st_.verify_tops(top_data)
|
||||
@ -632,30 +634,30 @@ def single(fun, name, test=None, **kwargs):
|
||||
|
||||
'''
|
||||
st_kwargs = __salt__.kwargs
|
||||
__opts__['grains'] = __grains__
|
||||
__opts__[u'grains'] = __grains__
|
||||
|
||||
# state.fun -> [state, fun]
|
||||
comps = fun.split('.')
|
||||
comps = fun.split(u'.')
|
||||
if len(comps) < 2:
|
||||
__context__['retcode'] = 1
|
||||
return 'Invalid function passed'
|
||||
__context__[u'retcode'] = 1
|
||||
return u'Invalid function passed'
|
||||
|
||||
# Create the low chunk, using kwargs as a base
|
||||
kwargs.update({'state': comps[0],
|
||||
'fun': comps[1],
|
||||
'__id__': name,
|
||||
'name': name})
|
||||
kwargs.update({u'state': comps[0],
|
||||
u'fun': comps[1],
|
||||
u'__id__': name,
|
||||
u'name': name})
|
||||
|
||||
opts = copy.deepcopy(__opts__)
|
||||
|
||||
# Set test mode
|
||||
if salt.utils.test_mode(test=test, **kwargs):
|
||||
opts['test'] = True
|
||||
opts[u'test'] = True
|
||||
else:
|
||||
opts['test'] = __opts__.get('test', None)
|
||||
opts[u'test'] = __opts__.get(u'test', None)
|
||||
|
||||
# Get the override pillar data
|
||||
__pillar__.update(kwargs.get('pillar', {}))
|
||||
__pillar__.update(kwargs.get(u'pillar', {}))
|
||||
|
||||
# Create the State environment
|
||||
st_ = salt.client.ssh.state.SSHState(__opts__, __pillar__)
|
||||
@ -663,7 +665,7 @@ def single(fun, name, test=None, **kwargs):
|
||||
# Verify the low chunk
|
||||
err = st_.verify_data(kwargs)
|
||||
if err:
|
||||
__context__['retcode'] = 1
|
||||
__context__[u'retcode'] = 1
|
||||
return err
|
||||
|
||||
# Must be a list of low-chunks
|
||||
@ -674,46 +676,46 @@ def single(fun, name, test=None, **kwargs):
|
||||
file_refs = salt.client.ssh.state.lowstate_file_refs(
|
||||
chunks,
|
||||
_merge_extra_filerefs(
|
||||
kwargs.get('extra_filerefs', ''),
|
||||
__opts__.get('extra_filerefs', '')
|
||||
kwargs.get(u'extra_filerefs', u''),
|
||||
__opts__.get(u'extra_filerefs', u'')
|
||||
)
|
||||
)
|
||||
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get('roster', 'flat'))
|
||||
roster_grains = roster.opts['grains']
|
||||
roster = salt.roster.Roster(__opts__, __opts__.get(u'roster', u'flat'))
|
||||
roster_grains = roster.opts[u'grains']
|
||||
|
||||
# Create the tar containing the state pkg and relevant files.
|
||||
trans_tar = salt.client.ssh.state.prep_trans_tar(
|
||||
__opts__,
|
||||
__context__['fileclient'],
|
||||
__context__[u'fileclient'],
|
||||
chunks,
|
||||
file_refs,
|
||||
__pillar__,
|
||||
st_kwargs['id_'],
|
||||
st_kwargs[u'id_'],
|
||||
roster_grains)
|
||||
|
||||
# Create a hash so we can verify the tar on the target system
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__['hash_type'])
|
||||
trans_tar_sum = salt.utils.get_hash(trans_tar, __opts__[u'hash_type'])
|
||||
|
||||
# We use state.pkg to execute the "state package"
|
||||
cmd = 'state.pkg {0}/salt_state.tgz test={1} pkg_sum={2} hash_type={3}'.format(
|
||||
__opts__['thin_dir'],
|
||||
cmd = u'state.pkg {0}/salt_state.tgz test={1} pkg_sum={2} hash_type={3}'.format(
|
||||
__opts__[u'thin_dir'],
|
||||
test,
|
||||
trans_tar_sum,
|
||||
__opts__['hash_type'])
|
||||
__opts__[u'hash_type'])
|
||||
|
||||
# Create a salt-ssh Single object to actually do the ssh work
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
cmd,
|
||||
fsclient=__context__['fileclient'],
|
||||
fsclient=__context__[u'fileclient'],
|
||||
minion_opts=__salt__.minion_opts,
|
||||
**st_kwargs)
|
||||
|
||||
# Copy the tar down
|
||||
single.shell.send(
|
||||
trans_tar,
|
||||
'{0}/salt_state.tgz'.format(__opts__['thin_dir']))
|
||||
u'{0}/salt_state.tgz'.format(__opts__[u'thin_dir']))
|
||||
|
||||
# Run the state.pkg command on the target
|
||||
stdout, stderr, _ = single.cmd_block()
|
||||
@ -728,7 +730,7 @@ def single(fun, name, test=None, **kwargs):
|
||||
try:
|
||||
return json.loads(stdout, object_hook=salt.utils.decode_dict)
|
||||
except Exception as e:
|
||||
log.error("JSON Render failed for: {0}\n{1}".format(stdout, stderr))
|
||||
log.error(u"JSON Render failed for: %s\n%s", stdout, stderr)
|
||||
log.error(str(e))
|
||||
|
||||
# If for some reason the json load fails, return the stdout
|
||||
|
@ -30,13 +30,12 @@ import salt.config
|
||||
import salt.client
|
||||
import salt.loader
|
||||
import salt.utils
|
||||
import salt.utils.args
|
||||
import salt.utils.cloud
|
||||
import salt.utils.context
|
||||
import salt.utils.dictupdate
|
||||
import salt.utils.files
|
||||
import salt.syspaths
|
||||
from salt.utils import reinit_crypto
|
||||
from salt.utils import context
|
||||
from salt.ext.six import string_types
|
||||
from salt.template import compile_template
|
||||
|
||||
# Import third party libs
|
||||
@ -48,7 +47,7 @@ except ImportError:
|
||||
except ImportError:
|
||||
pass # pycrypto < 2.1
|
||||
import yaml
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
from salt.ext.six.moves import input # pylint: disable=import-error,redefined-builtin
|
||||
|
||||
# Get logging started
|
||||
@ -342,7 +341,7 @@ class CloudClient(object):
|
||||
vm_overrides = {}
|
||||
kwargs['profile'] = profile
|
||||
mapper = salt.cloud.Map(self._opts_defaults(**kwargs))
|
||||
if isinstance(names, str):
|
||||
if isinstance(names, six.string_types):
|
||||
names = names.split(',')
|
||||
return salt.utils.simple_types_filter(
|
||||
mapper.run_profile(profile, names, vm_overrides=vm_overrides)
|
||||
@ -367,7 +366,7 @@ class CloudClient(object):
|
||||
Destroy the named VMs
|
||||
'''
|
||||
mapper = salt.cloud.Map(self._opts_defaults(destroy=True))
|
||||
if isinstance(names, str):
|
||||
if isinstance(names, six.string_types):
|
||||
names = names.split(',')
|
||||
return salt.utils.simple_types_filter(
|
||||
mapper.destroy(names)
|
||||
@ -391,7 +390,7 @@ class CloudClient(object):
|
||||
provider += ':{0}'.format(next(six.iterkeys(providers[provider])))
|
||||
else:
|
||||
return False
|
||||
if isinstance(names, str):
|
||||
if isinstance(names, six.string_types):
|
||||
names = names.split(',')
|
||||
ret = {}
|
||||
for name in names:
|
||||
@ -433,7 +432,7 @@ class CloudClient(object):
|
||||
provider += ':{0}'.format(next(six.iterkeys(providers[provider])))
|
||||
else:
|
||||
return False
|
||||
if isinstance(names, str):
|
||||
if isinstance(names, six.string_types):
|
||||
names = names.split(',')
|
||||
|
||||
ret = {}
|
||||
@ -625,7 +624,7 @@ class Cloud(object):
|
||||
pmap[alias] = {}
|
||||
|
||||
try:
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=':'.join([alias, driver])
|
||||
):
|
||||
@ -708,7 +707,7 @@ class Cloud(object):
|
||||
|
||||
def get_running_by_names(self, names, query='list_nodes', cached=False,
|
||||
profile=None):
|
||||
if isinstance(names, string_types):
|
||||
if isinstance(names, six.string_types):
|
||||
names = [names]
|
||||
|
||||
matches = {}
|
||||
@ -730,18 +729,9 @@ class Cloud(object):
|
||||
continue
|
||||
|
||||
for vm_name, details in six.iteritems(vms):
|
||||
# If VM was created with use_fqdn with either of the softlayer drivers,
|
||||
# we need to strip the VM name and only search for the short hostname.
|
||||
if driver == 'softlayer' or driver == 'softlayer_hw':
|
||||
ret = []
|
||||
for name in names:
|
||||
name = name.split('.')[0]
|
||||
ret.append(name)
|
||||
if vm_name not in ret:
|
||||
continue
|
||||
# XXX: The logic below can be removed once the aws driver
|
||||
# is removed
|
||||
elif vm_name not in names:
|
||||
if vm_name not in names:
|
||||
continue
|
||||
|
||||
elif driver == 'ec2' and 'aws' in handled_drivers and \
|
||||
@ -827,7 +817,7 @@ class Cloud(object):
|
||||
|
||||
try:
|
||||
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=':'.join([alias, driver])
|
||||
):
|
||||
@ -870,7 +860,7 @@ class Cloud(object):
|
||||
data[alias] = {}
|
||||
|
||||
try:
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=':'.join([alias, driver])
|
||||
):
|
||||
@ -913,7 +903,7 @@ class Cloud(object):
|
||||
data[alias] = {}
|
||||
|
||||
try:
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=':'.join([alias, driver])
|
||||
):
|
||||
@ -1035,7 +1025,7 @@ class Cloud(object):
|
||||
log.info('Destroying in non-parallel mode.')
|
||||
for alias, driver, name in vms_to_destroy:
|
||||
fun = '{0}.destroy'.format(driver)
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=':'.join([alias, driver])
|
||||
):
|
||||
@ -1280,7 +1270,7 @@ class Cloud(object):
|
||||
try:
|
||||
alias, driver = vm_['provider'].split(':')
|
||||
func = '{0}.create'.format(driver)
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=':'.join([alias, driver])
|
||||
):
|
||||
@ -1366,7 +1356,7 @@ class Cloud(object):
|
||||
return
|
||||
|
||||
try:
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=extra_['provider']
|
||||
):
|
||||
@ -1514,7 +1504,7 @@ class Cloud(object):
|
||||
invalid_functions[fun].append(vm_name)
|
||||
continue
|
||||
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=':'.join([alias, driver])
|
||||
):
|
||||
@ -1526,7 +1516,7 @@ class Cloud(object):
|
||||
# Clean kwargs of "__pub_*" data before running the cloud action call.
|
||||
# Prevents calling positional "kwarg" arg before "call" when no kwarg
|
||||
# argument is present in the cloud driver function's arg spec.
|
||||
kwargs = salt.utils.clean_kwargs(**kwargs)
|
||||
kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
||||
|
||||
if kwargs:
|
||||
ret[alias][driver][vm_name] = self.clouds[fun](
|
||||
@ -1598,7 +1588,7 @@ class Cloud(object):
|
||||
)
|
||||
)
|
||||
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=':'.join([alias, driver])
|
||||
):
|
||||
@ -1646,7 +1636,7 @@ class Cloud(object):
|
||||
self.opts['providers'].pop(alias)
|
||||
continue
|
||||
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
self.clouds[fun],
|
||||
__active_provider_name__=':'.join([alias, driver])
|
||||
):
|
||||
@ -1815,7 +1805,7 @@ class Map(Cloud):
|
||||
if isinstance(mapped, (list, tuple)):
|
||||
entries = {}
|
||||
for mapping in mapped:
|
||||
if isinstance(mapping, string_types):
|
||||
if isinstance(mapping, six.string_types):
|
||||
# Foo:
|
||||
# - bar1
|
||||
# - bar2
|
||||
@ -1855,7 +1845,7 @@ class Map(Cloud):
|
||||
map_[profile] = entries
|
||||
continue
|
||||
|
||||
if isinstance(mapped, string_types):
|
||||
if isinstance(mapped, six.string_types):
|
||||
# If it's a single string entry, let's make iterable because of
|
||||
# the next step
|
||||
mapped = [mapped]
|
||||
@ -2310,7 +2300,7 @@ def create_multiprocessing(parallel_data, queue=None):
|
||||
This function will be called from another process when running a map in
|
||||
parallel mode. The result from the create is always a json object.
|
||||
'''
|
||||
reinit_crypto()
|
||||
salt.utils.reinit_crypto()
|
||||
|
||||
parallel_data['opts']['output'] = 'json'
|
||||
cloud = Cloud(parallel_data['opts'])
|
||||
@ -2342,14 +2332,14 @@ def destroy_multiprocessing(parallel_data, queue=None):
|
||||
This function will be called from another process when running a map in
|
||||
parallel mode. The result from the destroy is always a json object.
|
||||
'''
|
||||
reinit_crypto()
|
||||
salt.utils.reinit_crypto()
|
||||
|
||||
parallel_data['opts']['output'] = 'json'
|
||||
clouds = salt.loader.clouds(parallel_data['opts'])
|
||||
|
||||
try:
|
||||
fun = clouds['{0}.destroy'.format(parallel_data['driver'])]
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
fun,
|
||||
__active_provider_name__=':'.join([
|
||||
parallel_data['alias'],
|
||||
@ -2378,11 +2368,11 @@ def run_parallel_map_providers_query(data, queue=None):
|
||||
This function will be called from another process when building the
|
||||
providers map.
|
||||
'''
|
||||
reinit_crypto()
|
||||
salt.utils.reinit_crypto()
|
||||
|
||||
cloud = Cloud(data['opts'])
|
||||
try:
|
||||
with context.func_globals_inject(
|
||||
with salt.utils.context.func_globals_inject(
|
||||
cloud.clouds[data['fun']],
|
||||
__active_provider_name__=':'.join([
|
||||
data['alias'],
|
||||
|
@ -20,23 +20,24 @@ import logging
|
||||
from salt.ext.six.moves import input
|
||||
|
||||
# Import salt libs
|
||||
import salt.cloud
|
||||
import salt.utils.cloud
|
||||
import salt.config
|
||||
import salt.defaults.exitcodes
|
||||
import salt.output
|
||||
import salt.syspaths as syspaths
|
||||
import salt.utils
|
||||
from salt.utils import parsers
|
||||
import salt.utils.parsers
|
||||
from salt.exceptions import SaltCloudException, SaltCloudSystemExit
|
||||
from salt.utils.verify import check_user, verify_env, verify_files, verify_log
|
||||
|
||||
# Import salt.cloud libs
|
||||
import salt.cloud
|
||||
import salt.utils.cloud
|
||||
from salt.exceptions import SaltCloudException, SaltCloudSystemExit
|
||||
import salt.ext.six as six
|
||||
import salt.syspaths as syspaths
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SaltCloud(parsers.SaltCloudParser):
|
||||
class SaltCloud(salt.utils.parsers.SaltCloudParser):
|
||||
|
||||
def run(self):
|
||||
'''
|
||||
|
@ -50,7 +50,8 @@ from salt.exceptions import (
|
||||
SaltCloudExecutionTimeout
|
||||
)
|
||||
|
||||
# Import Third Party Libs
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
try:
|
||||
import requests
|
||||
HAS_REQUESTS = True
|
||||
@ -745,7 +746,7 @@ def _compute_signature(parameters, access_key_secret):
|
||||
'''
|
||||
|
||||
def percent_encode(line):
|
||||
if not isinstance(line, str):
|
||||
if not isinstance(line, six.string_types):
|
||||
return line
|
||||
|
||||
s = line
|
||||
|
@ -65,7 +65,7 @@ import salt.config as config
|
||||
import salt.utils
|
||||
import salt.utils.cloud
|
||||
import salt.utils.files
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
import salt.version
|
||||
from salt.exceptions import (
|
||||
SaltCloudSystemExit,
|
||||
|
@ -30,6 +30,8 @@ import logging
|
||||
|
||||
# Import salt cloud libs
|
||||
import salt.config as config
|
||||
import salt.utils.cloud
|
||||
import salt.utils.event
|
||||
from salt.cloud.libcloudfuncs import * # pylint: disable=redefined-builtin,wildcard-import,unused-wildcard-import
|
||||
from salt.utils import namespaced_function
|
||||
from salt.exceptions import SaltCloudSystemExit
|
||||
|
@ -46,9 +46,8 @@ from salt.exceptions import (
|
||||
SaltCloudExecutionFailure,
|
||||
SaltCloudExecutionTimeout
|
||||
)
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
from salt.ext.six.moves import zip
|
||||
from salt.ext.six import string_types
|
||||
|
||||
# Import Third Party Libs
|
||||
try:
|
||||
@ -209,7 +208,7 @@ def get_image(vm_):
|
||||
vm_image = config.get_cloud_config_value(
|
||||
'image', vm_, __opts__, search_global=False
|
||||
)
|
||||
if not isinstance(vm_image, string_types):
|
||||
if not isinstance(vm_image, six.string_types):
|
||||
vm_image = str(vm_image)
|
||||
|
||||
for image in images:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user