mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 01:18:58 +00:00
Add initial support for etcd
This commit is contained in:
parent
9890db1fc1
commit
585c2755fc
136
salt/modules/etcd_mod.py
Normal file
136
salt/modules/etcd_mod.py
Normal file
@ -0,0 +1,136 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Execution module to work with etcd
|
||||
|
||||
:depends: - python-etcd
|
||||
|
||||
In order to use an etcd server, a profile should be created in the master
|
||||
configuration file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
my_etd_config:
|
||||
etcd.host: 127.0.0.1
|
||||
etcd.port: 4001
|
||||
|
||||
It is technically possible to configure etcd without using a profile, but this
|
||||
is not consided to be a best practice, especially when multiple etcd servers or
|
||||
clusters are available.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
etcd.host: 127.0.0.1
|
||||
etcd.port: 4001
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
import logging
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
import salt.utils.etcd_util
|
||||
HAS_LIBS = True
|
||||
except Exception:
|
||||
HAS_LIBS = False
|
||||
|
||||
__virtualname__ = 'etcd'
|
||||
|
||||
# Set up logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Define a function alias in order not to shadow built-in's
|
||||
__func_alias__ = {
|
||||
'get_': 'get',
|
||||
'set_': 'set',
|
||||
'rm_': 'rm',
|
||||
'ls_': 'ls'
|
||||
}
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only return if python-etcd is installed
|
||||
'''
|
||||
return __virtualname__ if HAS_LIBS else False
|
||||
|
||||
|
||||
def get_(key, recurse=False, profile=None):
|
||||
'''
|
||||
Get a value from etcd, by direct path
|
||||
|
||||
CLI Examples:
|
||||
|
||||
salt myminion etcd.get /path/to/key
|
||||
salt myminion etcd.get /path/to/key profile=my_etcd_config
|
||||
salt myminion etcd.get /path/to/key recurse=True profile=my_etcd_config
|
||||
'''
|
||||
client = salt.utils.etcd_util.get_conn(__opts__, profile)
|
||||
result = client.get(key)
|
||||
|
||||
if recurse:
|
||||
return salt.utils.etcd_util.tree(client, key)
|
||||
else:
|
||||
return result.value
|
||||
|
||||
|
||||
def set_(key, value, profile=None):
|
||||
'''
|
||||
Set a value in etcd, by direct path
|
||||
|
||||
CLI Example:
|
||||
|
||||
salt myminion etcd.set /path/to/key value
|
||||
salt myminion etcd.set /path/to/key value profile=my_etcd_config
|
||||
'''
|
||||
client = salt.utils.etcd_util.get_conn(__opts__, profile)
|
||||
return client.write(key, value)
|
||||
|
||||
|
||||
def ls_(path='/', profile=None):
|
||||
'''
|
||||
Return all keys and dirs inside a specific path
|
||||
|
||||
CLI Example:
|
||||
|
||||
salt myminion etcd.ls /path/to/dir/
|
||||
salt myminion etcd.ls /path/to/dir/ profile=my_etcd_config
|
||||
'''
|
||||
ret = {}
|
||||
client = salt.utils.etcd_util.get_conn(__opts__, profile)
|
||||
items = client.get(path)
|
||||
for item in items.children:
|
||||
if item.dir is True:
|
||||
dir_name = '{0}/'.format(item.key)
|
||||
ret[dir_name] = {}
|
||||
else:
|
||||
ret[item.key] = item.value
|
||||
return {path: ret}
|
||||
|
||||
|
||||
def rm_(key, recurse=False, profile=None):
|
||||
'''
|
||||
Delete a key from etcd
|
||||
|
||||
CLI Example:
|
||||
|
||||
salt myminion etcd.rm /path/to/key
|
||||
salt myminion etcd.rm /path/to/key profile=my_etcd_config
|
||||
salt myminion etcd.rm /path/to/dir recurse=True profile=my_etcd_config
|
||||
'''
|
||||
client = salt.utils.etcd_util.get_conn(__opts__, profile)
|
||||
return client.delete(key, recursive=recurse)
|
||||
|
||||
|
||||
def tree(path='/', profile=None):
|
||||
'''
|
||||
Recurse through etcd and return all values
|
||||
|
||||
CLI Example:
|
||||
|
||||
salt myminion etcd.tree
|
||||
salt myminion etcd.tree profile=my_etcd_config
|
||||
salt myminion etcd.tree /path/to/keys profile=my_etcd_config
|
||||
'''
|
||||
client = salt.utils.etcd_util.get_conn(__opts__, profile)
|
||||
return salt.utils.etcd_util.tree(client, path)
|
74
salt/pillar/etcd_pillar.py
Normal file
74
salt/pillar/etcd_pillar.py
Normal file
@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Use etcd data as a Pillar source
|
||||
|
||||
:depends: - python-etcd
|
||||
|
||||
In order to use an etcd server, a profile must be created in the master
|
||||
configuration file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
my_etd_config:
|
||||
etcd.host: 127.0.0.1
|
||||
etcd.port: 4001
|
||||
|
||||
After the profile is created, configure the external pillar system to use it.
|
||||
Optionally, a root may be specified.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
ext_pillar:
|
||||
- etcd: my_etcd_config
|
||||
|
||||
ext_pillar:
|
||||
- etcd: my_etcd_config root=/salt
|
||||
|
||||
Using these configuration profiles, multiple etcd sources may also be used:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
ext_pillar:
|
||||
- etcd: my_etcd_config
|
||||
- etcd: my_other_etcd_config
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
import logging
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
import salt.utils.etcd_util
|
||||
HAS_LIBS = True
|
||||
except Exception:
|
||||
HAS_LIBS = False
|
||||
|
||||
__virtualname__ = 'etcd'
|
||||
|
||||
# Set up logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only return if python-etcd is installed
|
||||
'''
|
||||
return __virtualname__ if HAS_LIBS else False
|
||||
|
||||
|
||||
def ext_pillar(minion_id, pillar, conf): # pylint: disable=W0613
|
||||
'''
|
||||
Check etcd for all data
|
||||
'''
|
||||
comps = conf.split()
|
||||
|
||||
profile = None
|
||||
if comps[0]:
|
||||
profile = comps[0]
|
||||
client = salt.utils.etcd_util.get_conn(__opts__, profile)
|
||||
|
||||
path = '/'
|
||||
if len(comps) > 1 and comps[1].startswith('root='):
|
||||
path = comps[1].replace('root=', '')
|
||||
|
||||
return salt.utils.etcd_util.tree(client, path)
|
82
salt/returners/etcd_return.py
Normal file
82
salt/returners/etcd_return.py
Normal file
@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Return data to an etcd server or cluster
|
||||
|
||||
:depends: - python-etcd
|
||||
|
||||
In order to return to an etcd server, a profile should be created in the master
|
||||
configuration file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
my_etd_config:
|
||||
etcd.host: 127.0.0.1
|
||||
etcd.port: 4001
|
||||
|
||||
It is technically possible to configure etcd without using a profile, but this
|
||||
is not consided to be a best practice, especially when multiple etcd servers or
|
||||
clusters are available.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
etcd.host: 127.0.0.1
|
||||
etcd.port: 4001
|
||||
|
||||
Additionally, two more options must be specified in the top-level configuration
|
||||
in order to use the etcd returner:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
etcd.returner: my_etcd_config
|
||||
etcd.returner_root: /salt/return
|
||||
|
||||
The ``etcd.returner`` option specifies which configuration profile to use. The
|
||||
``etcd.returner_root`` option specifies the path inside etcd to use as the root
|
||||
of the returner system.
|
||||
|
||||
Once the etcd options are configured, the returner may be used:
|
||||
|
||||
CLI Example:
|
||||
|
||||
salt '*' test.ping --return etcd
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
import logging
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
import salt.utils.etcd_util
|
||||
HAS_LIBS = True
|
||||
except Exception:
|
||||
HAS_LIBS = False
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Define the module's virtual name
|
||||
__virtualname__ = 'etcd'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only return if python-etcd is installed
|
||||
'''
|
||||
return __virtualname__ if HAS_LIBS else False
|
||||
|
||||
|
||||
def returner(ret):
|
||||
'''
|
||||
Return data to an etcd server or cluster
|
||||
'''
|
||||
profile = __opts__.get('etcd.returner', None)
|
||||
path = __opts__.get('etcd.returner_root', '/salt/return')
|
||||
client = salt.utils.etcd_util.get_conn(__opts__, profile)
|
||||
|
||||
for field in ret.keys():
|
||||
dest = '/'.join((
|
||||
path,
|
||||
ret['jid'],
|
||||
ret['id'],
|
||||
field
|
||||
))
|
||||
client.write(dest, ret[field])
|
79
salt/utils/etcd_util.py
Normal file
79
salt/utils/etcd_util.py
Normal file
@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Utilities for working with etcd
|
||||
|
||||
:depends: - python-etcd
|
||||
|
||||
This library sets up a client object for etcd, using the configuration passed
|
||||
into the client() function. Normally, this is __opts__. Optionally, a profile
|
||||
may be passed in. The following configurations are both valid:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# No profile name
|
||||
etcd.host: 127.0.0.1
|
||||
etcd.port: 4001
|
||||
|
||||
# One or more profiles defined
|
||||
my_etcd_config:
|
||||
etcd.host: 127.0.0.1
|
||||
etcd.port: 4001
|
||||
|
||||
Once configured, the client() function is passed a set of opts, and optionally,
|
||||
the name of a profile to be used.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import salt.utils.etcd_utils
|
||||
client = salt.utils.etcd_utils.client(__opts__, profile='my_etcd_config')
|
||||
|
||||
It should be noted that some usages of etcd require a profile to be specified,
|
||||
rather than top-level configurations. This being the case, it is better to
|
||||
always use a named configuration profile, as shown above.
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
import logging
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
import etcd
|
||||
HAS_LIBS = True
|
||||
except Exception:
|
||||
HAS_LIBS = False
|
||||
|
||||
# Set up logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_conn(opts, profile=None):
|
||||
'''
|
||||
Return a client object for accessing etcd
|
||||
'''
|
||||
if profile:
|
||||
conf = opts.get(profile, {})
|
||||
else:
|
||||
conf = opts
|
||||
|
||||
host = conf.get('etcd.host', '127.0.0.1')
|
||||
port = conf.get('etcd.port', 4001)
|
||||
|
||||
return etcd.Client(host, port)
|
||||
|
||||
|
||||
def tree(client, path):
|
||||
'''
|
||||
Recurse through etcd and return all values
|
||||
'''
|
||||
ret = {}
|
||||
items = client.get(path)
|
||||
|
||||
for item in items.children:
|
||||
comps = str(item.key).split('/')
|
||||
if item.dir is True:
|
||||
if item.key == path:
|
||||
continue
|
||||
ret[comps[-1]] = tree(client, item.key)
|
||||
else:
|
||||
ret[comps[-1]] = item.value
|
||||
return ret
|
Loading…
Reference in New Issue
Block a user