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:
Nicole Thomas 2015-05-27 09:05:01 -06:00
commit b9507d1567
10 changed files with 170 additions and 120 deletions

View file

@ -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)

View file

@ -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>`

View file

@ -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.*

View file

@ -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

View file

@ -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):

View file

@ -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}}

View file

@ -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,

View file

@ -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:

View file

@ -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']

View file

@ -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