mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 00:55:19 +00:00
Merge remote-tracking branch 'upstream/2015.5' into merge-forward-2015.8
Conflicts: doc/topics/cloud/vmware.rst salt/cloud/__init__.py salt/cloud/clouds/vmware.py salt/loader.py salt/minion.py salt/modules/archive.py salt/modules/file.py salt/states/pkg.py salt/utils/http.py
This commit is contained in:
commit
0fc16040d6
@ -224,6 +224,11 @@ rst_prolog = """\
|
||||
.. _`salt-users`: https://groups.google.com/forum/#!forum/salt-users
|
||||
.. _`salt-announce`: https://groups.google.com/forum/#!forum/salt-announce
|
||||
.. _`salt-packagers`: https://groups.google.com/forum/#!forum/salt-packagers
|
||||
.. |windownload| raw:: html
|
||||
|
||||
<a href="https://repo.saltstack.com/windows/Salt-Minion-{release}-2-x86-Setup.exe"><strong>Salt-Minion-{release}-2-x86-Setup.exe</strong></a>
|
||||
| <a href="https://repo.saltstack.com/windows/Salt-Minion-{release}-2-x86-Setup.exe.md5"><strong>md5</strong></a>
|
||||
|
||||
""".format(release=release)
|
||||
|
||||
# A shortcut for linking to tickets on the GitHub issue tracker
|
||||
|
@ -18,139 +18,16 @@ Windows Installer
|
||||
Salt Minion Windows installers can be found here. The output of `md5sum <salt
|
||||
minion exe>` should match the contents of the corresponding md5 file.
|
||||
|
||||
.. admonition:: Download here
|
||||
**Latest stable build from the selected branch**:
|
||||
|windownload|
|
||||
|
||||
* 2015.5.2
|
||||
* `Salt-Minion-2015.5.2-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.2-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.2-x86-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2015.5.2-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.2-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.2-AMD64-Setup.exe.md5>`__
|
||||
`Earlier builds from supported branches <https://repo.saltstack.com/windows/>`__
|
||||
|
||||
* 2015.5.1-3
|
||||
* `Salt-Minion-2015.5.1-3-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.1-3-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.1-3-x86-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2015.5.1-3-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.1-3-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.1-3-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2015.5.0-2
|
||||
* `Salt-Minion-2015.5.0-2-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.0-2-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.0-2-x86-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2015.5.0-2-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.0-2-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2015.5.0-2-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.7.5-2
|
||||
* `Salt-Minion-2014.7.5-2-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.5-2-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.5-2-x86-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.7.5-2-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.5-2-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.5-2-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.7.4
|
||||
* `Salt-Minion-2014.7.4-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-x86-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.7.4-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.7.2
|
||||
* `Salt-Minion-2014.7.2-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.2-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.2-x86-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.7.2-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.2-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.2-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.7.1
|
||||
* `Salt-Minion-2014.7.1-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.1-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.1-x86-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.7.1-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.1-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.1-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.7.0
|
||||
* Salt-Minion-2014.7.0-1-win32-Setup.exe | md5
|
||||
* Salt-Minion-2014.7.0-AMD64-Setup.exe | md5
|
||||
.. note::
|
||||
|
||||
The 2014.7.0 installers have been removed because of a regression. Please use the 2014.7.1 release instead.
|
||||
|
||||
* 2014.1.13
|
||||
* `Salt-Minion-2014.1.13-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.1.13-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.1.13-x86-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.13-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.1.13-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.1.13-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.1.11
|
||||
* `Salt-Minion-2014.1.11-win32-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.11-win32-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.11-win32-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.11-AMD64-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.11-AMD64-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.11-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.1.10
|
||||
* `Salt-Minion-2014.1.10-win32-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.10-win32-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.10-win32-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.10-AMD64-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.10-AMD64-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.10-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.1.7
|
||||
* `Salt-Minion-2014.1.7-win32-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.7-win32-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.7-win32-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.7-AMD64-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.7-AMD64-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.7-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.1.5
|
||||
* `Salt-Minion-2014.1.5-win32-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.5-win32-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.5-win32-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.5-AMD64-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.5-AMD64-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.5-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.1.4
|
||||
* `Salt-Minion-2014.1.4-win32-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.4-win32-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.4-win32-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.4-AMD64-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.4-AMD64-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.4-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.1.3-1 (packaging bugfix)
|
||||
* `Salt-Minion-2014.1.3-1-win32-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.3-1-win32-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.3-1-win32-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.3-1-AMD64-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.3-1-AMD64-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.3-1-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.1.3
|
||||
* `Salt-Minion-2014.1.3-win32-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.3-win32-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.3-win32-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.3-AMD64-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.3-AMD64-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.3-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 2014.1.1
|
||||
* `Salt-Minion-2014.1.1-win32-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.1-win32-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.1-win32-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.1-AMD64-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.1-AMD64-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.1-AMD64-Setup.exe.md5>`__
|
||||
|
||||
|
||||
* 2014.1.0
|
||||
* `Salt-Minion-2014.1.0-win32-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.0-win32-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.0-win32-Setup.exe.md5>`__
|
||||
* `Salt-Minion-2014.1.0-AMD64-Setup.exe <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.0-AMD64-Setup.exe>`__ | `md5 <https://docs.saltstack.com/downloads/Salt-Minion-2014.1.0-AMD64-Setup.exe.md5>`__
|
||||
|
||||
* 0.17.5-2 (bugfix release)
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.5-2-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.5-2-AMD64-Setup.exe
|
||||
|
||||
* 0.17.5
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.5-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.5-AMD64-Setup.exe
|
||||
|
||||
* 0.17.4
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.4-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.4-AMD64-Setup.exe
|
||||
|
||||
* 0.17.2
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.2-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.2-AMD64-Setup.exe
|
||||
|
||||
* 0.17.1.1 - Windows Installer bugfix release
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.1.1-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.1.1-AMD64-Setup.exe
|
||||
|
||||
* 0.17.1
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.1-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.1-AMD64-Setup.exe
|
||||
|
||||
* 0.17.0
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.0-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.17.0-AMD64-Setup.exe
|
||||
|
||||
* 0.16.3
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.16.3-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.16.3-AMD64-Setup.exe
|
||||
|
||||
* 0.16.2
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.16.2-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.16.2-AMD64-Setup.exe
|
||||
|
||||
* 0.16.0
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.16.0-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.16.0-AMD64-Setup.exe
|
||||
|
||||
* 0.15.3
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.15.3-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.15.3-AMD64-Setup.exe
|
||||
|
||||
* 0.14.1
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.14.1-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.14.1-AMD64-Setup.exe
|
||||
|
||||
* 0.14.0
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.14.0-win32-Setup.exe
|
||||
* https://docs.saltstack.com/downloads/Salt-Minion-0.14.0-AMD64-Setup.exe
|
||||
`Archived builds from unsupported branches <https://repo.saltstack.com/archive/>`__
|
||||
|
||||
.. note::
|
||||
|
||||
The executables above will install dependencies that the Salt minion
|
||||
The installation executable installs dependencies that the Salt minion
|
||||
requires.
|
||||
|
||||
The 64bit installer has been tested on Windows 7 64bit and Windows Server
|
||||
|
@ -39,7 +39,7 @@ any way with the minion that started it.
|
||||
|
||||
To create support for a proxied device one needs to create four things:
|
||||
|
||||
1. The `proxytype connection class`_ (located in salt/proxy).
|
||||
1. The `proxy_connection_module`_ (located in salt/proxy).
|
||||
2. The `grains support code`_ (located in salt/grains).
|
||||
3. :ref:`Salt modules <all-salt.modules>` specific to the controlled
|
||||
device.
|
||||
@ -156,118 +156,289 @@ to control a particular device. That proxy-minion process will initiate
|
||||
a connection back to the master to enable control.
|
||||
|
||||
|
||||
.. _proxytype connection class:
|
||||
.. _proxy_connection_module:
|
||||
|
||||
Proxytypes
|
||||
##########
|
||||
Proxymodules
|
||||
############
|
||||
|
||||
A proxytype is a Python class called 'Proxyconn' that encapsulates all the code
|
||||
necessary to interface with a device. Proxytypes are located inside the
|
||||
salt.proxy module. At a minimum a proxytype object must implement the
|
||||
following methods:
|
||||
A proxy module encapsulates all the code necessary to interface with a device.
|
||||
Proxymodules are located inside the salt.proxy module. At a minimum
|
||||
a proxymodule object must implement the following functions:
|
||||
|
||||
``proxytype(self)``: Returns a string with the name of the proxy type.
|
||||
``__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 deepends.
|
||||
Returning ``False`` will prevent the module from loading.
|
||||
|
||||
``proxyconn(self, **kwargs)``: Provides the primary way to connect and communicate
|
||||
with the device. Some proxyconns instantiate a particular object that opens a
|
||||
network connection to a device and leaves the connection open for communication.
|
||||
Others simply abstract a serial connection or even implement endpoints to communicate
|
||||
via REST over HTTP.
|
||||
``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.
|
||||
|
||||
``id(self, opts)``: Returns a unique, unchanging id for the controlled device. This is
|
||||
``id(opts)``: Returns a unique, unchanging id for the controlled device. This is
|
||||
the "name" of the device, and is used by the salt-master for targeting and key
|
||||
authentication.
|
||||
|
||||
Optionally, the class may define a ``shutdown(self, opts)`` method if the
|
||||
controlled device should be informed when the minion goes away cleanly.
|
||||
``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.
|
||||
|
||||
It is highly recommended that the ``test.ping`` execution module also be defined
|
||||
for a proxytype. The code for ``ping`` should contact the controlled device and make
|
||||
sure it is really available.
|
||||
``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.
|
||||
|
||||
Here is an example proxytype used to interface to Juniper Networks devices that run
|
||||
the Junos operating system. Note the additional library requirements--most of the
|
||||
"hard part" of talking to these devices is handled by the jnpr.junos, jnpr.junos.utils,
|
||||
and jnpr.junos.cfg modules.
|
||||
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 <https://github.com/saltstack/salt-contrib/proxyminion_rest_example>`_
|
||||
|
||||
This proxymodule enables "service" enumration, starting, stopping, restarting,
|
||||
and status; "package" installation, and a ping.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
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/proxyminion_rest_example
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import python libs
|
||||
import logging
|
||||
import os
|
||||
import salt.utils.http
|
||||
|
||||
import jnpr.junos
|
||||
import jnpr.junos.utils
|
||||
import jnpr.junos.cfg
|
||||
HAS_JUNOS = True
|
||||
HAS_REST_EXAMPLE = True
|
||||
|
||||
class Proxyconn(object):
|
||||
# This must be present or the Salt loader won't load this module
|
||||
__proxyenabled__ = ['rest_sample']
|
||||
|
||||
|
||||
def __init__(self, details):
|
||||
self.conn = jnpr.junos.Device(user=details['username'], host=details['host'], password=details['passwd'])
|
||||
self.conn.open()
|
||||
self.conn.bind(cu=jnpr.junos.cfg.Resource)
|
||||
# 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__)
|
||||
|
||||
|
||||
def proxytype(self):
|
||||
return 'junos'
|
||||
# This does nothing, it's here just as an example and to provide a log
|
||||
# entry when the module is loaded.
|
||||
def __virtual__():
|
||||
'''
|
||||
Only return if all the modules are available
|
||||
'''
|
||||
log.debug('rest_sample proxy __virtual__() called...')
|
||||
return True
|
||||
|
||||
# Every proxy module needs an 'init', though you can
|
||||
# just put a 'pass' here if it doesn't need to do anything.
|
||||
def init(opts):
|
||||
log.debug('rest_sample proxy init() called...')
|
||||
|
||||
# Save the REST URL
|
||||
DETAILS['url'] = opts['proxy']['url']
|
||||
|
||||
# Make sure the REST URL ends with a '/'
|
||||
if not DETAILS['url'].endswith('/'):
|
||||
DETAILS['url'] += '/'
|
||||
|
||||
|
||||
def id(self, opts):
|
||||
return self.conn.facts['hostname']
|
||||
def id(opts):
|
||||
'''
|
||||
Return a unique ID for this proxy minion. This ID MUST NOT CHANGE.
|
||||
If it changes while the proxy is running the salt-master will get
|
||||
really confused and may stop talking to this minion
|
||||
'''
|
||||
r = salt.utils.http.query(opts['proxy']['url']+'id', decode_type='json', decode=True)
|
||||
return r['dict']['id'].encode('ascii', 'ignore')
|
||||
|
||||
|
||||
def ping(self):
|
||||
return self.conn.connected
|
||||
def grains():
|
||||
'''
|
||||
Get the grains from the proxied device
|
||||
'''
|
||||
if not GRAINS_CACHE:
|
||||
r = salt.utils.http.query(DETAILS['url']+'info', decode_type='json', decode=True)
|
||||
GRAINS_CACHE = r['dict']
|
||||
return GRAINS_CACHE
|
||||
|
||||
|
||||
def shutdown(self, opts):
|
||||
def grains_refresh():
|
||||
'''
|
||||
Refresh the grains from the proxied device
|
||||
'''
|
||||
GRAINS_CACHE = {}
|
||||
return grains()
|
||||
|
||||
print('Proxy module {} shutting down!!'.format(opts['id']))
|
||||
try:
|
||||
self.conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def service_start(name):
|
||||
'''
|
||||
Start a "service" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/start/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def service_stop(name):
|
||||
'''
|
||||
Stop a "service" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/stop/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def service_restart(name):
|
||||
'''
|
||||
Restart a "service" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/restart/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def service_list():
|
||||
'''
|
||||
List "services" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/list', decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def service_status(name):
|
||||
'''
|
||||
Check if a service is running on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/status/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def package_list():
|
||||
'''
|
||||
List "packages" installed on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'package/list', decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def package_install(name, **kwargs):
|
||||
'''
|
||||
Install a "package" on the REST server
|
||||
'''
|
||||
cmd = DETAILS['url']+'package/install/'+name
|
||||
if 'version' in kwargs:
|
||||
cmd += '/'+kwargs['version']
|
||||
else:
|
||||
cmd += '/1.0'
|
||||
r = salt.utils.http.query(cmd, decode_type='json', decode=True)
|
||||
|
||||
|
||||
def package_remove(name):
|
||||
|
||||
'''
|
||||
Remove a "package" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'package/remove/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def package_status(name):
|
||||
'''
|
||||
Check the installation status of a package on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'package/status/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def ping():
|
||||
'''
|
||||
Is the REST server up?
|
||||
'''
|
||||
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):
|
||||
'''
|
||||
For this proxy shutdown is a no-op
|
||||
'''
|
||||
log.debug('rest_sample proxy shutdown() called...')
|
||||
pass
|
||||
|
||||
|
||||
.. _grains support code:
|
||||
|
||||
Grains are data about minions. Most proxied devices will have a paltry amount
|
||||
of data as compared to a typical Linux server. Because proxy-minions are
|
||||
started by a regular minion, they inherit a sizeable number of grain settings
|
||||
which can be useful, especially when targeting (PYTHONPATH, for example).
|
||||
of data as compared to a typical Linux server. By default, a proxy minion will
|
||||
have no grains set at all. Salt core code requires values for ``kernel``,
|
||||
``os``, and ``os_family``. To add them (and others) to your proxy minion for
|
||||
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:
|
||||
|
||||
All proxy minions set a grain called 'proxy'. If it is present, you know the
|
||||
minion is controlling another device. To add more grains to your proxy minion
|
||||
for 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:
|
||||
|
||||
.. code: python::
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Generate baseline proxy minion grains
|
||||
'''
|
||||
__proxyenabled__ = ['rest_sample']
|
||||
|
||||
__virtualname__ = 'rest_sample'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
if 'proxy' not in __opts__:
|
||||
return False
|
||||
else:
|
||||
return __virtualname__
|
||||
|
||||
def kernel():
|
||||
return {'kernel':'proxy'}
|
||||
|
||||
def os():
|
||||
return {'os':'proxy'}
|
||||
|
||||
def location():
|
||||
return {'location': 'In this darn virtual machine. Let me out!'}
|
||||
|
||||
|
||||
def os_family():
|
||||
return {'os_family': 'proxy'}
|
||||
|
||||
|
||||
def os_data():
|
||||
return {'os_data': 'funkyHttp release 1.0.a.4.g'}
|
||||
|
||||
|
||||
The __proxyenabled__ directive
|
||||
------------------------------
|
||||
|
||||
Salt states and execution modules, by, and large, cannot "automatically" work
|
||||
Salt execution moduless, by, and large, cannot "automatically" work
|
||||
with proxied devices. Execution modules like ``pkg`` or ``sqlite3`` have no
|
||||
meaning on a network switch or a housecat. For a state/execution module to be
|
||||
meaning on a network switch or a housecat. For an execution module to be
|
||||
available to a proxy-minion, the ``__proxyenabled__`` variable must be defined
|
||||
in the module as an array containing the names of all the proxytypes that this
|
||||
module can support. The array can contain the special value ``*`` to indicate
|
||||
that the module supports all proxies.
|
||||
|
||||
If no ``__proxyenabled__`` variable is defined, then by default, the
|
||||
state/execution module is unavailable to any proxy.
|
||||
execution module is unavailable to any proxy.
|
||||
|
||||
Here is an excerpt from a module that was modified to support proxy-minions:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
__proxyenabled__ = ['*']
|
||||
|
||||
[...]
|
||||
|
||||
def ping():
|
||||
|
||||
if 'proxyobject' in __opts__:
|
||||
if 'proxymodule' in __opts__:
|
||||
if 'ping' in __opts__['proxyobject'].__attr__():
|
||||
return __opts['proxyobject'].ping()
|
||||
else:
|
||||
@ -275,15 +446,18 @@ Here is an excerpt from a module that was modified to support proxy-minions:
|
||||
else:
|
||||
return True
|
||||
|
||||
And then in salt.proxy.junos we find
|
||||
And then in salt.proxy.rest_sample.py we find
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def ping(self):
|
||||
|
||||
return self.connected
|
||||
def ping():
|
||||
'''
|
||||
Is the REST server up?
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'ping', decode_type='json', decode=True)
|
||||
try:
|
||||
return r['dict'].get('ret', False)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
The Junos API layer lacks the ability to do a traditional 'ping', so the
|
||||
example simply checks the connection object field that indicates
|
||||
if the ssh connection was successfully made to the device.
|
||||
|
@ -777,7 +777,7 @@ repository:
|
||||
- git: master https://domain.com/pillar.git root=subdirectory
|
||||
|
||||
More information on the git external pillar can be found in the
|
||||
:mod:`salt.pillar.get_pillar docs <salt.pillar.git_pillar>`.
|
||||
:mod:`salt.pillar.git_pillar docs <salt.pillar.git_pillar>`.
|
||||
|
||||
|
||||
.. _faq-gitfs-bug:
|
||||
|
@ -41,7 +41,12 @@ def __define_global_system_encoding_variable__():
|
||||
# encoding. MS Windows has problems with this and reports the wrong
|
||||
# encoding
|
||||
import locale
|
||||
encoding = locale.getdefaultlocale()[-1]
|
||||
try:
|
||||
encoding = locale.getdefaultlocale()[-1]
|
||||
except ValueError:
|
||||
# A bad locale setting was most likely found:
|
||||
# https://github.com/saltstack/salt/issues/26063
|
||||
pass
|
||||
|
||||
# This is now garbage collectable
|
||||
del locale
|
||||
|
@ -417,8 +417,9 @@ class ProxyMinion(parsers.MinionOptionParser): # pylint: disable=no-init
|
||||
'''
|
||||
If sub-classed, run any shutdown operations on this method.
|
||||
'''
|
||||
if 'proxy' in self.minion.opts:
|
||||
self.minion.opts['proxyobject'].shutdown(self.minion.opts)
|
||||
if 'proxymodule' in self.minion.opts:
|
||||
proxy_fn = self.minion.opts['proxymodule'].loaded_base_name + '.shutdown'
|
||||
self.minion.opts['proxymodule'][proxy_fn](self.minion.opts)
|
||||
logger.info('The proxy minion is shut down')
|
||||
|
||||
|
||||
|
@ -2129,7 +2129,9 @@ class Map(Cloud):
|
||||
output[name] = self.create(
|
||||
profile, local_master=local_master
|
||||
)
|
||||
if self.opts.get('show_deploy_args', False) is False and 'deploy_kwargs' in output:
|
||||
if self.opts.get('show_deploy_args', False) is False \
|
||||
and 'deploy_kwargs' in output \
|
||||
and isinstance(output[name], dict):
|
||||
output[name].pop('deploy_kwargs', None)
|
||||
except SaltCloudException as exc:
|
||||
log.error(
|
||||
|
@ -630,10 +630,10 @@ def _get_file_from_s3(metadata, saltenv, bucket_name, path, cached_file_path):
|
||||
for header_name, header_value in ret['headers'].items():
|
||||
name = header_name.strip()
|
||||
value = header_value.strip()
|
||||
if name == 'Last-Modified'.lower():
|
||||
if str(name).lower() == 'last-modified':
|
||||
s3_file_mtime = datetime.datetime.strptime(
|
||||
value, '%a, %d %b %Y %H:%M:%S %Z')
|
||||
elif name == 'Content-Length'.lower():
|
||||
elif str(name).lower() == 'content-length':
|
||||
s3_file_size = int(value)
|
||||
if (cached_file_size == s3_file_size and
|
||||
cached_file_mtime > s3_file_mtime):
|
||||
|
@ -5,10 +5,14 @@ NOTE this is a little complicated--junos can only be accessed via salt-proxy-min
|
||||
Thus, some grains make sense to get them from the minion (PYTHONPATH), but others
|
||||
don't (ip_interfaces)
|
||||
'''
|
||||
import logging
|
||||
|
||||
__proxyenabled__ = ['junos']
|
||||
|
||||
__virtualname__ = 'junos'
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __virtual__():
|
||||
if 'proxy' not in __opts__:
|
||||
@ -17,16 +21,31 @@ def __virtual__():
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def location():
|
||||
return {'location': 'dc-1-europe'}
|
||||
def _remove_complex_types(dictionary):
|
||||
'''
|
||||
Linode-python is now returning some complex types that
|
||||
are not serializable by msgpack. Kill those.
|
||||
'''
|
||||
|
||||
for k, v in dictionary.iteritems():
|
||||
if isinstance(v, dict):
|
||||
dictionary[k] = _remove_complex_types(v)
|
||||
elif hasattr(v, 'to_eng_string'):
|
||||
dictionary[k] = v.to_eng_string()
|
||||
|
||||
return dictionary
|
||||
|
||||
|
||||
def defaults():
|
||||
return {'os': 'proxy', 'kernel': 'unknown', 'osrelease': 'proxy'}
|
||||
|
||||
|
||||
def facts():
|
||||
log.debug('----------- Trying to get facts')
|
||||
facts = __opts__['proxymodule']['junos.facts']()
|
||||
facts['version_info'] = 'override'
|
||||
return facts
|
||||
|
||||
|
||||
def os_family():
|
||||
return {'os_family': 'junos'}
|
||||
|
||||
|
||||
def os_data():
|
||||
facts = {}
|
||||
facts['version_info'] = {'major': '12,1', 'type': 'I', 'minor': '20131108_srx_12q1_x46_intgr', 'build': '0-613414'}
|
||||
facts['os_family'] = 'proxy'
|
||||
return facts
|
||||
|
@ -14,6 +14,14 @@ def __virtual__():
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def kernel():
|
||||
return {'kernel': 'proxy'}
|
||||
|
||||
|
||||
def os():
|
||||
return {'os': 'proxy'}
|
||||
|
||||
|
||||
def location():
|
||||
return {'location': 'In this darn virtual machine. Let me out!'}
|
||||
|
||||
@ -23,4 +31,4 @@ def os_family():
|
||||
|
||||
|
||||
def os_data():
|
||||
return __opts__['proxyobject'].grains()
|
||||
return {'os_data': 'funkyHttp release 1.0.a.4.g'}
|
||||
|
@ -248,7 +248,7 @@ def engines(opts, functions, runners):
|
||||
pack=pack)
|
||||
|
||||
|
||||
def proxy(opts, functions, whitelist=None):
|
||||
def proxy(opts, functions, whitelist=None, loaded_base_name=None):
|
||||
'''
|
||||
Returns the proxy module for this salt-proxy-minion
|
||||
'''
|
||||
@ -256,7 +256,8 @@ def proxy(opts, functions, whitelist=None):
|
||||
opts,
|
||||
tag='proxy',
|
||||
whitelist=whitelist,
|
||||
pack={'__proxy__': functions})
|
||||
pack={'__proxy__': functions},
|
||||
loaded_base_name=loaded_base_name)
|
||||
|
||||
|
||||
def returners(opts, functions, whitelist=None, context=None):
|
||||
@ -1138,14 +1139,17 @@ class LazyLoader(salt.utils.lazy.LazyDict):
|
||||
# If this is a proxy minion then MOST modules cannot work. Therefore, require that
|
||||
# any module that does work with salt-proxy-minion define __proxyenabled__ as a list
|
||||
# containing the names of the proxy types that the module supports.
|
||||
if not hasattr(mod, 'render') and 'proxy' in self.opts:
|
||||
if not hasattr(mod, '__proxyenabled__') or \
|
||||
self.opts['proxy']['proxytype'] in mod.__proxyenabled__ or \
|
||||
'*' in mod.__proxyenabled__:
|
||||
err_string = 'not a proxy_minion enabled module'
|
||||
self.missing_modules[module_name] = err_string
|
||||
self.missing_modules[name] = err_string
|
||||
return False
|
||||
#
|
||||
# Render modules and state modules are OK though
|
||||
if 'proxy' in self.opts:
|
||||
if self.tag not in ['render', 'states']:
|
||||
if not hasattr(mod, '__proxyenabled__') or \
|
||||
(self.opts['proxy']['proxytype'] not in mod.__proxyenabled__ and
|
||||
'*' not in mod.__proxyenabled__):
|
||||
err_string = 'not a proxy_minion enabled module'
|
||||
self.missing_modules[module_name] = err_string
|
||||
self.missing_modules[name] = err_string
|
||||
return False
|
||||
|
||||
if getattr(mod, '__load__', False) is not False:
|
||||
log.info(
|
||||
|
@ -89,6 +89,8 @@ import salt.utils.schedule
|
||||
import salt.utils.error
|
||||
import salt.utils.zeromq
|
||||
import salt.defaults.exitcodes
|
||||
import salt.cli.daemons
|
||||
|
||||
from salt.defaults import DEFAULT_TARGET_DELIM
|
||||
from salt.utils.debug import enable_sigusr1_handler
|
||||
from salt.utils.event import tagify
|
||||
@ -384,6 +386,7 @@ class SMinion(object):
|
||||
self.utils = salt.loader.utils(self.opts)
|
||||
self.functions = salt.loader.minion_mods(self.opts, utils=self.utils,
|
||||
include_errors=True)
|
||||
self.proxy = salt.loader.proxy(self.opts, None)
|
||||
# TODO: remove
|
||||
self.function_errors = {} # Keep the funcs clean
|
||||
self.returners = salt.loader.returners(self.opts, self.functions)
|
||||
@ -674,22 +677,22 @@ class Minion(MinionBase):
|
||||
self.grains_cache = self.opts['grains']
|
||||
|
||||
if 'proxy' in self.opts['pillar']:
|
||||
log.debug('I am {0} and I need to start some proxies for {1}'.format(self.opts['id'],
|
||||
self.opts['pillar']['proxy']))
|
||||
log.info('I am {0} and I need to start some proxies for {1}'.format(self.opts['id'],
|
||||
self.opts['pillar']['proxy'].keys()))
|
||||
for p in self.opts['pillar']['proxy']:
|
||||
log.debug('Starting {0} proxy.'.format(p))
|
||||
log.info('Starting {0} proxy.'.format(p))
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
reinit_crypto()
|
||||
continue
|
||||
else:
|
||||
reinit_crypto()
|
||||
proxyminion = ProxyMinion(self.opts)
|
||||
proxyminion = salt.cli.daemons.ProxyMinion(self.opts)
|
||||
proxyminion.start(self.opts['pillar']['proxy'][p])
|
||||
self.clean_die(signal.SIGTERM, None)
|
||||
else:
|
||||
log.debug('I am {0} and I am not supposed to start any proxies. '
|
||||
'(Likely not a problem)'.format(self.opts['id']))
|
||||
log.info('I am {0} and I am not supposed to start any proxies. '
|
||||
'(Likely not a problem)'.format(self.opts['id']))
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def eval_master(self,
|
||||
@ -2480,12 +2483,14 @@ class ProxyMinion(Minion):
|
||||
This class instantiates a 'proxy' minion--a minion that does not manipulate
|
||||
the host it runs on, but instead manipulates a device that cannot run a minion.
|
||||
'''
|
||||
def __init__(self, opts, timeout=60, safe=True): # pylint: disable=W0231
|
||||
def __init__(self, opts, timeout=60, safe=True, loaded_base_name=None): # pylint: disable=W0231
|
||||
'''
|
||||
Pass in the options dict
|
||||
'''
|
||||
|
||||
self._running = None
|
||||
self.win_proc = []
|
||||
self.loaded_base_name = loaded_base_name
|
||||
|
||||
# Warn if ZMQ < 3.2
|
||||
if HAS_ZMQ:
|
||||
try:
|
||||
@ -2505,11 +2510,19 @@ class ProxyMinion(Minion):
|
||||
)
|
||||
# Late setup the of the opts grains, so we can log from the grains
|
||||
# module
|
||||
# print opts['proxymodule']
|
||||
fq_proxyname = 'proxy.'+opts['proxy']['proxytype']
|
||||
self.proxymodule = salt.loader.proxy(opts, fq_proxyname)
|
||||
opts['proxyobject'] = self.proxymodule[opts['proxy']['proxytype']+'.Proxyconn'](opts['proxy'])
|
||||
opts['id'] = opts['proxyobject'].id(opts)
|
||||
opts['master'] = self.eval_master(opts,
|
||||
timeout,
|
||||
safe)
|
||||
fq_proxyname = opts['proxy']['proxytype']
|
||||
# Need to match the function signature of the other loader fns
|
||||
# which is def proxy(opts, functions, whitelist=None, loaded_base_name=None)
|
||||
# 'functions' for other loaders is a LazyLoader object
|
||||
# but since we are not needing to merge functions into another fn dictionary
|
||||
# we will pass 'None' in
|
||||
self.proxymodule = salt.loader.proxy(opts, None, loaded_base_name=fq_proxyname)
|
||||
opts['proxymodule'] = self.proxymodule
|
||||
opts['grains'] = salt.loader.grains(opts)
|
||||
opts['id'] = opts['proxymodule'][fq_proxyname+'.id'](opts)
|
||||
opts.update(resolve_dns(opts))
|
||||
self.opts = opts
|
||||
self.opts['pillar'] = salt.pillar.get_pillar(
|
||||
@ -2519,6 +2532,7 @@ class ProxyMinion(Minion):
|
||||
opts['environment'],
|
||||
pillarenv=opts.get('pillarenv'),
|
||||
).compile_pillar()
|
||||
opts['proxymodule'][fq_proxyname+'.init'](opts)
|
||||
self.functions, self.returners, self.function_errors = self._load_modules()
|
||||
self.serial = salt.payload.Serial(self.opts)
|
||||
self.mod_opts = self._prep_mod_opts()
|
||||
@ -2529,7 +2543,26 @@ class ProxyMinion(Minion):
|
||||
self.opts,
|
||||
self.functions,
|
||||
self.returners)
|
||||
|
||||
# add default scheduling jobs to the minions scheduler
|
||||
if 'mine.update' in self.functions:
|
||||
log.info('Added mine.update to scheduler')
|
||||
self.schedule.add_job({
|
||||
'__mine_interval':
|
||||
{
|
||||
'function': 'mine.update',
|
||||
'minutes': opts['mine_interval'],
|
||||
'jid_include': True,
|
||||
'maxrunning': 2
|
||||
}
|
||||
})
|
||||
|
||||
self.grains_cache = self.opts['grains']
|
||||
|
||||
# store your hexid to subscribe to zmq, hash since zmq filters are prefix
|
||||
# matches this way we can avoid collisions
|
||||
self.hexid = hashlib.sha1(self.opts['id']).hexdigest()
|
||||
|
||||
# self._running = True
|
||||
|
||||
def _prep_mod_opts(self):
|
||||
|
@ -772,7 +772,8 @@ def version(name, check_remote=False, source=None, pre_versions=False):
|
||||
log.error(err)
|
||||
raise CommandExecutionError(err)
|
||||
|
||||
if _LooseVersion(chocolatey_version()) >= _LooseVersion('0.9.9'):
|
||||
use_list = _LooseVersion(chocolatey_version()) >= _LooseVersion('0.9.9')
|
||||
if use_list:
|
||||
choco_cmd = "list"
|
||||
else:
|
||||
choco_cmd = "version"
|
||||
@ -794,18 +795,22 @@ def version(name, check_remote=False, source=None, pre_versions=False):
|
||||
|
||||
ret = {}
|
||||
|
||||
res = result['stdout'].split('\n')
|
||||
if use_list:
|
||||
res = res[:-1]
|
||||
|
||||
# the next bit is to deal with the stupid default PowerShell formatting.
|
||||
# printing two value pairs is shown in columns, whereas printing six
|
||||
# pairs is shown in rows...
|
||||
if not salt.utils.is_true(check_remote):
|
||||
ver_re = re.compile(r'(\S+)\s+(.+)')
|
||||
for line in result['stdout'].split('\n')[:-1]:
|
||||
for line in res:
|
||||
for name, ver in ver_re.findall(line):
|
||||
ret['name'] = name
|
||||
ret['found'] = ver
|
||||
else:
|
||||
ver_re = re.compile(r'(\S+)\s+:\s*(.*)')
|
||||
for line in result['stdout'].split('\n')[:-1]:
|
||||
for line in res:
|
||||
for key, value in ver_re.findall(line):
|
||||
ret[key] = value
|
||||
|
||||
|
@ -3942,9 +3942,9 @@ def manage_file(name,
|
||||
if not sfn:
|
||||
return _error(
|
||||
ret, 'Source file {0!r} not found'.format(source))
|
||||
# If the downloaded file came from a non salt server source verify
|
||||
# that it matches the intended sum value
|
||||
if _urlparse(source).scheme != 'salt':
|
||||
# If the downloaded file came from a non salt server or local source
|
||||
# verify that it matches the intended sum value
|
||||
if _urlparse(source).scheme not in ('salt', ''):
|
||||
dl_sum = get_hash(sfn, source_sum['hash_type'])
|
||||
if dl_sum != source_sum['hsum']:
|
||||
ret['comment'] = ('File sum set for file {0} of {1} does '
|
||||
|
@ -37,8 +37,8 @@ def __execute_cmd(name, xml):
|
||||
if not os.path.isdir(tmp_dir):
|
||||
os.mkdir(tmp_dir)
|
||||
with tempfile.NamedTemporaryFile(dir=tmp_dir,
|
||||
prefix=name,
|
||||
suffix=os.getpid(),
|
||||
prefix=name+str(os.getpid()),
|
||||
suffix='.xml',
|
||||
delete=False) as fh:
|
||||
tmpfilename = fh.name
|
||||
fh.write(xml)
|
||||
|
@ -11,7 +11,7 @@ from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
# Juniper interface libraries
|
||||
# https://github.com/jeremyschulman/py-junos-eznc
|
||||
# https://github.com/Juniper/py-junos-eznc
|
||||
|
||||
|
||||
try:
|
||||
@ -28,6 +28,7 @@ except ImportError:
|
||||
# Set up logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Define the module's virtual name
|
||||
__virtualname__ = 'junos'
|
||||
|
||||
@ -37,7 +38,7 @@ __proxyenabled__ = ['junos']
|
||||
def __virtual__():
|
||||
'''
|
||||
We need the Junos adapter libraries for this
|
||||
module to work. We also need a proxyobject object
|
||||
module to work. We also need a proxymodule entry in __opts__
|
||||
in the opts dictionary
|
||||
'''
|
||||
if HAS_JUNOS and 'proxy' in __opts__:
|
||||
@ -52,13 +53,17 @@ def facts_refresh():
|
||||
if the device configuration is changed by some other actor.
|
||||
'''
|
||||
|
||||
return __opts__['proxyobject'].refresh
|
||||
return __opts__['proxymodule']['junos.refresh']()
|
||||
|
||||
|
||||
def call_rpc():
|
||||
return __opts__['proxymodule']['junos.rpc']()
|
||||
|
||||
|
||||
def set_hostname(hostname=None, commit_change=True):
|
||||
|
||||
conn = __opts__['proxymodule']['junos.conn']()
|
||||
ret = dict()
|
||||
conn = __opts__['proxyobject']
|
||||
if hostname is None:
|
||||
ret['out'] = False
|
||||
return ret
|
||||
@ -79,8 +84,7 @@ def set_hostname(hostname=None, commit_change=True):
|
||||
|
||||
def commit():
|
||||
|
||||
conn = __opts__['proxyobject']
|
||||
|
||||
conn = __opts__['proxymodule']['junos.conn']()
|
||||
ret = {}
|
||||
commit_ok = conn.cu.commit_check()
|
||||
if commit_ok:
|
||||
@ -99,8 +103,8 @@ def commit():
|
||||
|
||||
|
||||
def rollback():
|
||||
conn = __opts__['proxyobject']
|
||||
ret = dict()
|
||||
conn = __opts__['proxymodule']['junos.conn']()
|
||||
|
||||
ret['out'] = conn.cu.rollback(0)
|
||||
|
||||
@ -114,8 +118,8 @@ def rollback():
|
||||
|
||||
def diff():
|
||||
|
||||
conn = __opts__['proxymodule']['junos.conn']()
|
||||
ret = dict()
|
||||
conn = __opts__['proxyobject']
|
||||
ret['out'] = True
|
||||
ret['message'] = conn.cu.diff()
|
||||
|
||||
@ -124,7 +128,7 @@ def diff():
|
||||
|
||||
def ping():
|
||||
|
||||
conn = __opts__['proxymodule']['junos.conn']()
|
||||
ret = dict()
|
||||
conn = __opts__['proxyobject']
|
||||
ret['message'] = conn.cli('show system uptime')
|
||||
ret['message'] = conn.probe()
|
||||
ret['out'] = True
|
||||
|
@ -884,8 +884,17 @@ def remove(name=None,
|
||||
except MinionError as exc:
|
||||
raise CommandExecutionError(exc)
|
||||
|
||||
old = list_pkgs(jail=jail, chroot=chroot)
|
||||
targets = [x for x in pkg_params if x in old]
|
||||
targets = []
|
||||
old = list_pkgs(jail=jail, chroot=chroot, with_origin=True)
|
||||
for pkg in pkg_params.items():
|
||||
# FreeBSD pkg supports `openjdk` and `java/openjdk7` package names
|
||||
if pkg[0].find("/") > 0:
|
||||
origin = pkg[0]
|
||||
pkg = [k for k, v in old.iteritems() if v['origin'] == origin][0]
|
||||
|
||||
if pkg[0] in old:
|
||||
targets.append(pkg[0])
|
||||
|
||||
if not targets:
|
||||
return {}
|
||||
|
||||
@ -915,7 +924,7 @@ def remove(name=None,
|
||||
__salt__['cmd.run'](cmd, python_shell=False, output_loglevel='trace')
|
||||
__context__.pop(_contextkey(jail, chroot), None)
|
||||
__context__.pop(_contextkey(jail, chroot, prefix='pkg.origin'), None)
|
||||
new = list_pkgs(jail=jail, chroot=chroot)
|
||||
new = list_pkgs(jail=jail, chroot=chroot, with_origin=True)
|
||||
return salt.utils.compare_dicts(old, new)
|
||||
|
||||
# Support pkg.delete to remove packages, since this is the CLI usage
|
||||
|
@ -17,11 +17,11 @@ __virtualname__ = 'pkg'
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only work on RestExampleOS
|
||||
Only work on proxy
|
||||
'''
|
||||
# Enable on these platforms only.
|
||||
enable = set((
|
||||
'RestExampleOS',
|
||||
'proxy',
|
||||
))
|
||||
if __grains__['os'] in enable:
|
||||
return __virtualname__
|
||||
@ -29,16 +29,16 @@ def __virtual__():
|
||||
|
||||
|
||||
def list_pkgs(versions_as_list=False, **kwargs):
|
||||
return __opts__['proxyobject'].package_list()
|
||||
return __opts__['proxymodule']['rest_sample.package_list']()
|
||||
|
||||
|
||||
def install(name=None, refresh=False, fromrepo=None,
|
||||
pkgs=None, sources=None, **kwargs):
|
||||
return __opts__['proxyobject'].package_install(name, **kwargs)
|
||||
return __opts__['proxymodule']['rest_sample.package_install'](name, **kwargs)
|
||||
|
||||
|
||||
def remove(name=None, pkgs=None, **kwargs):
|
||||
return __opts__['proxyobject'].package_remove(name)
|
||||
return __opts__['proxymodule']['rest_sample.package_remove'](name)
|
||||
|
||||
|
||||
def version(*names, **kwargs):
|
||||
@ -55,7 +55,7 @@ def version(*names, **kwargs):
|
||||
salt '*' pkg.version <package1> <package2> <package3> ...
|
||||
'''
|
||||
if len(names) == 1:
|
||||
return str(__opts__['proxyobject'].package_status(names))
|
||||
return str(__opts__['proxymodule']['rest_sample.package_status'](names))
|
||||
|
||||
|
||||
def installed(
|
||||
@ -68,7 +68,7 @@ def installed(
|
||||
sources=None,
|
||||
**kwargs):
|
||||
|
||||
p = __opts__['proxyobject'].package_status(name)
|
||||
p = __opts__['proxymodule']['rest_sample.package_status'](name)
|
||||
if version is None:
|
||||
if 'ret' in p:
|
||||
return str(p['ret'])
|
||||
|
105
salt/modules/system_rest_sample.py
Normal file
105
salt/modules/system_rest_sample.py
Normal file
@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Provide the service module for the proxy-minion REST sample
|
||||
'''
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
__proxyenabled__ = ['rest_sample']
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__func_alias__ = {
|
||||
'reload_': 'reload'
|
||||
}
|
||||
|
||||
# Define the module's virtual name
|
||||
__virtualname__ = 'service'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only work on systems that are a proxy minion
|
||||
'''
|
||||
if __grains__['kernel'] == 'proxy':
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
||||
def get_all():
|
||||
'''
|
||||
Return a list of all available services
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.get_all
|
||||
'''
|
||||
proxy_fn = 'rest_sample'+ '.service_list'
|
||||
return __opts__['proxymodule'][proxy_fn]()
|
||||
|
||||
|
||||
def start(name):
|
||||
'''
|
||||
Start the specified service on the rest_sample
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.start <service name>
|
||||
'''
|
||||
|
||||
proxy_fn = 'rest_sample'+ '.service_start'
|
||||
return __opts__['proxymodule'][proxy_fn](name)
|
||||
|
||||
|
||||
def stop(name):
|
||||
'''
|
||||
Stop the specified service on the rest_sample
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.stop <service name>
|
||||
'''
|
||||
proxy_fn = 'rest_sample'+ '.service_stop'
|
||||
return __opts__['proxymodule'][proxy_fn](name)
|
||||
|
||||
|
||||
def restart(name):
|
||||
'''
|
||||
Restart the specified service with rest_sample
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.restart <service name>
|
||||
'''
|
||||
|
||||
proxy_fn = 'rest_sample'+ '.service_restart'
|
||||
return __opts__['proxymodule'][proxy_fn](name)
|
||||
|
||||
|
||||
def status(name, sig):
|
||||
'''
|
||||
Return the status for a service via rest_sample, returns a bool
|
||||
whether the service is running.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.status <service name>
|
||||
'''
|
||||
|
||||
proxy_fn = 'rest_sample' + '.service_status'
|
||||
resp = __opts__['proxymodule'][proxy_fn](name)
|
||||
if resp['comment'] == 'stopped':
|
||||
return {name: False}
|
||||
if resp['comment'] == 'running':
|
||||
return {name: True}
|
@ -111,8 +111,9 @@ def ping():
|
||||
salt '*' test.ping
|
||||
'''
|
||||
|
||||
if 'proxyobject' in __opts__:
|
||||
return __opts__['proxyobject'].ping()
|
||||
if 'proxymodule' in __opts__:
|
||||
ping_cmd = __opts__['proxymodule'].loaded_base_name + '.ping'
|
||||
return __opts__['proxymodule'][ping_cmd]()
|
||||
else:
|
||||
return True
|
||||
|
||||
|
@ -31,6 +31,23 @@ def __virtual__():
|
||||
return False
|
||||
|
||||
|
||||
def _get_dirs(user_dir, startup_dir):
|
||||
'''
|
||||
Return a list of startup dirs
|
||||
'''
|
||||
try:
|
||||
users = os.listdir(user_dir)
|
||||
except WindowsError: # pylint: disable=E0602
|
||||
users = []
|
||||
|
||||
full_dirs = []
|
||||
for user in users:
|
||||
full_dir = os.path.join(user_dir, user, startup_dir)
|
||||
if os.path.exists(full_dir):
|
||||
full_dirs.append(full_dir)
|
||||
return full_dirs
|
||||
|
||||
|
||||
def list_():
|
||||
'''
|
||||
Get a list of automatically running programs
|
||||
@ -56,21 +73,18 @@ def list_():
|
||||
autoruns[key].append(line)
|
||||
|
||||
# Find autoruns in user's startup folder
|
||||
if os.path.exists('C:\\Documents and Settings\\'):
|
||||
user_dir = 'C:\\Documents and Settings\\'
|
||||
startup_dir = '\\Start Menu\\Programs\\Startup'
|
||||
else:
|
||||
user_dir = 'C:\\Documents and Settings\\'
|
||||
startup_dir = '\\Start Menu\\Programs\\Startup'
|
||||
full_dirs = _get_dirs(user_dir, startup_dir)
|
||||
if not full_dirs:
|
||||
user_dir = 'C:\\Users\\'
|
||||
startup_dir = '\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup'
|
||||
full_dirs = _get_dirs(user_dir, startup_dir)
|
||||
|
||||
for user in os.listdir(user_dir):
|
||||
try:
|
||||
full_dir = user_dir + user + startup_dir
|
||||
files = os.listdir(full_dir)
|
||||
autoruns[full_dir] = []
|
||||
for afile in files:
|
||||
autoruns[full_dir].append(afile)
|
||||
except Exception:
|
||||
pass
|
||||
for full_dir in full_dirs:
|
||||
files = os.listdir(full_dir)
|
||||
autoruns[full_dir] = []
|
||||
for single_file in files:
|
||||
autoruns[full_dir].append(single_file)
|
||||
|
||||
return autoruns
|
||||
|
@ -7,58 +7,79 @@ Interface with a Junos device via proxy-minion.
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
|
||||
# Import 3rd-party libs
|
||||
import jnpr.junos
|
||||
import jnpr.junos.utils
|
||||
import jnpr.junos.cfg
|
||||
# import jnpr.junos
|
||||
# import jnpr.junos.utils
|
||||
# import jnpr.junos.utils.config
|
||||
import json
|
||||
HAS_JUNOS = True
|
||||
|
||||
__proxyenabled__ = ['junos']
|
||||
|
||||
thisproxy = {}
|
||||
|
||||
class Proxyconn(object):
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# def __init__(opts):
|
||||
# '''
|
||||
# Open the connection to the Junos device, login, and bind to the
|
||||
# Resource class
|
||||
# '''
|
||||
# log.debug('Opening connection to junos')
|
||||
# thisproxy['conn'] = jnpr.junos.Device(user=opts['proxy']['username'],
|
||||
# host=opts['proxy']['host'],
|
||||
# password=opts['proxy']['passwd'])
|
||||
# thisproxy['conn'].open()
|
||||
# thisproxy['conn'].bind(cu=jnpr.junos.utils.config.Config)
|
||||
|
||||
|
||||
def conn():
|
||||
return thisproxy['conn']
|
||||
|
||||
|
||||
def facts():
|
||||
return thisproxy['conn'].facts
|
||||
|
||||
|
||||
def refresh():
|
||||
return thisproxy['conn'].facts_refresh()
|
||||
|
||||
|
||||
def proxytype():
|
||||
'''
|
||||
This class provides the persistent connection to the device that is being
|
||||
controlled.
|
||||
Returns the name of this proxy
|
||||
'''
|
||||
return 'junos'
|
||||
|
||||
|
||||
def id(opts):
|
||||
'''
|
||||
Returns a unique ID for this proxy minion
|
||||
'''
|
||||
return thisproxy['conn'].facts['hostname']
|
||||
|
||||
|
||||
def ping():
|
||||
'''
|
||||
Ping? Pong!
|
||||
'''
|
||||
return thisproxy['conn'].connected
|
||||
|
||||
|
||||
def shutdown(opts):
|
||||
'''
|
||||
This is called when the proxy-minion is exiting to make sure the
|
||||
connection to the device is closed cleanly.
|
||||
'''
|
||||
|
||||
def __init__(self, details):
|
||||
'''
|
||||
Open the connection to the Junos device, login, and bind to the
|
||||
Resource class
|
||||
'''
|
||||
self.conn = jnpr.junos.Device(user=details['username'],
|
||||
host=details['host'],
|
||||
password=details['passwd'])
|
||||
self.conn.open()
|
||||
self.conn.bind(cu=jnpr.junos.cfg.Resource)
|
||||
log.debug('Proxy module {0} shutting down!!'.format(opts['id']))
|
||||
try:
|
||||
thisproxy['conn'].close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def proxytype(self):
|
||||
'''
|
||||
Returns the name of this proxy
|
||||
'''
|
||||
return 'junos'
|
||||
|
||||
def id(self, opts):
|
||||
'''
|
||||
Returns a unique ID for this proxy minion
|
||||
'''
|
||||
return self.conn.facts['hostname']
|
||||
|
||||
def ping(self):
|
||||
'''
|
||||
Ping? Pong!
|
||||
'''
|
||||
return self.conn.connected
|
||||
|
||||
def shutdown(self, opts):
|
||||
'''
|
||||
This is called when the proxy-minion is exiting to make sure the
|
||||
connection to the device is closed cleanly.
|
||||
'''
|
||||
|
||||
print('Proxy module {0} shutting down!!'.format(opts['id']))
|
||||
try:
|
||||
self.conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
def rpc():
|
||||
return json.dumps(thisproxy['conn'].rpc.get_software_information())
|
||||
|
@ -1,147 +1,173 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
This is a simple proxy-minion designed to connect to and communicate with
|
||||
the bottle-based web service contained in salt/tests/rest.py.
|
||||
|
||||
Note this example needs the 'requests' library.
|
||||
Requests is not a hard dependency for Salt
|
||||
the bottle-based web service contained in https://github.com/salt-contrib/proxyminion_rest_example
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import python libs
|
||||
try:
|
||||
import requests
|
||||
HAS_REQUESTS = True
|
||||
except ImportError:
|
||||
HAS_REQUESTS = False
|
||||
import logging
|
||||
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__():
|
||||
'''
|
||||
Only return if all the modules are available
|
||||
'''
|
||||
if not HAS_REQUESTS:
|
||||
log.debug('rest_sample proxy __virtual__() called...')
|
||||
return True
|
||||
|
||||
|
||||
def init(opts):
|
||||
'''
|
||||
Every proxy module needs an 'init', though you can
|
||||
just put a 'pass' here if it doesn't need to do anything.
|
||||
'''
|
||||
log.debug('rest_sample proxy init() called...')
|
||||
|
||||
# Save the REST URL
|
||||
DETAILS['url'] = opts['proxy']['url']
|
||||
|
||||
# Make sure the REST URL ends with a '/'
|
||||
if not DETAILS['url'].endswith('/'):
|
||||
DETAILS['url'] += '/'
|
||||
|
||||
|
||||
def id(opts):
|
||||
'''
|
||||
Return a unique ID for this proxy minion. This ID MUST NOT CHANGE.
|
||||
If it changes while the proxy is running the salt-master will get
|
||||
really confused and may stop talking to this minion
|
||||
'''
|
||||
r = salt.utils.http.query(opts['proxy']['url']+'id', decode_type='json', decode=True)
|
||||
return r['dict']['id'].encode('ascii', 'ignore')
|
||||
|
||||
|
||||
def grains():
|
||||
'''
|
||||
Get the grains from the proxied device
|
||||
'''
|
||||
if not GRAINS_CACHE:
|
||||
r = salt.utils.http.query(DETAILS['url']+'info', decode_type='json', decode=True)
|
||||
GRAINS_CACHE = r['dict']
|
||||
return GRAINS_CACHE
|
||||
|
||||
|
||||
def grains_refresh():
|
||||
'''
|
||||
Refresh the grains from the proxied device
|
||||
'''
|
||||
GRAINS_CACHE = {}
|
||||
return grains()
|
||||
|
||||
|
||||
def service_start(name):
|
||||
'''
|
||||
Start a "service" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/start/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def service_stop(name):
|
||||
'''
|
||||
Stop a "service" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/stop/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def service_restart(name):
|
||||
'''
|
||||
Restart a "service" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/restart/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def service_list():
|
||||
'''
|
||||
List "services" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/list', decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def service_status(name):
|
||||
'''
|
||||
Check if a service is running on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'service/status/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def package_list():
|
||||
'''
|
||||
List "packages" installed on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'package/list', decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def package_install(name, **kwargs):
|
||||
'''
|
||||
Install a "package" on the REST server
|
||||
'''
|
||||
cmd = DETAILS['url']+'package/install/'+name
|
||||
if 'version' in kwargs:
|
||||
cmd += '/'+kwargs['version']
|
||||
else:
|
||||
cmd += '/1.0'
|
||||
r = salt.utils.http.query(cmd, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def package_remove(name):
|
||||
|
||||
'''
|
||||
Remove a "package" on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'package/remove/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def package_status(name):
|
||||
'''
|
||||
Check the installation status of a package on the REST server
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'package/status/'+name, decode_type='json', decode=True)
|
||||
return r['dict']
|
||||
|
||||
|
||||
def ping():
|
||||
'''
|
||||
Is the REST server up?
|
||||
'''
|
||||
r = salt.utils.http.query(DETAILS['url']+'ping', decode_type='json', decode=True)
|
||||
try:
|
||||
return r['dict'].get('ret', False)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class Proxyconn(object):
|
||||
def shutdown(opts):
|
||||
'''
|
||||
Interface with the REST sample web service (rest.py at
|
||||
https://github.com/cro/salt-proxy-rest)
|
||||
For this proxy shutdown is a no-op
|
||||
'''
|
||||
def __init__(self, details):
|
||||
self.url = details['url']
|
||||
self.grains_cache = {}
|
||||
|
||||
def id(self, opts):
|
||||
'''
|
||||
Return a unique ID for this proxy minion
|
||||
'''
|
||||
r = requests.get(self.url+'id')
|
||||
return r.text.encode('ascii', 'ignore')
|
||||
|
||||
def grains(self):
|
||||
'''
|
||||
Get the grains from the proxied device
|
||||
'''
|
||||
if not self.grains_cache:
|
||||
r = requests.get(self.url+'info')
|
||||
self.grains_cache = r.json()
|
||||
return self.grains_cache
|
||||
|
||||
def grains_refresh(self):
|
||||
'''
|
||||
Refresh the grains from the proxied device
|
||||
'''
|
||||
self.grains_cache = {}
|
||||
return self.grains()
|
||||
|
||||
def service_start(self, name):
|
||||
'''
|
||||
Start a "service" on the REST server
|
||||
'''
|
||||
r = requests.get(self.url+'service/start/'+name)
|
||||
return r.json()
|
||||
|
||||
def service_stop(self, name):
|
||||
'''
|
||||
Stop a "service" on the REST server
|
||||
'''
|
||||
r = requests.get(self.url+'service/stop/'+name)
|
||||
return r.json()
|
||||
|
||||
def service_restart(self, name):
|
||||
'''
|
||||
Restart a "service" on the REST server
|
||||
'''
|
||||
r = requests.get(self.url+'service/restart/'+name)
|
||||
return r.json()
|
||||
|
||||
def service_list(self):
|
||||
'''
|
||||
List "services" on the REST server
|
||||
'''
|
||||
r = requests.get(self.url+'service/list')
|
||||
return r.json()
|
||||
|
||||
def service_status(self, name):
|
||||
'''
|
||||
Check if a service is running on the REST server
|
||||
'''
|
||||
r = requests.get(self.url+'service/status/'+name)
|
||||
return r.json()
|
||||
|
||||
def package_list(self):
|
||||
'''
|
||||
List "packages" installed on the REST server
|
||||
'''
|
||||
r = requests.get(self.url+'package/list')
|
||||
return r.json()
|
||||
|
||||
def package_install(self, name, **kwargs):
|
||||
'''
|
||||
Install a "package" on the REST server
|
||||
'''
|
||||
cmd = self.url+'package/install/'+name
|
||||
if 'version' in kwargs:
|
||||
cmd += '/'+kwargs['version']
|
||||
else:
|
||||
cmd += '/1.0'
|
||||
r = requests.get(cmd)
|
||||
|
||||
def package_remove(self, name):
|
||||
'''
|
||||
Remove a "package" on the REST server
|
||||
'''
|
||||
r = requests.get(self.url+'package/remove/'+name)
|
||||
return r.json()
|
||||
|
||||
def package_status(self, name):
|
||||
'''
|
||||
Check the installation status of a package on the REST server
|
||||
'''
|
||||
r = requests.get(self.url+'package/status/'+name)
|
||||
return r.json()
|
||||
|
||||
def ping(self):
|
||||
'''
|
||||
Is the REST server up?
|
||||
'''
|
||||
r = requests.get(self.url+'ping')
|
||||
try:
|
||||
if r.status_code == 200:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def shutdown(self, opts):
|
||||
'''
|
||||
For this proxy shutdown is a no-op
|
||||
'''
|
||||
pass
|
||||
log.debug('rest_sample proxy shutdown() called...')
|
||||
|
@ -182,6 +182,8 @@ def _find_remove_targets(name=None,
|
||||
Inspect the arguments to pkg.removed and discover what packages need to
|
||||
be removed. Return a dict of packages to remove.
|
||||
'''
|
||||
if __grains__['os'] == 'FreeBSD':
|
||||
kwargs['with_origin'] = True
|
||||
cur_pkgs = __salt__['pkg.list_pkgs'](versions_as_list=True, **kwargs)
|
||||
if pkgs:
|
||||
to_remove = _repack_pkgs(pkgs, normalize=normalize)
|
||||
@ -204,7 +206,14 @@ def _find_remove_targets(name=None,
|
||||
targets = []
|
||||
problems = []
|
||||
for pkgname, pkgver in six.iteritems(to_remove):
|
||||
cver = cur_pkgs.get(pkgname, [])
|
||||
# FreeBSD pkg supports `openjdk` and `java/openjdk7` package names
|
||||
origin = bool(re.search('/', pkgname))
|
||||
|
||||
if __grains__['os'] == 'FreeBSD' and origin:
|
||||
cver = [k for k, v in six.iteritems(cur_pkgs) if v['origin'] == pkgname]
|
||||
else:
|
||||
cver = cur_pkgs.get(pkgname, [])
|
||||
|
||||
# Package not installed, no need to remove
|
||||
if not cver:
|
||||
continue
|
||||
@ -279,6 +288,9 @@ def _find_install_targets(name=None,
|
||||
else:
|
||||
ignore_types = []
|
||||
|
||||
if __grains__['os'] == 'FreeBSD':
|
||||
kwargs['with_origin'] = True
|
||||
|
||||
cur_pkgs = __salt__['pkg.list_pkgs'](versions_as_list=True, **kwargs)
|
||||
if any((pkgs, sources)):
|
||||
if pkgs:
|
||||
@ -319,7 +331,14 @@ def _find_install_targets(name=None,
|
||||
|
||||
to_unpurge = _find_unpurge_targets(desired)
|
||||
|
||||
cver = cur_pkgs.get(name, [])
|
||||
# FreeBSD pkg supports `openjdk` and `java/openjdk7` package names
|
||||
origin = bool(re.search('/', name))
|
||||
|
||||
if __grains__['os'] == 'FreeBSD' and origin:
|
||||
cver = [k for k, v in six.iteritems(cur_pkgs) if v['origin'] == name]
|
||||
else:
|
||||
cver = cur_pkgs.get(name, [])
|
||||
|
||||
if name not in to_unpurge:
|
||||
if version and version in cver and not pkg_verify:
|
||||
# The package is installed and is the correct version
|
||||
@ -477,8 +496,15 @@ def _verify_install(desired, new_pkgs):
|
||||
'''
|
||||
ok = []
|
||||
failed = []
|
||||
for pkgname, pkgver in six.iteritems(desired):
|
||||
cver = new_pkgs.get(pkgname)
|
||||
for pkgname, pkgver in desired.items():
|
||||
# FreeBSD pkg supports `openjdk` and `java/openjdk7` package names
|
||||
origin = bool(re.search('/', pkgname))
|
||||
|
||||
if __grains__['os'] == 'FreeBSD' and origin:
|
||||
cver = [k for k, v in six.iteritems(new_pkgs) if v['origin'] == pkgname]
|
||||
else:
|
||||
cver = new_pkgs.get(pkgname)
|
||||
|
||||
if not cver:
|
||||
failed.append(pkgname)
|
||||
continue
|
||||
@ -1118,6 +1144,8 @@ def installed(
|
||||
and x not in to_reinstall]
|
||||
failed = [x for x in targets if x not in modified]
|
||||
else:
|
||||
if __grains__['os'] == 'FreeBSD':
|
||||
kwargs['with_origin'] = True
|
||||
ok, failed = \
|
||||
_verify_install(
|
||||
desired, __salt__['pkg.list_pkgs'](
|
||||
|
@ -162,7 +162,12 @@ def managed(name,
|
||||
use_vt=use_vt,
|
||||
)
|
||||
|
||||
ret['result'] = _ret['retcode'] == 0
|
||||
if _ret['retcode'] != 0:
|
||||
ret['result'] = False
|
||||
ret['comment'] = _ret['stdout'] + _ret['stderr']
|
||||
return ret
|
||||
|
||||
ret['result'] = True
|
||||
ret['changes']['new'] = __salt__['cmd.run_stderr'](
|
||||
'{0} -V'.format(venv_py)).strip('\n')
|
||||
|
||||
|
@ -311,6 +311,8 @@ def query(url,
|
||||
urllib_request.HTTPHandler,
|
||||
urllib_request.HTTPCookieProcessor(sess_cookies)
|
||||
]
|
||||
if password_mgr:
|
||||
handlers.append(urllib_request.HTTPBasicAuthHandler(password_mgr))
|
||||
|
||||
if url.startswith('https') or port == 443:
|
||||
hostname = request.get_host()
|
||||
|
@ -121,6 +121,6 @@ class WheelClient(mixins.SyncClientMixin, mixins.AsyncClientMixin, object):
|
||||
>>> wheel.cmd('key.finger', ['jerry'])
|
||||
{'minions': {'jerry': '5d:f6:79:43:5e:d4:42:3f:57:b8:45:a8:7e:a4:6e:ca'}}
|
||||
'''
|
||||
|
||||
return self.low(fun, kwarg)
|
||||
|
||||
Wheel = WheelClient # for backward-compat
|
||||
|
@ -1,78 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||
'''
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from salttesting import skipIf, TestCase
|
||||
from salttesting.mock import (
|
||||
NO_MOCK,
|
||||
NO_MOCK_REASON,
|
||||
MagicMock,
|
||||
patch)
|
||||
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
# Import Salt Libs
|
||||
from salt.modules import rest_package
|
||||
|
||||
# Globals
|
||||
rest_package.__opts__ = {}
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class RestPkgTestCase(TestCase):
|
||||
'''
|
||||
Test cases for salt.modules.rest_package
|
||||
'''
|
||||
def test_list_pkgs(self):
|
||||
'''
|
||||
Test for list pkgs
|
||||
'''
|
||||
with patch.dict(rest_package.__opts__, {'proxyobject': MagicMock()}):
|
||||
self.assertTrue(rest_package.list_pkgs())
|
||||
|
||||
def test_install(self):
|
||||
'''
|
||||
Test for install
|
||||
'''
|
||||
with patch.dict(rest_package.__opts__, {'proxyobject': MagicMock()}):
|
||||
self.assertTrue(rest_package.install())
|
||||
|
||||
def test_remove(self):
|
||||
'''
|
||||
Test for remove
|
||||
'''
|
||||
with patch.dict(rest_package.__opts__, {'proxyobject': MagicMock()}):
|
||||
self.assertTrue(rest_package.remove())
|
||||
|
||||
def test_version(self):
|
||||
'''
|
||||
Test to return a string representing the package version or
|
||||
an empty string if not installed.
|
||||
'''
|
||||
with patch.dict(rest_package.__opts__, {'proxyobject': MagicMock()}):
|
||||
self.assertTrue(rest_package.version('A'))
|
||||
|
||||
def test_installed(self):
|
||||
'''
|
||||
Test for installed
|
||||
'''
|
||||
with patch.dict(rest_package.__opts__, {'proxyobject': MagicMock()}):
|
||||
with patch.object(rest_package.__opts__['proxyobject'],
|
||||
'package_status',
|
||||
MagicMock(return_value={'ret': 'ret'})):
|
||||
self.assertEqual(rest_package.installed('name'), 'ret')
|
||||
|
||||
self.assertTrue(rest_package.installed('name'))
|
||||
|
||||
self.assertFalse(rest_package.installed('name', version='v'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(RestPkgTestCase, needs_daemon=False)
|
@ -1,81 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||
'''
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from salttesting import skipIf, TestCase
|
||||
from salttesting.mock import (
|
||||
NO_MOCK,
|
||||
NO_MOCK_REASON,
|
||||
MagicMock,
|
||||
patch)
|
||||
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
# Import Salt Libs
|
||||
from salt.modules import rest_service
|
||||
|
||||
# Globals
|
||||
rest_service.__opts__ = {}
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class RestSvcTestCase(TestCase):
|
||||
'''
|
||||
Test cases for salt.modules.rest_service
|
||||
'''
|
||||
def test_start(self):
|
||||
'''
|
||||
Test to start the specified service
|
||||
'''
|
||||
with patch.dict(rest_service.__opts__, {'proxyobject': MagicMock()}):
|
||||
with patch.object(rest_service.__opts__['proxyobject'],
|
||||
'service_start', MagicMock(return_value=True)):
|
||||
self.assertTrue(rest_service.start('name'))
|
||||
|
||||
def test_stop(self):
|
||||
'''
|
||||
Test to stop the specified service
|
||||
'''
|
||||
with patch.dict(rest_service.__opts__, {'proxyobject': MagicMock()}):
|
||||
with patch.object(rest_service.__opts__['proxyobject'],
|
||||
'service_stop', MagicMock(return_value=True)):
|
||||
self.assertTrue(rest_service.stop('name'))
|
||||
|
||||
def test_restart(self):
|
||||
'''
|
||||
Test to restart the named service
|
||||
'''
|
||||
with patch.dict(rest_service.__opts__, {'proxyobject': MagicMock()}):
|
||||
with patch.object(rest_service.__opts__['proxyobject'],
|
||||
'service_restart', MagicMock(return_value=True)):
|
||||
self.assertTrue(rest_service.restart('name'))
|
||||
|
||||
def test_status(self):
|
||||
'''
|
||||
Test to return the status for a service, returns a bool whether
|
||||
the service is running.
|
||||
'''
|
||||
with patch.dict(rest_service.__opts__, {'proxyobject': MagicMock()}):
|
||||
with patch.object(rest_service.__opts__['proxyobject'],
|
||||
'service_status', MagicMock(return_value=True)):
|
||||
self.assertTrue(rest_service.status('name'))
|
||||
|
||||
def test_list_(self):
|
||||
'''
|
||||
Test for list services.
|
||||
'''
|
||||
with patch.dict(rest_service.__opts__, {'proxyobject': MagicMock()}):
|
||||
with patch.object(rest_service.__opts__['proxyobject'],
|
||||
'service_list_', MagicMock(return_value=True)):
|
||||
self.assertTrue(rest_service.list_())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(RestSvcTestCase, needs_daemon=False)
|
Loading…
Reference in New Issue
Block a user