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