mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #24156 from basepi/merge-forward-2015.5
[2015.5] Merge forward from 2014.7 to 2015.5
This commit is contained in:
commit
b9507d1567
10 changed files with 170 additions and 120 deletions
|
@ -395,4 +395,4 @@ class ReleasesTree(TocTree):
|
|||
|
||||
def setup(app):
|
||||
app.add_directive('releasestree', ReleasesTree)
|
||||
app.connect('autodoc-skip-member', skip_mod_init_member)
|
||||
app.connect('autodoc-skip-member', skip_mod_init_member)
|
||||
|
|
|
@ -12,24 +12,6 @@ and fast enough to communicate with those servers in *seconds*.
|
|||
Salt delivers a dynamic communication bus for infrastructures that can be used
|
||||
for orchestration, remote execution, configuration management and much more.
|
||||
|
||||
.. seealso:: Other Documentation
|
||||
|
||||
Download an offline copy of the latest Salt documentation:
|
||||
|
||||
* `PDF`_
|
||||
* `ePub`_
|
||||
|
||||
See documentation for past Salt releases at http://salt.readthedocs.org.
|
||||
Download offline copies on the `ReadTheDocs download page`_.
|
||||
|
||||
Watch announcements, demonstrations, and video tutorials on the `SaltStack
|
||||
YouTube channel`_.
|
||||
|
||||
.. _`PDF`: https://media.readthedocs.org/pdf/salt/latest/salt.pdf
|
||||
.. _`ePub`: https://media.readthedocs.org/epub/salt/latest/salt.epub
|
||||
.. _`ReadTheDocs download page`: https://readthedocs.org/projects/salt/downloads/
|
||||
.. _`SaltStack YouTube channel`: http://www.youtube.com/saltstack
|
||||
|
||||
Download
|
||||
========
|
||||
|
||||
|
@ -47,18 +29,28 @@ shell script, which automates the install correctly on multiple platforms:
|
|||
|
||||
https://github.com/saltstack/salt-bootstrap
|
||||
|
||||
Getting Started
|
||||
Get Started
|
||||
===============
|
||||
|
||||
This walkthrough helps individuals to get started quickly and gain a
|
||||
A new `Get Started Guide <http://docs.saltstack.com/en/getstarted/>`_ walks you
|
||||
through the basics of getting SaltStack up and running. You'll learn how to:
|
||||
|
||||
* Install and configure SaltStack
|
||||
* Remotely execute commands across all managed systems
|
||||
* Design, develop, and deploy system configurations
|
||||
|
||||
Tutorials
|
||||
=========
|
||||
|
||||
This walkthrough is an additional tutorial to help you get started quickly and gain a
|
||||
foundational knowledge of Salt:
|
||||
|
||||
:doc:`Official Salt Walkthrough</topics/tutorials/walkthrough>`
|
||||
:doc:`Official Salt Walkthrough </topics/tutorials/walkthrough>`
|
||||
|
||||
The following getting started tutorials are also available:
|
||||
|
||||
States - Configuration Management with Salt:
|
||||
- :doc:`Getting Started with States<topics/tutorials/starting_states>`
|
||||
- :doc:`Getting Started with States <topics/tutorials/starting_states>`
|
||||
- :doc:`Basic config management <topics/tutorials/states_pt1>`
|
||||
- :doc:`Less basic config management <topics/tutorials/states_pt2>`
|
||||
- :doc:`Advanced techniques <topics/tutorials/states_pt3>`
|
||||
|
|
|
@ -5,13 +5,13 @@ Release notes
|
|||
See the :doc:`version numbers</topics/releases/version_numbers>` page for more
|
||||
information about the version numbering scheme.
|
||||
|
||||
Latest Stable Release
|
||||
Latest Branch Release
|
||||
=====================
|
||||
|
||||
.. releasestree::
|
||||
:maxdepth: 1
|
||||
|
||||
2015.5.0
|
||||
2014.7.6
|
||||
|
||||
Previous Releases
|
||||
=================
|
||||
|
@ -20,7 +20,6 @@ Previous Releases
|
|||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
2015.5.*
|
||||
2014.7.*
|
||||
2014.1.*
|
||||
0.*
|
||||
|
|
|
@ -194,7 +194,6 @@ Thu Jan 15 17:50:52 UTC 2015 - aboe76@gmail.com
|
|||
- Added man salt.7.gz to salt-master package
|
||||
|
||||
-------------------------------------------------------------------
|
||||
>>>>>>> updated suse spec file to version 2015.5.0
|
||||
Mon Nov 3 21:35:31 UTC 2014 - aboe76@gmail.com
|
||||
|
||||
- Updated to Major Release 2014.7.0
|
||||
|
|
|
@ -44,18 +44,13 @@ class Batch(object):
|
|||
else:
|
||||
args.append(self.opts.get('expr_form', 'glob'))
|
||||
|
||||
ping_gen = self.local.cmd_iter_no_block(*args, **self.eauth)
|
||||
wait_until = time.time() + self.opts['timeout']
|
||||
ping_gen = self.local.cmd_iter(*args, **self.eauth)
|
||||
|
||||
fret = set()
|
||||
for ret in ping_gen:
|
||||
m = next(ret.iterkeys())
|
||||
if m is not None:
|
||||
fret.add(m)
|
||||
if time.time() > wait_until:
|
||||
break
|
||||
if m is None:
|
||||
time.sleep(0.1)
|
||||
return (list(fret), ping_gen)
|
||||
|
||||
def get_bnum(self):
|
||||
|
|
|
@ -391,8 +391,8 @@ class LocalClient(object):
|
|||
.. code-block:: python
|
||||
|
||||
>>> returns = local.cmd_batch('*', 'state.highstate', bat='10%')
|
||||
>>> for return in returns:
|
||||
... print return
|
||||
>>> for ret in returns:
|
||||
... print(ret)
|
||||
{'jerry': {...}}
|
||||
{'dave': {...}}
|
||||
{'stewart': {...}}
|
||||
|
@ -622,13 +622,13 @@ class LocalClient(object):
|
|||
The function signature is the same as :py:meth:`cmd` with the
|
||||
following exceptions.
|
||||
|
||||
:return: A generator
|
||||
:return: A generator yielding the individual minion returns
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> ret = local.cmd_iter('*', 'test.ping')
|
||||
>>> for i in ret:
|
||||
... print i
|
||||
... print(i)
|
||||
{'jerry': {'ret': True}}
|
||||
{'dave': {'ret': True}}
|
||||
{'stewart': {'ret': True}}
|
||||
|
@ -648,9 +648,9 @@ class LocalClient(object):
|
|||
else:
|
||||
for fn_ret in self.get_iter_returns(pub_data['jid'],
|
||||
pub_data['minions'],
|
||||
self._get_timeout(timeout),
|
||||
tgt,
|
||||
expr_form,
|
||||
timeout=self._get_timeout(timeout),
|
||||
tgt=tgt,
|
||||
tgt_type=expr_form,
|
||||
**kwargs):
|
||||
if not fn_ret:
|
||||
continue
|
||||
|
@ -667,19 +667,21 @@ class LocalClient(object):
|
|||
kwarg=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Blocks while waiting for individual minions to return.
|
||||
Yields the individual minion returns as they come in, or None
|
||||
when no returns are available.
|
||||
|
||||
The function signature is the same as :py:meth:`cmd` with the
|
||||
following exceptions.
|
||||
|
||||
:returns: None until the next minion returns. This allows for actions
|
||||
to be injected in between minion returns.
|
||||
:returns: A generator yielding the individual minion returns, or None
|
||||
when no returns are available. This allows for actions to be
|
||||
injected in between minion returns.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> ret = local.cmd_iter('*', 'test.ping')
|
||||
>>> ret = local.cmd_iter_no_block('*', 'test.ping')
|
||||
>>> for i in ret:
|
||||
... print i
|
||||
... print(i)
|
||||
None
|
||||
{'jerry': {'ret': True}}
|
||||
{'dave': {'ret': True}}
|
||||
|
@ -701,9 +703,10 @@ class LocalClient(object):
|
|||
else:
|
||||
for fn_ret in self.get_iter_returns(pub_data['jid'],
|
||||
pub_data['minions'],
|
||||
timeout,
|
||||
tgt,
|
||||
expr_form,
|
||||
timeout=timeout,
|
||||
tgt=tgt,
|
||||
tgt_type=expr_form,
|
||||
block=False,
|
||||
**kwargs):
|
||||
yield fn_ret
|
||||
|
||||
|
@ -855,6 +858,7 @@ class LocalClient(object):
|
|||
tgt_type='glob',
|
||||
expect_minions=False,
|
||||
gather_errors=True,
|
||||
block=True,
|
||||
**kwargs):
|
||||
'''
|
||||
Watch the event system and return job data as it comes in
|
||||
|
@ -1028,7 +1032,10 @@ class LocalClient(object):
|
|||
break
|
||||
|
||||
# don't spin
|
||||
time.sleep(0.01)
|
||||
if block:
|
||||
time.sleep(0.01)
|
||||
else:
|
||||
yield
|
||||
if expect_minions:
|
||||
for minion in list((minions - found)):
|
||||
yield {minion: {'failed': True}}
|
||||
|
|
|
@ -57,6 +57,24 @@ def _get_rabbitmq_plugin():
|
|||
return rabbitmq
|
||||
|
||||
|
||||
def _output_to_dict(cmdoutput, values_mapper=None):
|
||||
'''Convert rabbitmqctl output to a dict of data
|
||||
cmdoutput: string output of rabbitmqctl commands
|
||||
values_mapper: function object to process the values part of each line
|
||||
'''
|
||||
ret = {}
|
||||
if values_mapper is None:
|
||||
values_mapper = lambda string: string.split('\t')
|
||||
|
||||
# remove first and last line: Listing ... - ...done
|
||||
data_rows = cmdoutput.splitlines()[1:-1]
|
||||
for row in data_rows:
|
||||
key, values = row.split('\t', 1)
|
||||
ret[key] = values_mapper(values)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def list_users(runas=None):
|
||||
'''
|
||||
Return a list of users based off of rabbitmqctl user_list.
|
||||
|
@ -67,19 +85,14 @@ def list_users(runas=None):
|
|||
|
||||
salt '*' rabbitmq.list_users
|
||||
'''
|
||||
ret = {}
|
||||
if runas is None:
|
||||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run']('rabbitmqctl list_users',
|
||||
runas=runas)
|
||||
for line in res.splitlines():
|
||||
if '...' not in line or line == '\n':
|
||||
parts = line.split('\t')
|
||||
if len(parts) < 2:
|
||||
continue
|
||||
user, properties = parts[0], parts[1]
|
||||
ret[user] = properties
|
||||
return ret
|
||||
|
||||
# func to get tags from string such as "[admin, monitoring]"
|
||||
func = lambda string: set(string[1:-1].split(','))
|
||||
return _output_to_dict(res, func)
|
||||
|
||||
|
||||
def list_vhosts(runas=None):
|
||||
|
@ -96,9 +109,9 @@ def list_vhosts(runas=None):
|
|||
runas = salt.utils.get_user()
|
||||
res = __salt__['cmd.run']('rabbitmqctl list_vhosts',
|
||||
runas=runas)
|
||||
lines = res.splitlines()
|
||||
vhost_list = [line for line in lines if '...' not in line]
|
||||
return vhost_list
|
||||
|
||||
# remove first and last line: Listing ... - ...done
|
||||
return res.splitlines()[1:-1]
|
||||
|
||||
|
||||
def user_exists(name, runas=None):
|
||||
|
@ -313,7 +326,8 @@ def list_permissions(vhost, runas=None):
|
|||
'rabbitmqctl list_permissions -p {0}'.format(vhost),
|
||||
python_shell=False,
|
||||
runas=runas)
|
||||
return [r.split('\t') for r in res.splitlines()]
|
||||
|
||||
return _output_to_dict(res)
|
||||
|
||||
|
||||
def list_user_permissions(name, runas=None):
|
||||
|
@ -332,7 +346,8 @@ def list_user_permissions(name, runas=None):
|
|||
'rabbitmqctl list_user_permissions {0}'.format(name),
|
||||
python_shell=False,
|
||||
runas=runas)
|
||||
return [r.split('\t') for r in res.splitlines()]
|
||||
|
||||
return _output_to_dict(res)
|
||||
|
||||
|
||||
def set_user_tags(name, tags, runas=None):
|
||||
|
@ -346,6 +361,10 @@ def set_user_tags(name, tags, runas=None):
|
|||
'''
|
||||
if runas is None:
|
||||
runas = salt.utils.get_user()
|
||||
|
||||
if tags and isinstance(tags, (list, tuple)):
|
||||
tags = ' '.join(tags)
|
||||
|
||||
res = __salt__['cmd.run'](
|
||||
'rabbitmqctl set_user_tags {0} {1}'.format(name, tags),
|
||||
python_shell=False,
|
||||
|
|
|
@ -132,9 +132,8 @@ it can also watch a git state for changes
|
|||
- git: my-project
|
||||
|
||||
|
||||
Should I use :mod:`cmd.run <salt.states.cmd.run>` or :mod:`cmd.wait
|
||||
<salt.states.cmd.wait>`?
|
||||
-------------------------------------------------------------------------------
|
||||
Should I use :mod:`cmd.run <salt.states.cmd.run>` or :mod:`cmd.wait <salt.states.cmd.wait>`?
|
||||
--------------------------------------------------------------------------------------------
|
||||
|
||||
These two states are often confused. The important thing to remember about them
|
||||
is that :mod:`cmd.run <salt.states.cmd.run>` states are run each time the SLS
|
||||
|
@ -159,7 +158,7 @@ executed when the state it is watching changes. Example:
|
|||
- file: /usr/local/bin/postinstall.sh
|
||||
|
||||
How do I create an environment from a pillar map?
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------
|
||||
|
||||
The map that comes from a pillar cannot be directly consumed by the env option.
|
||||
To use it one must convert it to a list. Example:
|
||||
|
|
|
@ -39,6 +39,39 @@ def __virtual__():
|
|||
return salt.utils.which('rabbitmqctl') is not None
|
||||
|
||||
|
||||
def _check_perms_changes(name, newperms):
|
||||
'''
|
||||
Whether Rabbitmq user's permissions need to be changed
|
||||
'''
|
||||
if not newperms:
|
||||
return False
|
||||
|
||||
existing_perms = __salt__['rabbitmq.list_user_permissions'](name)
|
||||
|
||||
perm_need_change = False
|
||||
for vhost_perms in newperms:
|
||||
for vhost, perms in vhost_perms.iteritems():
|
||||
if vhost in existing_perms:
|
||||
if perms != existing_perms[vhost]:
|
||||
perm_need_change = True
|
||||
else:
|
||||
perm_need_change = True
|
||||
|
||||
return perm_need_change
|
||||
|
||||
|
||||
def _check_tags_changes(name, newtags):
|
||||
'''
|
||||
Whether Rabbitmq user's tags need to be changed
|
||||
'''
|
||||
if newtags:
|
||||
if isinstance(newtags, str):
|
||||
newtags = newtags.split()
|
||||
return __salt__['rabbitmq.list_users']()[name] - set(newtags)
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def present(name,
|
||||
password=None,
|
||||
force=False,
|
||||
|
@ -67,41 +100,69 @@ def present(name,
|
|||
|
||||
user_exists = __salt__['rabbitmq.user_exists'](name, runas=runas)
|
||||
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
|
||||
if user_exists:
|
||||
if force:
|
||||
ret['comment'] = 'User {0} is set to be updated'
|
||||
else:
|
||||
ret['comment'] = 'User {0} already presents'
|
||||
else:
|
||||
ret['comment'] = 'User {0} is set to be created'
|
||||
|
||||
ret['comment'] = ret['comment'].format(name)
|
||||
return ret
|
||||
|
||||
if user_exists and not force:
|
||||
log.debug('User exists, and force is not set - Abandoning')
|
||||
if user_exists and not any((force, perms, tags)):
|
||||
log.debug('RabbitMQ user %s exists, '
|
||||
'and force is not set.', name)
|
||||
ret['comment'] = 'User {0} already presents'.format(name)
|
||||
return ret
|
||||
else:
|
||||
changes = {'old': '', 'new': ''}
|
||||
|
||||
# Get it into the correct format
|
||||
if tags and isinstance(tags, (list, tuple)):
|
||||
tags = ' '.join(tags)
|
||||
if not tags:
|
||||
tags = ''
|
||||
if not user_exists:
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] = 'User {0} is set to be created'.format(name)
|
||||
return ret
|
||||
|
||||
def _set_tags_and_perms(tags, perms):
|
||||
if tags:
|
||||
result.update(__salt__['rabbitmq.set_user_tags'](
|
||||
name, tags, runas=runas)
|
||||
)
|
||||
changes['new'] += 'Set tags: {0}\n'.format(tags)
|
||||
for element in perms:
|
||||
for vhost, perm in element.items():
|
||||
log.debug("RabbitMQ user %s doesn't exist - Creating", name)
|
||||
result = __salt__['rabbitmq.add_user'](
|
||||
name, password, runas=runas)
|
||||
else:
|
||||
log.debug('RabbitMQ user %s exists', name)
|
||||
if force:
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
|
||||
if password is not None:
|
||||
if __opts__['test']:
|
||||
ret['comment'] = ('User {0}\'s password is '
|
||||
'set to be updated'.format(name))
|
||||
return ret
|
||||
|
||||
result = __salt__['rabbitmq.change_password'](
|
||||
name, password, runas=runas)
|
||||
changes['new'] = 'Set password.\n'
|
||||
else:
|
||||
log.debug('Password for %s is not set - Clearing password',
|
||||
name)
|
||||
if __opts__['test']:
|
||||
ret['comment'] = ('User {0}\'s password is '
|
||||
'set to be removed'.format(name))
|
||||
return ret
|
||||
|
||||
result = __salt__['rabbitmq.clear_password'](
|
||||
name, runas=runas)
|
||||
changes['old'] += 'Removed password.\n'
|
||||
|
||||
if _check_tags_changes(name, tags):
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] += ('Tags for user {0} '
|
||||
'is set to be changed'.format(name))
|
||||
return ret
|
||||
result.update(__salt__['rabbitmq.set_user_tags'](
|
||||
name, tags, runas=runas)
|
||||
)
|
||||
changes['new'] += 'Set tags: {0}\n'.format(tags)
|
||||
|
||||
if _check_perms_changes(name, perms):
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] += ('Permissions for user {0} '
|
||||
'is set to be changed'.format(name))
|
||||
return ret
|
||||
for vhost_perm in perms:
|
||||
for vhost, perm in vhost_perm.iteritems():
|
||||
result.update(__salt__['rabbitmq.set_permissions'](
|
||||
vhost, name, perm[0], perm[1], perm[2], runas)
|
||||
)
|
||||
|
@ -109,27 +170,6 @@ def present(name,
|
|||
'Set permissions {0} for vhost {1}'
|
||||
).format(perm, vhost)
|
||||
|
||||
if not user_exists:
|
||||
log.debug(
|
||||
"User doesn't exist - Creating")
|
||||
result = __salt__['rabbitmq.add_user'](
|
||||
name, password, runas=runas)
|
||||
|
||||
_set_tags_and_perms(tags, perms)
|
||||
else:
|
||||
log.debug('RabbitMQ user exists and force is set - Overriding')
|
||||
if password is not None:
|
||||
result = __salt__['rabbitmq.change_password'](
|
||||
name, password, runas=runas)
|
||||
changes['new'] = 'Set password.\n'
|
||||
else:
|
||||
log.debug('Password is not set - Clearing password')
|
||||
result = __salt__['rabbitmq.clear_password'](
|
||||
name, runas=runas)
|
||||
changes['old'] += 'Removed password.\n'
|
||||
|
||||
_set_tags_and_perms(tags, perms)
|
||||
|
||||
if 'Error' in result:
|
||||
ret['result'] = False
|
||||
ret['comment'] = result['Error']
|
||||
|
|
|
@ -98,9 +98,9 @@ def present(name,
|
|||
vhost_exists = __salt__['rabbitmq.vhost_exists'](name, runas=runas)
|
||||
|
||||
if vhost_exists:
|
||||
perms = __salt__['rabbitmq.list_permissions'](name, runas=runas)
|
||||
for perm in perms:
|
||||
if perm == [owner, conf, write, read]:
|
||||
owner_perms = __salt__['rabbitmq.list_permissions'](name, runas=runas)
|
||||
for eowner, eperms in owner_perms.iteritem():
|
||||
if eowner == owner and eperms == [conf, write, read]:
|
||||
ret['comment'] = 'Nothing to do'
|
||||
return ret
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue