salt/doc/topics/proxyminion/index.rst

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

939 lines
30 KiB
ReStructuredText
Raw Normal View History

.. _proxy-minion:
=================
Salt Proxy Minion
=================
2013-12-25 21:08:56 -07:00
2014-01-15 13:00:59 -07:00
Proxy minions are a developing Salt feature that enables controlling devices
that, for whatever reason, cannot run a standard salt-minion. Examples include
network gear that has an API but runs a proprietary OS, devices with limited
CPU or memory, or devices that could run a minion, but for security reasons,
will not.
2013-12-25 21:08:56 -07:00
There are some :ref:`proxy modules <all-salt.proxy>` available, but if your device
interface is not currently supported you will most likely have to write the interface
yourself, because there are an infinite number of controllable devices. Fortunately, this
is only as difficult as the actual interface to the proxied device. Devices that have an
existing Python module (PyUSB for example) would be relatively simple to interface.
Code to control a device that has an HTML REST-based interface should be easy. Code to
control your typical housecat would be excellent source material for a PhD thesis.
2013-12-25 21:08:56 -07:00
2014-01-14 14:29:11 -07:00
Salt proxy-minions provide the 'plumbing' that allows device enumeration
and discovery, control, status, remote execution, and state management.
2013-12-25 21:08:56 -07:00
See the :ref:`Proxy Minion Walkthrough <proxy-minion-end-to-end-example>` for an end-to-end
demonstration of a working REST-based proxy minion.
2015-08-18 14:43:26 -06:00
See the :ref:`Proxy Minion SSH Walkthrough <proxy-minion-ssh-end-to-end-example>` for an end-to-end
2015-10-19 13:30:35 -04:00
demonstration of a working SSH proxy minion.
2015-11-19 12:51:45 -05:00
See :ref:`Proxyminion States <proxy-minion-states>` to configure and
2015-11-19 12:51:45 -05:00
run ``salt-proxy`` on a remote minion. Specify all your master side
proxy (pillar) configuration and use this state to remotely configure proxies on one
or more minions.
See :ref:`Proxyminion Beacon <proxy-minion-beacon>` to help
2015-12-08 15:58:38 -05:00
with easy configuration and management of ``salt-proxy`` processes.
2015-11-19 12:51:45 -05:00
New in 2017.7.0
---------------
2017-03-23 14:15:13 +00:00
The :conf_proxy:`proxy_merge_grains_in_module` configuration variable
introduced in 2016.3, has been changed, defaulting to ``True``.
The connection with the remote device is kept alive by default, when the
module implements the ``alive`` function and :conf_proxy:`proxy_keep_alive`
is set to ``True``. The polling interval is set using the
:conf_proxy:`proxy_keep_alive_interval` option which defaults to 1 minute.
The developers are also able to use the :conf_proxy:`proxy_always_alive`,
when designing a proxy module flexible enough to open the
connection with the remote device only when required.
New in 2016.11.0
----------------
Proxy minions now support configuration files with names ending in '\*.conf'
and placed in /etc/salt/proxy.d.
Proxy minions can now be configured in /etc/salt/proxy or /etc/salt/proxy.d
instead of just pillar. Configuration format is the same as it would be in pillar.
New in 2016.3
-------------
The deprecated config option ``enumerate_proxy_minions`` has been removed.
As mentioned in earlier documentation, the ``add_proxymodule_to_opts``
configuration variable defaults to ``False`` in this release. This means if you
have proxymodules or other code looking in ``__opts__['proxymodule']`` you
will need to set this variable in your ``/etc/salt/proxy`` file, or
modify your code to use the `__proxy__` injected variable.
The ``__proxyenabled__`` directive now only applies to grains and proxy modules
themselves. Standard execution modules and state modules are not prevented
from loading for proxy minions.
Enhancements in grains processing have made the ``__proxyenabled__`` directive
somewhat redundant in dynamic grains code. It is still required, but best
practices for the ``__virtual__`` function in grains files have changed. It
is now recommended that the ``__virtual__`` functions check to make sure
they are being loaded for the correct proxytype, example below:
.. code-block:: python
def __virtual__():
2020-06-09 09:58:34 +01:00
"""
Only work on proxy
2020-06-09 09:58:34 +01:00
"""
try:
Use explicit unicode strings + break up salt.utils This PR is part of what will be an ongoing effort to use explicit unicode strings in Salt. Because Python 3 does not suport Python 2's raw unicode string syntax (i.e. `ur'\d+'`), we must use `salt.utils.locales.sdecode()` to ensure that the raw string is unicode. However, because of how `salt/utils/__init__.py` has evolved into the hulking monstrosity it is today, this means importing a large module in places where it is not needed, which could negatively impact performance. For this reason, this PR also breaks out some of the functions from `salt/utils/__init__.py` into new/existing modules under `salt/utils/`. The long term goal will be that the modules within this directory do not depend on importing `salt.utils`. A summary of the changes in this PR is as follows: * Moves the following functions from `salt.utils` to new locations (including a deprecation warning if invoked from `salt.utils`): `to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`, `dequote`, `is_hex`, `is_bin_str`, `rand_string`, `contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`, `which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`, `is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`, `is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`, `is_openbsd`, `is_aix` * Moves the functions already deprecated by @rallytime to the bottom of `salt/utils/__init__.py` for better organization, so we can keep the deprecated ones separate from the ones yet to be deprecated as we continue to break up `salt.utils` * Updates `salt/*.py` and all files under `salt/client/` to use explicit unicode string literals. * Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils import foo` becomes `import salt.utils.foo as foo`). * Renames the `test.rand_str` function to `test.random_hash` to more accurately reflect what it does * Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`) such that it returns a string matching the passed size. Previously this function would get `size` bytes from `os.urandom()`, base64-encode it, and return the result, which would in most cases not be equal to the passed size.
2017-07-24 20:47:15 -05:00
if (
salt.utils.platform.is_proxy()
and __opts__["proxy"]["proxytype"] == "ssh_sample"
):
return __virtualname__
except KeyError:
pass
return False
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.
Grains are loaded so early in startup that no dunder dictionaries are
present, so ``__proxy__``, ``__salt__``, etc. are not available. Custom
grains located in ``/srv/salt/_grains`` and in the salt install grains
directory can now take a single argument, ``proxy``, that is identical
to ``__proxy__``. This enables patterns like
.. code-block:: python
def get_ip(proxy):
2020-06-09 09:58:34 +01:00
"""
Ask the remote device what IP it has
2020-06-09 09:58:34 +01:00
"""
return {"ip": proxy["proxymodulename.get_ip"]()}
Then the grain ``ip`` will contain the result of calling the ``get_ip()`` function
in the proxymodule called ``proxymodulename``.
Proxy modules now benefit from including a function called ``initialized()``. This
function should return ``True`` if the proxy's ``init()`` function has been successfully
called. This is needed to make grains processing easier.
Finally, if there is a function called ``grains`` in the proxymodule, it
will be executed on proxy-minion startup and its contents will be merged with
the rest of the proxy's grains. Since older proxy-minions might have used other
methods to call such a function and add its results to grains, this is config-gated
by a new proxy configuration option called ``proxy_merge_grains_in_module``. This
defaults to ``True`` in the **2017.7.0** release.
2015-10-12 14:55:19 -06:00
New in 2015.8.2
---------------
*BREAKING CHANGE*: Adding the `proxymodule` variable to __opts__ is deprecated.
The `proxymodule` variable has been moved a new globally-injected variable
called `__proxy__`. A related configuration option called
`add_proxymodule_to_opts` has been added and defaults to `True`. In the next
major release, 2016.3.0, this variable will default to False.
2015-10-12 14:55:19 -06:00
In the meantime, proxies that functioned under 2015.8.0 and .1 should continue
to work under 2015.8.2. You should rework your proxy code to use `__proxy__` as
soon as possible.
The `rest_sample` example proxy minion has been updated to use `__proxy__`.
This change was made because proxymodules are a LazyLoader object, but
LazyLoaders cannot be serialized. `__opts__` gets serialized, and so things
like `saltutil.sync_all` and `state.highstate` would throw exceptions.
Support has been added to Salt's loader allowing custom proxymodules
to be placed in ``salt://_proxy``. Proxy minions that need these modules
will need to be restarted to pick up any changes. A corresponding utility function,
``saltutil.sync_proxymodules``, has been added to sync these modules to minions.
2015-10-12 14:55:19 -06:00
In addition, a salt.utils helper function called `is_proxy()` was added to make
Use explicit unicode strings + break up salt.utils This PR is part of what will be an ongoing effort to use explicit unicode strings in Salt. Because Python 3 does not suport Python 2's raw unicode string syntax (i.e. `ur'\d+'`), we must use `salt.utils.locales.sdecode()` to ensure that the raw string is unicode. However, because of how `salt/utils/__init__.py` has evolved into the hulking monstrosity it is today, this means importing a large module in places where it is not needed, which could negatively impact performance. For this reason, this PR also breaks out some of the functions from `salt/utils/__init__.py` into new/existing modules under `salt/utils/`. The long term goal will be that the modules within this directory do not depend on importing `salt.utils`. A summary of the changes in this PR is as follows: * Moves the following functions from `salt.utils` to new locations (including a deprecation warning if invoked from `salt.utils`): `to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`, `dequote`, `is_hex`, `is_bin_str`, `rand_string`, `contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`, `which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`, `is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`, `is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`, `is_openbsd`, `is_aix` * Moves the functions already deprecated by @rallytime to the bottom of `salt/utils/__init__.py` for better organization, so we can keep the deprecated ones separate from the ones yet to be deprecated as we continue to break up `salt.utils` * Updates `salt/*.py` and all files under `salt/client/` to use explicit unicode string literals. * Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils import foo` becomes `import salt.utils.foo as foo`). * Renames the `test.rand_str` function to `test.random_hash` to more accurately reflect what it does * Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`) such that it returns a string matching the passed size. Previously this function would get `size` bytes from `os.urandom()`, base64-encode it, and return the result, which would in most cases not be equal to the passed size.
2017-07-24 20:47:15 -05:00
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 2018.3.0
release**
2015-08-14 11:52:19 -06:00
New in 2015.8
-------------
Use explicit unicode strings + break up salt.utils This PR is part of what will be an ongoing effort to use explicit unicode strings in Salt. Because Python 3 does not suport Python 2's raw unicode string syntax (i.e. `ur'\d+'`), we must use `salt.utils.locales.sdecode()` to ensure that the raw string is unicode. However, because of how `salt/utils/__init__.py` has evolved into the hulking monstrosity it is today, this means importing a large module in places where it is not needed, which could negatively impact performance. For this reason, this PR also breaks out some of the functions from `salt/utils/__init__.py` into new/existing modules under `salt/utils/`. The long term goal will be that the modules within this directory do not depend on importing `salt.utils`. A summary of the changes in this PR is as follows: * Moves the following functions from `salt.utils` to new locations (including a deprecation warning if invoked from `salt.utils`): `to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`, `dequote`, `is_hex`, `is_bin_str`, `rand_string`, `contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`, `which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`, `is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`, `is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`, `is_openbsd`, `is_aix` * Moves the functions already deprecated by @rallytime to the bottom of `salt/utils/__init__.py` for better organization, so we can keep the deprecated ones separate from the ones yet to be deprecated as we continue to break up `salt.utils` * Updates `salt/*.py` and all files under `salt/client/` to use explicit unicode string literals. * Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils import foo` becomes `import salt.utils.foo as foo`). * Renames the `test.rand_str` function to `test.random_hash` to more accurately reflect what it does * Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`) such that it returns a string matching the passed size. Previously this function would get `size` bytes from `os.urandom()`, base64-encode it, and return the result, which would in most cases not be equal to the passed size.
2017-07-24 20:47:15 -05:00
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.
2015-08-14 11:52:19 -06:00
Use explicit unicode strings + break up salt.utils This PR is part of what will be an ongoing effort to use explicit unicode strings in Salt. Because Python 3 does not suport Python 2's raw unicode string syntax (i.e. `ur'\d+'`), we must use `salt.utils.locales.sdecode()` to ensure that the raw string is unicode. However, because of how `salt/utils/__init__.py` has evolved into the hulking monstrosity it is today, this means importing a large module in places where it is not needed, which could negatively impact performance. For this reason, this PR also breaks out some of the functions from `salt/utils/__init__.py` into new/existing modules under `salt/utils/`. The long term goal will be that the modules within this directory do not depend on importing `salt.utils`. A summary of the changes in this PR is as follows: * Moves the following functions from `salt.utils` to new locations (including a deprecation warning if invoked from `salt.utils`): `to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`, `dequote`, `is_hex`, `is_bin_str`, `rand_string`, `contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`, `which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`, `is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`, `is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`, `is_openbsd`, `is_aix` * Moves the functions already deprecated by @rallytime to the bottom of `salt/utils/__init__.py` for better organization, so we can keep the deprecated ones separate from the ones yet to be deprecated as we continue to break up `salt.utils` * Updates `salt/*.py` and all files under `salt/client/` to use explicit unicode string literals. * Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils import foo` becomes `import salt.utils.foo as foo`). * Renames the `test.rand_str` function to `test.random_hash` to more accurately reflect what it does * Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`) such that it returns a string matching the passed size. Previously this function would get `size` bytes from `os.urandom()`, base64-encode it, and return the result, which would in most cases not be equal to the passed size.
2017-07-24 20:47:15 -05:00
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.
2015-08-14 11:52:19 -06:00
2013-12-25 21:08:56 -07:00
Getting Started
2014-01-14 14:29:11 -07:00
---------------
The following diagram may be helpful in understanding the structure of a Salt
installation that includes proxy-minions:
.. image:: /_static/proxy_minions.png
The key thing to remember is the left-most section of the diagram. Salt's
nature is to have a minion connect to a master, then the master may control
2015-08-14 11:52:19 -06:00
the minion. However, for proxy minions, the target device cannot run a minion.
2014-01-14 14:29:11 -07:00
After the proxy minion is started and initiates its connection to the
2015-08-14 11:52:19 -06:00
device, it connects back to the salt-master and for all intents and purposes
looks like just another minion to the Salt master.
2014-01-14 14:29:11 -07:00
2014-01-16 12:39:23 -07:00
To create support for a proxied device one needs to create four things:
2015-08-06 15:43:53 -06:00
1. The `proxy_connection_module`_ (located in salt/proxy).
2014-01-16 12:39:23 -07:00
2. The `grains support code`_ (located in salt/grains).
2014-01-26 05:28:14 -06:00
3. :ref:`Salt modules <all-salt.modules>` specific to the controlled
device.
4. :ref:`Salt states <all-salt.states>` specific to the controlled device.
2014-01-16 12:39:23 -07:00
2014-01-14 14:29:11 -07:00
2015-08-14 11:52:19 -06:00
Configuration parameters
########################
2014-01-14 14:29:11 -07:00
2014-01-15 13:00:59 -07:00
Proxy minions require no configuration parameters in /etc/salt/master.
2014-01-14 14:29:11 -07:00
Salt's Pillar system is ideally suited for configuring proxy-minions
(though they can be configured in /etc/salt/proxy as well). Proxies
2014-01-15 13:00:59 -07:00
can either be designated via a pillar file in pillar_roots, or through an
external pillar. External pillars afford the opportunity for interfacing with
a configuration management system, database, or other knowledgeable system that
that may already contain all the details of proxy targets. To use static files
in pillar_roots, pattern your files after the following examples, which are
based on the diagram above:
2014-01-14 14:29:11 -07:00
``/srv/pillar/top.sls``
2014-01-14 14:29:11 -07:00
.. code-block:: yaml
base:
net-device1:
- net-device1
net-device2:
- net-device2
net-device3:
- net-device3
i2c-device4:
- i2c-device4
i2c-device5:
- i2c-device5
433wireless-device6:
- 433wireless-device6
smsgate-device7:
- device7
``/srv/pillar/net-device1.sls``
2014-01-14 14:29:11 -07:00
.. code-block:: yaml
proxy:
proxytype: networkswitch
host: 172.23.23.5
username: root
passwd: letmein
2014-01-14 14:29:11 -07:00
``/srv/pillar/net-device2.sls``
2014-01-14 14:29:11 -07:00
.. code-block:: yaml
proxy:
proxytype: networkswitch
host: 172.23.23.6
username: root
passwd: letmein
``/srv/pillar/net-device3.sls``
.. code-block:: yaml
proxy:
proxytype: networkswitch
host: 172.23.23.7
username: root
passwd: letmein
``/srv/pillar/i2c-device4.sls``
.. code-block:: yaml
proxy:
proxytype: i2c_lightshow
i2c_address: 1
``/srv/pillar/i2c-device5.sls``
.. code-block:: yaml
proxy:
2014-01-14 14:29:11 -07:00
proxytype: i2c_lightshow
i2c_address: 2
``/srv/pillar/433wireless-device6.sls``
.. code-block:: yaml
proxy:
2014-01-14 14:29:11 -07:00
proxytype: 433mhz_wireless
``/srv/pillar/smsgate-device7.sls``
2014-01-14 14:29:11 -07:00
.. code-block:: yaml
proxy:
proxytype: sms_serial
deventry: /dev/tty04
2014-01-14 14:29:11 -07:00
Note the contents of each minioncontroller key may differ widely based on
the type of device that the proxy-minion is managing.
In the above example
- net-devices 1, 2, and 3 are network switches that have a management
2014-01-14 14:29:11 -07:00
interface available at a particular IP address.
- i2c-devices 4 and 5 are very low-level devices controlled over an i2c bus.
2014-01-26 05:28:14 -06:00
In this case the devices are physically connected to machine
'minioncontroller2', and are addressable on the i2c bus at their respective
i2c addresses.
2014-01-14 14:29:11 -07:00
- 433wireless-device6 is a 433 MHz wireless transmitter, also physically connected to
2014-01-26 05:28:14 -06:00
minioncontroller2
2014-01-14 14:29:11 -07:00
- smsgate-device7 is an SMS gateway connected to machine minioncontroller3 via a
2014-01-26 05:28:14 -06:00
serial port.
2014-01-14 14:29:11 -07:00
2015-08-14 11:52:19 -06:00
Because of the way pillar works, each of the salt-proxy processes that fork off the
2014-01-16 12:39:23 -07:00
proxy minions will only see the keys specific to the proxies it will be
handling.
2014-01-16 12:39:23 -07:00
Proxies can be configured in /etc/salt/proxy or with files in /etc/salt/proxy.d as of
Salt's 2016.11.0 release.
2014-01-16 12:39:23 -07:00
Also, in general, proxy-minions are lightweight, so the machines that run them
could conceivably control a large number of devices. To run more than one proxy from
a single machine, simply start an additional proxy process with ``--proxyid``
set to the id to which you want the proxy to bind.
It is possible for the proxy services to be spread across
2014-01-16 12:39:23 -07:00
many machines if necessary, or intentionally run on machines that need to
control devices because of some physical interface (e.g. i2c and serial above).
Another reason to divide proxy services might be security. In more secure
environments only certain machines may have a network path to certain devices.
2014-01-14 14:29:11 -07:00
2015-08-06 15:43:53 -06:00
.. _proxy_connection_module:
2014-01-14 14:29:11 -07:00
2015-08-06 15:43:53 -06:00
Proxymodules
############
2014-01-14 14:29:11 -07:00
2015-08-06 15:43:53 -06:00
A proxy module encapsulates all the code necessary to interface with a device.
Proxymodules are located inside the salt.proxy module, or can be placed in
the ``_proxy`` directory in your file_roots (default is ``/srv/salt/_proxy``.
At a minimum a proxymodule object must implement the following functions:
2014-01-14 14:29:11 -07:00
2015-08-06 15:43:53 -06:00
``__virtual__()``: This function performs the same duty that it does for other
types of Salt modules. Logic goes here to determine if the module can be
loaded, checking for the presence of Python modules on which the proxy depends.
2015-08-06 15:43:53 -06:00
Returning ``False`` will prevent the module from loading.
2014-01-14 14:29:11 -07:00
2015-08-06 15:43:53 -06:00
``init(opts)``: Perform any initialization that the device needs. This is
a good place to bring up a persistent connection to a device, or authenticate
to create a persistent authorization token.
2014-01-14 14:29:11 -07:00
``initialized()``: Returns True if ``init()`` was successfully called.
2015-08-06 15:43:53 -06:00
``shutdown()``: Code to cleanly shut down or close a connection to
a controlled device goes here. This function must exist, but can contain only
the keyword ``pass`` if there is no shutdown logic required.
2014-01-15 13:00:59 -07:00
2015-08-06 15:43:53 -06:00
``ping()``: While not required, it is highly recommended that this function also
be defined in the proxymodule. The code for ``ping`` should contact the
controlled device and make sure it is really available.
2014-01-14 14:29:11 -07:00
``alive(opts)``: Another optional function, it is used together with the
``proxy_keep_alive`` option (default: ``True``). This function should
return a boolean value corresponding to the state of the connection.
If the connection is down, will try to restart (``shutdown``
followed by ``init``). The polling frequency is controlled using
the ``proxy_keep_alive_interval`` option, in minutes.
``grains()``: Rather than including grains in /srv/salt/_grains or in
the standard install directories for grains, grains can be computed and
returned by this function. This function will be called automatically
if ``proxy_merge_grains_in_module`` is set to ``True`` in /etc/salt/proxy.
This variable defaults to ``True`` in the release code-named *2017.7.0*.
2015-08-14 11:52:19 -06:00
Pre 2015.8 the proxymodule also must have an ``id()`` function. 2015.8 and following don't use
this function because the proxy's id is required on the command line.
2015-08-06 15:43:53 -06:00
Here is an example proxymodule used to interface to a *very* simple REST
server. Code for the server is in the `salt-contrib GitHub repository`_.
.. _`salt-contrib GitHub repository`: https://github.com/saltstack/salt-contrib/tree/master/proxyminion_rest_example
2014-01-14 14:29:11 -07:00
2015-08-14 11:52:19 -06:00
This proxymodule enables "service" enumeration, starting, stopping, restarting,
2015-08-06 15:43:53 -06:00
and status; "package" installation, and a ping.
2014-01-15 13:00:59 -07:00
2014-01-14 14:29:11 -07:00
.. code-block:: python
2015-08-06 15:43:53 -06:00
# -*- coding: utf-8 -*-
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
This is a simple proxy-minion designed to connect to and communicate with
the bottle-based web service contained in https://github.com/saltstack/salt-contrib/tree/master/proxyminion_rest_example
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
from __future__ import absolute_import
2014-01-14 14:29:11 -07:00
# Import python libs
import logging
2015-08-06 15:43:53 -06:00
import salt.utils.http
HAS_REST_EXAMPLE = True
# This must be present or the Salt loader won't load this module
__proxyenabled__ = ["rest_sample"]
# Variables are scoped to this module so we can have persistent data
# across calls to fns in here.
GRAINS_CACHE = {}
DETAILS = {}
# Want logging!
log = logging.getLogger(__file__)
# This does nothing, it's here just as an example and to provide a log
# entry when the module is loaded.
def __virtual__():
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Only return if all the modules are available
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
log.debug("rest_sample proxy __virtual__() called...")
return True
def _complicated_function_that_determines_if_alive():
return True
2020-06-09 09:58:34 +01:00
# Every proxy module needs an 'init', though you can
# just put DETAILS['initialized'] = True here if nothing
# else needs to be done.
2020-06-09 09:58:34 +01:00
2015-08-06 15:43:53 -06:00
def init(opts):
log.debug("rest_sample proxy init() called...")
DETAILS["initialized"] = True
2015-08-06 15:43:53 -06:00
# Save the REST URL
2015-08-06 15:43:53 -06:00
DETAILS["url"] = opts["proxy"]["url"]
2014-01-14 14:29:11 -07:00
2015-08-06 15:43:53 -06:00
# Make sure the REST URL ends with a '/'
if not DETAILS["url"].endswith("/"):
DETAILS["url"] += "/"
2020-06-09 09:58:34 +01:00
2014-01-14 14:29:11 -07:00
def alive(opts):
2020-06-09 09:58:34 +01:00
"""
This function returns a flag with the connection state.
It is very useful when the proxy minion establishes the communication
via a channel that requires a more elaborated keep-alive mechanism, e.g.
NETCONF over SSH.
2020-06-09 09:58:34 +01:00
"""
log.debug("rest_sample proxy alive() called...")
return _complicated_function_that_determines_if_alive()
2014-01-15 13:00:59 -07:00
def initialized():
2020-06-09 09:58:34 +01:00
"""
Since grains are loaded in many different places and some of those
places occur before the proxy can be initialized, return whether
our init() function has been called
2020-06-09 09:58:34 +01:00
"""
return DETAILS.get("initialized", False)
2014-01-15 13:00:59 -07:00
2015-08-06 15:43:53 -06:00
def grains():
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Get the grains from the proxied device
2020-06-09 09:58:34 +01:00
"""
if not DETAILS.get("grains_cache", {}):
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(
DETAILS["url"] + "info", decode_type="json", decode=True
)
DETAILS["grains_cache"] = r["dict"]
return DETAILS["grains_cache"]
2014-01-14 14:29:11 -07:00
2015-08-06 15:43:53 -06:00
def grains_refresh():
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Refresh the grains from the proxied device
2020-06-09 09:58:34 +01:00
"""
DETAILS["grains_cache"] = None
2015-08-06 15:43:53 -06:00
return grains()
2014-01-15 13:00:59 -07:00
2015-08-06 15:43:53 -06:00
def fns():
return {
"details": "This key is here because a function in "
"grains/rest_sample.py called fns() here in the proxymodule."
}
2015-08-06 15:43:53 -06:00
def service_start(name):
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Start a "service" on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(
DETAILS["url"] + "service/start/" + name, decode_type="json", decode=True
)
return r["dict"]
def service_stop(name):
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Stop a "service" on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(
DETAILS["url"] + "service/stop/" + name, decode_type="json", decode=True
)
return r["dict"]
def service_restart(name):
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Restart a "service" on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(
DETAILS["url"] + "service/restart/" + name, decode_type="json", decode=True
)
return r["dict"]
def service_list():
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
List "services" on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(
DETAILS["url"] + "service/list", decode_type="json", decode=True
)
return r["dict"]
def service_status(name):
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Check if a service is running on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(
DETAILS["url"] + "service/status/" + name, decode_type="json", decode=True
)
return r["dict"]
def package_list():
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
List "packages" installed on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(
DETAILS["url"] + "package/list", decode_type="json", decode=True
)
return r["dict"]
def package_install(name, **kwargs):
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Install a "package" on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
cmd = DETAILS["url"] + "package/install/" + name
if kwargs.get("version", False):
2015-08-06 15:43:53 -06:00
cmd += "/" + kwargs["version"]
else:
cmd += "/1.0"
r = salt.utils.http.query(cmd, decode_type="json", decode=True)
return r["dict"]
def fix_outage():
r = salt.utils.http.query(DETAILS["url"] + "fix_outage")
return r
def uptodate(name):
2020-06-09 09:58:34 +01:00
"""
Call the REST endpoint to see if the packages on the "server" are up to date.
2020-06-09 09:58:34 +01:00
"""
r = salt.utils.http.query(
DETAILS["url"] + "package/remove/" + name, decode_type="json", decode=True
)
return r["dict"]
2014-01-15 13:00:59 -07:00
2015-08-06 15:43:53 -06:00
def package_remove(name):
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Remove a "package" on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(
DETAILS["url"] + "package/remove/" + name, decode_type="json", decode=True
)
return r["dict"]
2014-01-15 13:00:59 -07:00
2015-08-06 15:43:53 -06:00
def package_status(name):
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Check the installation status of a package on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(
DETAILS["url"] + "package/status/" + name, decode_type="json", decode=True
)
return r["dict"]
def ping():
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
Is the REST server up?
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
r = salt.utils.http.query(DETAILS["url"] + "ping", decode_type="json", decode=True)
try:
return r["dict"].get("ret", False)
except Exception:
return False
def shutdown(opts):
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
For this proxy shutdown is a no-op
2020-06-09 09:58:34 +01:00
"""
2015-08-06 15:43:53 -06:00
log.debug("rest_sample proxy shutdown() called...")
2014-01-14 14:29:11 -07:00
2014-01-16 12:39:23 -07:00
.. _grains support code:
Grains are data about minions. Most proxied devices will have a paltry amount
2015-08-06 15:43:53 -06:00
of data as compared to a typical Linux server. By default, a proxy minion will
2015-08-14 11:52:19 -06:00
have several grains taken from the host. Salt core code requires values for ``kernel``,
``os``, and ``os_family``--all of these are forced to be ``proxy`` for proxy-minions.
2015-08-14 11:52:19 -06:00
To add others to your proxy minion for
2015-08-06 15:43:53 -06:00
a particular device, create a file in salt/grains named [proxytype].py and place
inside it the different functions that need to be run to collect the data you
are interested in. Here's an example. Note the function below called ``proxy_functions``.
It demonstrates how a grains function can take a single argument, which will be
set to the value of ``__proxy__``. Dunder variables are not yet injected into Salt processes
at the time grains are loaded, so this enables us to get a handle to the proxymodule so we
Fix various spelling mistakes in master branch (#55954) * Fix typo of additional Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of against Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of amount Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of argument Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of attempt Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of bandwidth Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of caught Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of compatibility Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of consistency Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of conversions Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of corresponding Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of dependent Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of dictionary Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of disabled Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of adapters Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of disassociates Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of changes Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of command Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of communicate Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of community Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of configuration Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of default Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of absence Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of attribute Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of container Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of described Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of existence Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of explicit Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of formatted Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of guarantees Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of hexadecimal Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of hierarchy Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of initialize Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of label Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of management Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of mismatch Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of don't Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of manually Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of getting Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of information Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of meant Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of nonexistent Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of occur Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of omitted Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of normally Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of overridden Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of repository Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of separate Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of separator Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of specific Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of successful Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of succeeded Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of support Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of version Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of that's Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of "will be removed" Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of release Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of synchronize Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of python Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of usually Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of override Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of running Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of whether Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of package Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of persist Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of preferred Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of present Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix typo of run Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix spelling mistake of "allows someone to..." "Allows to" is not correct English. It must either be "allows someone to" or "allows doing". Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix spelling mistake of "number of times" Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix spelling mistake of msgpack Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix spelling mistake of daemonized Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix spelling mistake of daemons Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix spelling mistake of extemporaneous Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix spelling mistake of instead Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com> * Fix spelling mistake of returning Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com>
2020-04-26 06:51:43 +02:00
can cross-call the functions therein used to communicate with the controlled device.
Note that as of 2016.3, grains values can also be calculated in a function called ``grains()``
in the proxymodule itself. This might be useful if a proxymodule author wants to keep
all the code for the proxy interface in the same place instead of splitting it between
the proxy and grains directories.
Use explicit unicode strings + break up salt.utils This PR is part of what will be an ongoing effort to use explicit unicode strings in Salt. Because Python 3 does not suport Python 2's raw unicode string syntax (i.e. `ur'\d+'`), we must use `salt.utils.locales.sdecode()` to ensure that the raw string is unicode. However, because of how `salt/utils/__init__.py` has evolved into the hulking monstrosity it is today, this means importing a large module in places where it is not needed, which could negatively impact performance. For this reason, this PR also breaks out some of the functions from `salt/utils/__init__.py` into new/existing modules under `salt/utils/`. The long term goal will be that the modules within this directory do not depend on importing `salt.utils`. A summary of the changes in this PR is as follows: * Moves the following functions from `salt.utils` to new locations (including a deprecation warning if invoked from `salt.utils`): `to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`, `dequote`, `is_hex`, `is_bin_str`, `rand_string`, `contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`, `which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`, `is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`, `is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`, `is_openbsd`, `is_aix` * Moves the functions already deprecated by @rallytime to the bottom of `salt/utils/__init__.py` for better organization, so we can keep the deprecated ones separate from the ones yet to be deprecated as we continue to break up `salt.utils` * Updates `salt/*.py` and all files under `salt/client/` to use explicit unicode string literals. * Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils import foo` becomes `import salt.utils.foo as foo`). * Renames the `test.rand_str` function to `test.random_hash` to more accurately reflect what it does * Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`) such that it returns a string matching the passed size. Previously this function would get `size` bytes from `os.urandom()`, base64-encode it, and return the result, which would in most cases not be equal to the passed size.
2017-07-24 20:47:15 -05:00
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*.
2015-08-06 15:43:53 -06:00
.. code: python::
# -*- coding: utf-8 -*-
'''
Generate baseline proxy minion grains
'''
from __future__ import absolute_import
import salt.utils.platform
2015-08-06 15:43:53 -06:00
__proxyenabled__ = ['rest_sample']
__virtualname__ = 'rest_sample'
def __virtual__():
try:
Use explicit unicode strings + break up salt.utils This PR is part of what will be an ongoing effort to use explicit unicode strings in Salt. Because Python 3 does not suport Python 2's raw unicode string syntax (i.e. `ur'\d+'`), we must use `salt.utils.locales.sdecode()` to ensure that the raw string is unicode. However, because of how `salt/utils/__init__.py` has evolved into the hulking monstrosity it is today, this means importing a large module in places where it is not needed, which could negatively impact performance. For this reason, this PR also breaks out some of the functions from `salt/utils/__init__.py` into new/existing modules under `salt/utils/`. The long term goal will be that the modules within this directory do not depend on importing `salt.utils`. A summary of the changes in this PR is as follows: * Moves the following functions from `salt.utils` to new locations (including a deprecation warning if invoked from `salt.utils`): `to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`, `dequote`, `is_hex`, `is_bin_str`, `rand_string`, `contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`, `which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`, `is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`, `is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`, `is_openbsd`, `is_aix` * Moves the functions already deprecated by @rallytime to the bottom of `salt/utils/__init__.py` for better organization, so we can keep the deprecated ones separate from the ones yet to be deprecated as we continue to break up `salt.utils` * Updates `salt/*.py` and all files under `salt/client/` to use explicit unicode string literals. * Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils import foo` becomes `import salt.utils.foo as foo`). * Renames the `test.rand_str` function to `test.random_hash` to more accurately reflect what it does * Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`) such that it returns a string matching the passed size. Previously this function would get `size` bytes from `os.urandom()`, base64-encode it, and return the result, which would in most cases not be equal to the passed size.
2017-07-24 20:47:15 -05:00
if salt.utils.platform.is_proxy() and __opts__['proxy']['proxytype'] == 'rest_sample':
return __virtualname__
except KeyError:
pass
return False
2015-08-06 15:43:53 -06:00
def kernel():
return {'kernel': 'proxy'}
def proxy_functions(proxy):
'''
The loader will execute functions with one argument and pass
a reference to the proxymodules LazyLoader object. However,
grains sometimes get called before the LazyLoader object is setup
so `proxy` might be None.
'''
if proxy:
return {'proxy_functions': proxy['rest_sample.fns']()}
2015-08-06 15:43:53 -06:00
def os():
return {'os': 'RestExampleOS'}
2015-08-06 15:43:53 -06:00
def location():
return {'location': 'In this darn virtual machine. Let me out!'}
2014-01-16 12:39:23 -07:00
2015-08-06 15:43:53 -06:00
def os_family():
return {'os_family': 'proxy'}
def os_data():
return {'os_data': 'funkyHttp release 1.0.a.4.g'}
2014-01-16 12:39:23 -07:00
2014-01-14 14:29:11 -07:00
The __proxyenabled__ directive
2014-01-16 12:39:23 -07:00
------------------------------
2014-01-14 14:29:11 -07:00
In previous versions of Salt the ``__proxyenabled__`` directive controlled
loading of all Salt modules for proxies (e.g. grains, execution modules, state
modules). From 2016.3 on, the only modules that respect ``__proxyenabled__``
are grains and proxy modules. These modules need to be told which proxy they
work with.
2014-01-14 14:29:11 -07:00
``__proxyenabled__`` is a list, and can contain a single '*' to indicate
a grains module works with all proxies.
2013-12-25 21:08:56 -07:00
Example from ``salt/grains/rest_sample.py``:
2013-12-25 21:08:56 -07:00
2014-01-14 14:29:11 -07:00
.. code-block:: python
2013-12-25 21:08:56 -07:00
# -*- coding: utf-8 -*-
2020-06-09 09:58:34 +01:00
"""
Generate baseline proxy minion grains
2020-06-09 09:58:34 +01:00
"""
from __future__ import absolute_import
import salt.utils.platform
2013-12-25 21:08:56 -07:00
__proxyenabled__ = ["rest_sample"]
2020-06-09 09:58:34 +01:00
__virtualname__ = "rest_sample"
2013-12-25 21:08:56 -07:00
def __virtual__():
2015-08-06 15:43:53 -06:00
try:
Use explicit unicode strings + break up salt.utils This PR is part of what will be an ongoing effort to use explicit unicode strings in Salt. Because Python 3 does not suport Python 2's raw unicode string syntax (i.e. `ur'\d+'`), we must use `salt.utils.locales.sdecode()` to ensure that the raw string is unicode. However, because of how `salt/utils/__init__.py` has evolved into the hulking monstrosity it is today, this means importing a large module in places where it is not needed, which could negatively impact performance. For this reason, this PR also breaks out some of the functions from `salt/utils/__init__.py` into new/existing modules under `salt/utils/`. The long term goal will be that the modules within this directory do not depend on importing `salt.utils`. A summary of the changes in this PR is as follows: * Moves the following functions from `salt.utils` to new locations (including a deprecation warning if invoked from `salt.utils`): `to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`, `dequote`, `is_hex`, `is_bin_str`, `rand_string`, `contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`, `which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`, `is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`, `is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`, `is_openbsd`, `is_aix` * Moves the functions already deprecated by @rallytime to the bottom of `salt/utils/__init__.py` for better organization, so we can keep the deprecated ones separate from the ones yet to be deprecated as we continue to break up `salt.utils` * Updates `salt/*.py` and all files under `salt/client/` to use explicit unicode string literals. * Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils import foo` becomes `import salt.utils.foo as foo`). * Renames the `test.rand_str` function to `test.random_hash` to more accurately reflect what it does * Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`) such that it returns a string matching the passed size. Previously this function would get `size` bytes from `os.urandom()`, base64-encode it, and return the result, which would in most cases not be equal to the passed size.
2017-07-24 20:47:15 -05:00
if (
salt.utils.platform.is_proxy()
and __opts__["proxy"]["proxytype"] == "rest_sample"
):
return __virtualname__
except KeyError:
pass
2014-01-14 16:52:09 -07:00
return False
2013-12-25 21:08:56 -07:00
.. toctree::
:maxdepth: 2
:glob:
demo
2015-10-19 13:30:35 -04:00
SSH Proxymodules
----------------
See above for a general introduction to writing proxy modules.
All of the guidelines that apply to REST are the same for SSH.
This sections specifically talks about the SSH proxy module and
explains the working of the example proxy module ``ssh_sample``.
Here is a simple example proxymodule used to interface to a device over SSH.
Code for the SSH shell is in the `salt-contrib GitHub repository`_.
2015-10-19 13:30:35 -04:00
This proxymodule enables "package" installation.
.. code-block:: python
# -*- coding: utf-8 -*-
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
This is a simple proxy-minion designed to connect to and communicate with
a server that exposes functionality via SSH.
This can be used as an option when the device does not provide
an api over HTTP and doesn't have the python stack to run a minion.
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
from __future__ import absolute_import
# Import python libs
import salt.utils.json
2015-10-19 13:30:35 -04:00
import logging
# Import Salt's libs
from salt.utils.vt_helper import SSHConnection
from salt.utils.vt import TerminalException
# This must be present or the Salt loader won't load this module
__proxyenabled__ = ["ssh_sample"]
DETAILS = {}
# Want logging!
log = logging.getLogger(__file__)
# This does nothing, it's here just as an example and to provide a log
# entry when the module is loaded.
def __virtual__():
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
Only return if all the modules are available
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
log.info("ssh_sample proxy __virtual__() called...")
return True
def init(opts):
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
Required.
Can be used to initialize the server connection.
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
try:
DETAILS["server"] = SSHConnection(
host=__opts__["proxy"]["host"],
username=__opts__["proxy"]["username"],
password=__opts__["proxy"]["password"],
)
# connected to the SSH server
out, err = DETAILS["server"].sendline("help")
except TerminalException as e:
log.error(e)
return False
def shutdown(opts):
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
Disconnect
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
DETAILS["server"].close_connection()
def parse(out):
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
Extract json from out.
Parameter
out: Type string. The data returned by the
ssh command.
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
jsonret = []
in_json = False
for ln_ in out.split("\n"):
if "{" in ln_:
in_json = True
if in_json:
jsonret.append(ln_)
if "}" in ln_:
in_json = False
return salt.utils.json.loads("\n".join(jsonret))
2015-10-19 13:30:35 -04:00
def package_list():
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
List "packages" by executing a command via ssh
This function is called in response to the salt command
.. code-block:: bash
2015-10-19 13:30:35 -04:00
salt target_minion pkg.list_pkgs
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
# Send the command to execute
out, err = DETAILS["server"].sendline("pkg_list")
# "scrape" the output and return the right fields as a dict
return parse(out)
def package_install(name, **kwargs):
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
Install a "package" on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
cmd = "pkg_install " + name
if "version" in kwargs:
cmd += "/" + kwargs["version"]
else:
cmd += "/1.0"
# Send the command to execute
out, err = DETAILS["server"].sendline(cmd)
# "scrape" the output and return the right fields as a dict
return parse(out)
def package_remove(name):
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
Remove a "package" on the REST server
2020-06-09 09:58:34 +01:00
"""
2015-10-19 13:30:35 -04:00
cmd = "pkg_remove " + name
# Send the command to execute
out, err = DETAILS["server"].sendline(cmd)
# "scrape" the output and return the right fields as a dict
return parse(out)
2015-10-19 13:30:35 -04:00
Connection Setup
################
The ``init()`` method is responsible for connection setup. It uses the ``host``, ``username`` and ``password`` config variables defined in the pillar data. The ``prompt`` kwarg can be passed to ``SSHConnection`` if your SSH server's prompt differs from the example's prompt ``(Cmd)``. Instantiating the ``SSHConnection`` class establishes an SSH connection to the ssh server (using Salt VT).
Command execution
#################
The ``package_*`` methods use the SSH connection (established in ``init()``) to send commands out to the SSH server. The ``sendline()`` method of ``SSHConnection`` class can be used to send commands out to the server. In the above example we send commands like ``pkg_list`` or ``pkg_install``. You can send any SSH command via this utility.
Output parsing
##############
Output returned by ``sendline()`` is a tuple of strings representing the stdout and the stderr respectively. In the toy example shown we simply scrape the output and convert it to a python dictionary, as shown in the ``parse`` method. You can tailor this method to match your parsing logic.
Connection teardown
###################
The ``shutdown`` method is responsible for calling the ``close_connection()`` method of ``SSHConnection`` class. This ends the SSH connection to the server.
For more information please refer to class `SSHConnection`_.
.. toctree::
:maxdepth: 2
:glob:
ssh
beacon
state
../tutorials/esxi_proxy_minion
2015-10-19 13:30:35 -04:00
.. _SSHConnection: https://github.com/saltstack/salt/blob/b8271c7512da7e048019ee26422be9e7d6b795ab/salt/utils/vt_helper.py#L28