Merge remote-tracking branch 'upstream/2015.5' into merge-forward-develop2

Conflicts:
    doc/_themes/saltstack2/layout.html
    doc/conf.py
    doc/index.rst
    doc/ref/modules/all/salt.modules.hipchat.rst
    doc/topics/releases/index.rst
    salt/client/ssh/client.py
    salt/cloud/clouds/vsphere.py
    salt/modules/boto_dynamodb.py
    salt/modules/boto_route53.py
    salt/modules/data.py
    salt/modules/http.py
    salt/modules/tls.py
    salt/output/compact.py
    salt/states/boto_elb.py
    salt/states/linux_acl.py
    salt/states/rabbitmq_user.py
    salt/states/win_servermanager.py
    salt/utils/dictupdate.py
    salt/wheel/config.py
This commit is contained in:
Colton Myers 2015-05-29 15:10:13 -06:00
commit c4f5e231fa
64 changed files with 1238 additions and 501 deletions

View file

@ -53,10 +53,10 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '{{ url_root }}',
VERSION: '{{ release|e }}',
SEARCH_CX: '{{ search_cx }}',
SEARCH_CX: '{{ search_cx }}',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
HAS_SOURCE: {{ has_source|lower }}
HAS_SOURCE: '{{ has_source|lower }}'
};
</script>
{%- for scriptfile in script_files %}

View file

@ -44,6 +44,7 @@ class Mock(object):
MOCK_MODULES = [
# salt core
'Crypto',
'Crypto.Signature',
'Crypto.Cipher',
'Crypto.Hash',
'Crypto.PublicKey',
@ -161,7 +162,7 @@ project = 'Salt'
copyright = '2015 SaltStack, Inc.'
version = salt.version.__version__
latest_release = '2015.5.0' # latest release
latest_release = '2015.5.1' # latest release
previous_release = '2014.7.6' # latest release from previous branch
previous_release_dir = '2014.7' # path on web server for previous branch
build_type = 'develop' # latest, previous, develop

View file

@ -14,9 +14,15 @@ Salt Table of Contents
topics/reactor/index
topics/mine/index
topics/eauth/index
topics/eauth/access_control
topics/jobs/index
topics/jobs/job_cache
topics/sdb/index
topics/event/index
topics/beacons/index
topics/ext_processes/index
topics/topology/index
topics/transports/raet/index
topics/windows/index
topics/cloud/index
topics/netapi/index

View file

@ -42,18 +42,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

@ -472,7 +472,7 @@ And in the map file:
.. note::
In the cloud profile that uses this provider configuration, the syntax for the
``provider`` required field would be ``provdier: devhost10-lxc`.
``provider`` required field would be ``provider: devhost10-lxc``.
.. _config_saltify:

View file

@ -16,9 +16,9 @@ provider, that provider must be specified.
There are three universal salt-cloud functions that are extremely useful for
gathering information about instances on a provider basis:
*``list_nodes``: Returns some general information about the instances for the given provider.
*``list_nodes_full``: Returns all information about the instances for the given provider.
*``list_nodes_select``: Returns select information about the instances for the given provider.
* ``list_nodes``: Returns some general information about the instances for the given provider.
* ``list_nodes_full``: Returns all information about the instances for the given provider.
* ``list_nodes_select``: Returns select information about the instances for the given provider.
.. code-block:: bash

View file

@ -60,7 +60,7 @@ If supported by the cloud provider, a PowerShell script may be used to open up
this port automatically, using the cloud provider's `userdata`. The following
script would open up port 445, and apply the changes:
.. code-block:: other
.. code-block:: powershell
<powershell>
New-NetFirewallRule -Name "SMB445" -DisplayName "SMB445" -Protocol TCP -LocalPort 445

View file

@ -87,8 +87,8 @@ Fork a Repo Guide_>`_ and is well worth reading.
# modified: path/to/file2
If you get stuck `there are many introductory Git resources on
help.github.com <Git resources_>`_.
If you get stuck, there are many introductory Git resources on
http://help.github.com.
#. Push your locally-committed changes to your GitHub fork,

View file

@ -1,8 +1,11 @@
raet
====
# RAET
# Reliable Asynchronous Event Transport Protocol
.. seealso:: :ref:`RAET Overview <raet>`
Protocol
--------
@ -266,4 +269,4 @@ Receiver Side:
Duplicate detection save transaction id duplicate detection timeout
Request resend of missing packet in sequence
Sequence reordering with escrow timeout wait escrow before requesting resend
Unsegmentation (request resends of missing segment)
Unsegmentation (request resends of missing segment)

View file

@ -15,7 +15,7 @@ Processes started in this way will be restarted if they die and will be
killed when the Salt Master is shut down.
Example Configureation
Example Configuration
======================
Processes are declared in the master config file with the `ext_processes`
@ -56,4 +56,4 @@ Example Process Class
while True:
self.event.fire_event({'iteration': i}, 'ext_processes/test{0}')
time.sleep(60)
time.sleep(60)

View file

@ -2,7 +2,7 @@
Salt 2014.7.5 Release Notes
===========================
:release: TBA
:release: 2015-04-16
Version 2014.7.5 is a bugfix release for :doc:`2014.7.0
</topics/releases/2014.7.0>`.
@ -19,7 +19,7 @@ Changes:
- Fixed malformed locale string in localmod module
- Fixed checking of available version of package when accept_keywords were changed
- Fixed bug to make git.latest work with empty repositories
- Added **kwargs to service.mod_watch which removes warnings about `enable` and `__reqs__` not being supported by the function
- Added \*\*kwargs to service.mod_watch which removes warnings about `enable` and `__reqs__` not being supported by the function
- Improved state comments to not grow so quickly on failed requisites
- Added force argument to service to trigger force_reload
- Fixed bug to andle pkgrepo keyids that have been converted to int

View file

@ -2,7 +2,7 @@
Salt 2015.5.1 Release Notes
===========================
:release: TBA
:release: 2015-05-20
Version 2015.5.1 is a bugfix release for :doc:`2015.5.0
</topics/releases/2015.5.0>`.
@ -14,117 +14,103 @@ Changes:
Extended Changelog Courtesy of Todd Stansell (https://github.com/tjstansell/salt-changelogs):
- **PR** `#23989`_: (*rallytime*) Backport `#23980`_ to 2015.5
**PR** `#23989`_: (*rallytime*) Backport `#23980`_ to 2015.5
@ *2015-05-20T19:33:41Z*
- **PR** `#23980`_: (*iggy*) template: jinja2 -> jinja
| refs: `#23989`_
* **PR** `#23980`_: (*iggy*) template: jinja2 -> jinja | refs: `#23989`_
* 117ecb1 Merge pull request `#23989`_ from rallytime/`bp-23980`_
* 8f8557c template: jinja2 -> jinja
- **PR** `#23988`_: (*rallytime*) Backport `#23977`_ to 2015.5
**PR** `#23988`_: (*rallytime*) Backport `#23977`_ to 2015.5
@ *2015-05-20T19:13:36Z*
- **PR** `#23977`_: (*ionutbalutoiu*) Fixed glance image_create
| refs: `#23988`_
* **PR** `#23977`_: (*ionutbalutoiu*) Fixed glance image_create | refs: `#23988`_
* d4f1ba0 Merge pull request `#23988`_ from rallytime/`bp-23977`_
* 46fc7c6 Fixed glance image_create
- **PR** `#23986`_: (*basepi*) [2015.5] Merge forward from 2014.7 to 2015.5
**PR** `#23986`_: (*basepi*) [2015.5] Merge forward from 2014.7 to 2015.5
@ *2015-05-20T18:41:33Z*
- **PR** `#23965`_: (*hvnsweeting*) handle all exceptions gitpython can raise
* **PR** `#23965`_: (*hvnsweeting*) handle all exceptions gitpython can raise
* 9566e7d Merge pull request `#23986`_ from basepi/merge-forward-2015.5
* 0b78156 Merge remote-tracking branch 'upstream/2014.7' into merge-forward-2015.5
* 314e4db Merge pull request `#23965`_ from hvnsweeting/20147-fix-gitfs-gitpython-exception
* 2576301 handle all exception gitpython can raise
* 314e4db Merge pull request `#23965`_ from hvnsweeting/20147-fix-gitfs-gitpython-exception
* 2576301 handle all exception gitpython can raise
- **PR** `#23985`_: (*UtahDave*) Add 2014.7.5-2 and 2015.5.0-2 Windows installer download links
**PR** `#23985`_: (*UtahDave*) Add 2014.7.5-2 and 2015.5.0-2 Windows installer download links
@ *2015-05-20T18:32:44Z*
* 9d1130e Merge pull request `#23985`_ from UtahDave/2015.5local
* 10338d0 Add links to Windows 2015.5.0-2 install downloads
* b84f975 updated Windows 2014.7.5-2 installer download link
- **PR** `#23983`_: (*rallytime*) Versionadded tags for https_user and https_pass args new in 2015.5.0
**PR** `#23983`_: (*rallytime*) Versionadded tags for https_user and https_pass args new in 2015.5.0
@ *2015-05-20T18:05:27Z*
* ca7729d Merge pull request `#23983`_ from rallytime/versionadded_git_options
* 14eae22 Versionadded tags for https_user and https_pass args new in 2015.5.0
- **PR** `#23970`_: (*jayeshka*) adding system unit test case
**PR** `#23970`_: (*jayeshka*) adding system unit test case
@ *2015-05-20T17:12:57Z*
* b06df57 Merge pull request `#23970`_ from jayeshka/system-unit-test
* 89eb008 adding system unit test case
- **PR** `#23967`_: (*jayeshka*) adding states/memcached unit test case
**PR** `#23967`_: (*jayeshka*) adding states/memcached unit test case
@ *2015-05-20T17:12:26Z*
* 38d5f75 Merge pull request `#23967`_ from jayeshka/memcached-states-unit-test
* 8ef9240 adding states/memcached unit test case
- **PR** `#23966`_: (*jayeshka*) adding states/modjk unit test case
**PR** `#23966`_: (*jayeshka*) adding states/modjk unit test case
@ *2015-05-20T17:11:48Z*
* 868e807 Merge pull request `#23966`_ from jayeshka/modjk-states-unit-test
* 422a964 adding states/modjk unit test case
- **PR** `#23942`_: (*jacobhammons*) Updates to sphinx saltstack2 doc theme
**PR** `#23942`_: (*jacobhammons*) Updates to sphinx saltstack2 doc theme
@ *2015-05-20T15:43:54Z*
* 6316490 Merge pull request `#23942`_ from jacobhammons/2015.5
* 31023c8 Updates to sphinx saltstack2 doc theme
- **PR** `#23874`_: (*joejulian*) Validate keyword arguments to be valid
**PR** `#23874`_: (*joejulian*) Validate keyword arguments to be valid
@ *2015-05-20T04:53:40Z*
- **ISSUE** `#23872`_: (*joejulian*) create_ca_signed_cert can error if dereferenced dict is used for args
| refs: `#23874`_
* **ISSUE** `#23872`_: (*joejulian*) create_ca_signed_cert can error if dereferenced dict is used for args | refs: `#23874`_
* 587957b Merge pull request `#23874`_ from joejulian/2015.5_tls_validate_kwargs
* 30102ac Fix py3 and ordering inconsistency problems.
* 493f7ad Validate keyword arguments to be valid
- **PR** `#23960`_: (*rallytime*) Backport `#22114`_ to 2015.5
**PR** `#23960`_: (*rallytime*) Backport `#22114`_ to 2015.5
@ *2015-05-20T04:37:09Z*
- **PR** `#22114`_: (*dmyerscough*) Fixing KeyError when there are no additional pages
| refs: `#23960`_
* **PR** `#22114`_: (*dmyerscough*) Fixing KeyError when there are no additional pages | refs: `#23960`_
* 00c5c22 Merge pull request `#23960`_ from rallytime/`bp-22114`_
* f3e1d63 Catch KeyError
* 306b1ea Fixing KeyError
* 6b2cda2 Fix PEP8 complaint
* 239e50f Fixing KeyError when there are no additional pages
- **PR** `#23961`_: (*rallytime*) Backport `#23944`_ to 2015.5
**PR** `#23961`_: (*rallytime*) Backport `#23944`_ to 2015.5
@ *2015-05-20T04:35:41Z*
- **PR** `#23944`_: (*ryan-lane*) Add missing loginclass argument to _changes call
| refs: `#23961`_
* **PR** `#23944`_: (*ryan-lane*) Add missing loginclass argument to _changes call | refs: `#23961`_
* 4648b46 Merge pull request `#23961`_ from rallytime/`bp-23944`_
* 970d19a Add missing loginclass argument to _changes call
- **PR** `#23948`_: (*jfindlay*) augeas.change state now returns changes as a dict
**PR** `#23948`_: (*jfindlay*) augeas.change state now returns changes as a dict
@ *2015-05-20T04:00:10Z*
* 0cb5cd3 Merge pull request `#23948`_ from jfindlay/augeas_changes
* f09b80a augeas.change state now returns changes as a dict
- **PR** `#23957`_: (*rallytime*) Backport `#23951`_ to 2015.5
**PR** `#23957`_: (*rallytime*) Backport `#23951`_ to 2015.5
@ *2015-05-20T03:04:24Z*
- **PR** `#23951`_: (*ryan-lane*) Do not check perms in file.copy if preserve
| refs: `#23957`_
* **PR** `#23951`_: (*ryan-lane*) Do not check perms in file.copy if preserve | refs: `#23957`_
* 2d185f7 Merge pull request `#23957`_ from rallytime/`bp-23951`_
* 996b431 Update file.py
* 85d461f Do not check perms in file.copy if preserve
- **PR** `#23956`_: (*rallytime*) Backport `#23906`_ to 2015.5

View file

@ -1,3 +1,5 @@
.. _raet:
==================
The RAET Transport
==================
@ -135,3 +137,8 @@ externally developed cryptography system.
For more information on libsodium and CurveCP please see:
http://doc.libsodium.org/
http://curvecp.org/
Programming Intro
=================
:ref:`Raet Programming Introduction <raet-programming>`

View file

@ -1,3 +1,5 @@
.. _raet_programming:
=========================
Intro to RAET Programming
=========================

View file

@ -48,6 +48,8 @@ Advanced Topics
gitfs
walkthrough_macosx
writing_tests
http
lxc
Salt Virt
==========

View file

@ -249,6 +249,7 @@ Section -Post
WriteRegStr HKLM "SYSTEM\CurrentControlSet\services\salt-minion" "DependOnService" "nsi"
ExecWait "nssm.exe install salt-minion $INSTDIR\bin\python.exe $INSTDIR\bin\Scripts\salt-minion -c $INSTDIR\conf -l quiet"
ExecWait "nssm.exe set salt-minion AppEnvironmentExtra PYTHONHOME="
RMDir /R "$INSTDIR\var\cache\salt" ; removing cache from old version
Call updateMinionConfig

View file

@ -53,18 +53,17 @@ def _enqueue(revent):
'''
Enqueue the event
'''
__context__['inotify.que'].append(revent)
__context__['inotify.queue'].append(revent)
def _get_notifier():
'''
Check the context for the notifier and construct it if not present
'''
if 'inotify.notifier' in __context__:
return __context__['inotify.notifier']
__context__['inotify.que'] = collections.deque()
wm = pyinotify.WatchManager()
__context__['inotify.notifier'] = pyinotify.Notifier(wm, _enqueue)
if 'inotify.notifier' not in __context__:
__context__['inotify.queue'] = collections.deque()
wm = pyinotify.WatchManager()
__context__['inotify.notifier'] = pyinotify.Notifier(wm, _enqueue)
return __context__['inotify.notifier']
@ -152,56 +151,55 @@ def beacon(config):
recurse: True
auto_add: True
The mask list can contain options:
* access File was accessed
* attrib Metadata changed
* close_nowrite Unwrittable file closed
* close_write Writtable file was closed
* create File created
* delete File deleted
* delete_self Named file or directory deleted
* excl_unlink
* ignored
* modify File was modified
* moved_from File being watched was moved
* moved_to File moved into watched area
* move_self Named file was moved
* oneshot
The mask list can contain the following events (the default mask is create,
delete, and modify):
* access File accessed
* attrib File metadata changed
* close_nowrite Unwritable file closed
* close_write Writable file closed
* create File created in watched directory
* delete File deleted from watched directory
* delete_self Watched file or directory deleted
* modify File modified
* moved_from File moved out of watched directory
* moved_to File moved into watched directory
* move_self Watched file moved
* open File opened
The mask can also contain the following options:
* dont_follow Don't dereference symbolic links
* excl_unlink Omit events for children after they have been unlinked
* oneshot Remove watch after one event
* onlydir Operate only if name is directory
* open File was opened
* unmount Backing fs was unmounted
recurse:
Tell the beacon to recursively watch files in the directory
Recursively watch files in the directory
auto_add:
Automatically start adding files that are created in the watched directory
Automatically start watching files that are created in the watched directory
'''
ret = []
notifier = _get_notifier()
wm = notifier._watch_manager
# Read in existing events
# remove watcher files that are not in the config
# update all existing files with watcher settings
# return original data
if notifier.check_events(1):
notifier.read_events()
notifier.process_events()
while __context__['inotify.que']:
sub = {}
event = __context__['inotify.que'].popleft()
sub['tag'] = event.path
sub['path'] = event.pathname
sub['change'] = event.maskname
queue = __context__['inotify.queue']
while queue:
event = queue.popleft()
sub = {'tag': event.path,
'path': event.pathname,
'change': event.maskname}
ret.append(sub)
# Get paths currently being watched
current = set()
for wd in wm.watches:
current.add(wm.watches[wd].path)
need = set(config)
for path in current.difference(need):
# These need to be removed
for wd in wm.watches:
if path == wm.watches[wd].path:
wm.rm_watch(wd)
# Update existing watches and add new ones
# TODO: make the config handle more options
for path in config:
if isinstance(config[path], dict):
mask = config[path].get('mask', DEFAULT_MASK)
@ -220,14 +218,8 @@ def beacon(config):
mask = DEFAULT_MASK
rec = False
auto_add = False
# TODO: make the config handle more options
if path not in current:
wm.add_watch(
path,
mask,
rec=rec,
auto_add=auto_add)
else:
if path in current:
for wd in wm.watches:
if path == wm.watches[wd].path:
update = False
@ -236,9 +228,9 @@ def beacon(config):
if wm.watches[wd].auto_add != auto_add:
update = True
if update:
wm.update_watch(
wd,
mask=mask,
rec=rec,
auto_add=auto_add)
wm.update_watch(wd, mask=mask, rec=rec, auto_add=auto_add)
else:
wm.add_watch(path, mask, rec=rec, auto_add=auto_add)
# Return event data
return ret

View file

@ -48,18 +48,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(six.iterkeys(ret))
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):
@ -115,7 +110,11 @@ class Batch(object):
else:
for i in range(bnum - len(active)):
if to_run:
next_.append(to_run.pop())
minion_id = to_run.pop()
if isinstance(minion_id, dict):
next_.append(minion_id.keys()[0])
else:
next_.append(minion_id)
active += next_
args[0] = next_

View file

@ -398,8 +398,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': {...}}
@ -629,13 +629,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}}
@ -655,9 +655,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
@ -674,19 +674,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}}
@ -708,9 +710,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
@ -863,6 +866,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
@ -1035,7 +1039,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

@ -18,7 +18,7 @@ class SSHClient(object):
'''
Create a client object for executing routines via the salt-ssh backend
.. versionadded:: 2015.2
.. versionadded:: 2015.5.0
'''
def __init__(self,
c_path=os.path.join(syspaths.CONFIG_DIR, 'master'),
@ -72,7 +72,7 @@ class SSHClient(object):
Execute a single command via the salt-ssh subsystem and return a
generator
.. versionadded:: 2015.2
.. versionadded:: 2015.5.0
'''
ssh = self._prep_ssh(
tgt,
@ -98,7 +98,7 @@ class SSHClient(object):
Execute a single command via the salt-ssh subsystem and return all
routines at once
.. versionadded:: 2015.2
.. versionadded:: 2015.5.0
'''
ssh = self._prep_ssh(
tgt,
@ -117,7 +117,7 @@ class SSHClient(object):
'''
Execute a salt-ssh call synchronously.
.. versionadded:: 2015.2
.. versionaddedd:: 2015.5.0
WARNING: Eauth is **NOT** respected

View file

@ -1901,6 +1901,8 @@ class ClearFuncs(object):
'Authentication failure of type "user" occurred.'
)
return ''
elif clear_load.get('key', 'invalid') == self.key.get('root'):
clear_load.pop('key')
else:
if clear_load['user'] in self.key:
# User is authorised, check key and check perms

View file

@ -818,7 +818,7 @@ class Minion(MinionBase):
try:
beacons = self.process_beacons(self.functions)
except Exception as exc:
log.critical('Beacon processing errored: {0}. No beacons will be procssed.'.format(traceback.format_exc(exc)))
log.critical('Beacon processing failed: {0}. No beacons will be processed.'.format(traceback.format_exc(exc)))
beacons = None
if beacons:
self._fire_master(events=beacons)

View file

@ -30,7 +30,7 @@ Connection module for Amazon DynamoDB
If a region is not specified, the default is us-east-1.
It's also possible to specify key, keyid and region via a profile, either
as a passed in dict, or as a string to pull from pillars or minion config:
as a passed in dict, or as a string to pull from pillars or minion config::
.. code-block:: yaml

View file

@ -165,6 +165,14 @@ def delete_zone(zone, region=None, key=None, keyid=None, profile=None):
return False
def _encode_name(name):
return name.replace('*', r'\052')
def _decode_name(name):
return name.replace(r'\052', '*')
def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
keyid=None, profile=None, split_dns=False, private_zone=False):
'''
@ -190,6 +198,7 @@ def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
if not _is_valid_resource(_type):
return None
name = _encode_name(name)
if _type == 'A':
_record = _zone.get_a(name, fetch_all)
elif _type == 'CNAME':
@ -198,7 +207,7 @@ def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
_record = _zone.get_mx(name, fetch_all)
if _record:
ret['name'] = _record.name
ret['name'] = _decode_name(_record.name)
ret['value'] = _record.to_print()
ret['record_type'] = _record.type
ret['ttl'] = _record.ttl

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
'''
A module for shelling out
A module for shelling out.
Keep in mind that this module is insecure, in that it can give whomever has
access to the master root execution access to all salt minions.

View file

@ -596,17 +596,13 @@ def _parse_interfaces(interface_files=None):
iface_dict['ethtool'][attr] = valuestr
elif attr.startswith('bond'):
if '-' in attr:
opt = attr.split('-', 1)[1]
elif '_' in attr:
# Just in case configuration still has bond_
opt = attr.split('_', 1)[1]
opt = re.split(r'[_-]', attr, maxsplit=1)[1]
if 'bonding' not in iface_dict:
iface_dict['bonding'] = salt.utils.odict.OrderedDict()
iface_dict['bonding'][opt] = valuestr
elif attr.startswith('bridge'):
opt = attr.split('-', 1)[1]
opt = re.split(r'[_-]', attr, maxsplit=1)[1]
if 'bridging' not in iface_dict:
iface_dict['bridging'] = salt.utils.odict.OrderedDict()
iface_dict['bridging'][opt] = valuestr

View file

@ -158,7 +158,8 @@ def gid_to_group(gid):
try:
return grp.getgrgid(gid).gr_name
except (KeyError, NameError):
return ''
# If group is not present, fall back to the gid.
return gid
def group_to_gid(group):
@ -245,7 +246,8 @@ def uid_to_user(uid):
try:
return pwd.getpwuid(uid).pw_name
except (KeyError, NameError):
return ''
# If user is not present, fall back to the uid.
return uid
def user_to_uid(user):

View file

@ -6,7 +6,6 @@ from keyservers. Sign, encrypt and sign & encrypt text and files.
.. versionadded:: 2015.5.0
.. note::
The ``python-gnupg`` library and gpg binary are
required to be installed.

View file

@ -15,7 +15,7 @@ def query(url, **kwargs):
'''
Query a resource, and decode the return data
.. versionadded:: 2015.2
.. versionadded:: 2015.5.0
CLI Example:
@ -34,7 +34,7 @@ def update_ca_bundle(target=None, source=None, merge_files=None):
'''
Update the local CA bundle file from a URL
.. versionadded:: 2015.2
.. versionadded:: 2015.5.0
CLI Example:

View file

@ -81,9 +81,13 @@ __opts__ = {}
def auth(profile=None, **connection_args):
'''
Set up keystone credentials
Set up keystone credentials. Only intended to be used within Keystone-enabled modules.
Only intended to be used within Keystone-enabled modules
CLI Example:
.. code-block:: bash
salt '*' keystone.auth
'''
if profile:
@ -337,7 +341,9 @@ def endpoint_delete(service, profile=None, **connection_args):
def role_create(name, profile=None, **connection_args):
'''
Create named role
Create a named role.
CLI Example:
.. code-block:: bash

View file

@ -240,6 +240,7 @@ def disable(message=None):
salt '*' puppet.disable
salt '*' puppet.disable 'disabled for a good reason'
'''
_check_puppet()

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

@ -105,7 +105,7 @@ import logging
import hashlib
import salt.utils
from salt._compat import string_types
from salt.ext.six.moves import range
from salt.ext.six.moves import range as _range
from datetime import datetime
from distutils.version import LooseVersion
@ -1174,7 +1174,6 @@ def create_ca_signed_cert(ca_name,
The CN *must* match an existing CSR generated by create_csr. If it
does not, this method does nothing.
ca_name
name of the CA
CN
@ -1338,7 +1337,7 @@ def create_ca_signed_cert(ca_name,
native_exts_obj = OpenSSL._util.lib.X509_REQ_get_extensions(
req._req)
for i in range(OpenSSL._util.lib.sk_X509_EXTENSION_num(
for i in _range(OpenSSL._util.lib.sk_X509_EXTENSION_num(
native_exts_obj)):
ext = OpenSSL.crypto.X509Extension.__new__(
OpenSSL.crypto.X509Extension)
@ -1513,7 +1512,7 @@ def cert_info(cert_path, digest='sha256'):
# add additional info if your version of pyOpenSSL supports it
if hasattr(cert, 'get_extension_count'):
ret['extensions'] = {}
for i in range(cert.get_extension_count()):
for i in _range(cert.get_extension_count()):
ext = cert.get_extension(i)
ret['extensions'][ext.get_short_name()] = ext

View file

@ -302,7 +302,7 @@ class PyWinUpdater(object):
if update.InstallationBehavior.CanRequestUserInput:
log.debug('Skipped update {0}'.format(str(update)))
continue
updates.append(str(update))
updates.append(salt.utils.sdecode(update))
log.debug('added update {0}'.format(str(update)))
return updates

View file

@ -17,7 +17,6 @@ import sys
# Import Salt libs
import salt.utils
import salt.utils.decorators as decorators
import salt.modules.cmdmod as salt_cmd
log = logging.getLogger(__name__)
@ -45,7 +44,7 @@ def _available_commands():
return False
ret = {}
res = salt_cmd.run_stderr(
res = __salt__['cmd.run_stderr'](
'{0} -?'.format(zfs_path),
output_loglevel='trace',
ignore_retcode=True
@ -78,12 +77,20 @@ def __virtual__():
'''
Makes sure that ZFS kernel module is loaded.
'''
kernel_module_chk = {
'FreeBSD': 'kldstat -q -m zfs',
'Linux': 'modinfo zfs',
}
cmd = kernel_module_chk.get(__grains__['kernel'], '')
if cmd and salt_cmd.retcode(cmd, output_loglevel='quiet') == 0:
on_freebsd = __grains__['kernel'] == 'FreeBSD'
on_linux = __grains__['kernel'] == 'Linux'
cmd = ''
if on_freebsd:
cmd = 'kldstat -q -m zfs'
elif on_linux:
modinfo = salt.utils.which('modinfo')
if modinfo:
cmd = '{0} zfs'.format(modinfo)
else:
cmd = 'ls /sys/module/zfs'
if cmd and __salt__['cmd.retcode'](cmd, output_loglevel='quiet') == 0:
# Build dynamic functions and allow loading module
_build_zfs_cmd_list()
return 'zfs'
@ -108,7 +115,7 @@ def _make_function(cmd_name, doc):
ret = {}
# Run the command.
res = salt_cmd.run_all(
res = __salt__['cmd.run_all'](
'{0} {1} {2}'.format(
_check_zfs(),
cmd_name,

View file

@ -14,6 +14,9 @@ A REST API for Salt
CherryPy milestone 3.3, but the patch was committed for version 3.6.1.
- salt-api package
:optdepends: - ws4py Python module for websockets support.
:client_libraries:
- Java: https://github.com/SUSE/saltstack-netapi-client-java
- Python: https://github.com/saltstack/pepper
:configuration: All authentication is done through Salt's :ref:`external auth
<acl-eauth>` system which requires additional configuration not described
here.

View file

@ -3,10 +3,8 @@
Display compact output data structure
=====================================
Example output::
'saltdev': {'test_|-always-passes_|-foo_|-succeed_without_changes': {'comment': 'Success!', 'name': 'foo', 'start_time': '05:16:26.111814', 'result': True, 'duration': 1, '__run_num__': 0, 'changes': {}}, 'test_|-my-custom-combo_|-foo_|-configurable_test_state': {'comment': 'bar.baz', 'name': 'foo', 'start_time': '05:16:26.117177', 'result': False, 'duration': 1, '__run_num__': 4, 'changes': {'testing': {'new': 'Something pretended to change', 'old': 'Unchanged'}}}, 'test_|-always-fails_|-foo_|-fail_without_changes': {'comment': 'Failure!', 'name': 'foo', 'start_time': '05:16:26.113124', 'result': False, 'duration': 1, '__run_num__': 1, 'changes': {}}, 'test_|-always-changes-and-succeeds_|-foo_|-succeed_with_changes': {'comment': 'Success!', 'name': 'foo', 'start_time': '05:16:26.114570', 'result': True, 'duration': 0, '__run_num__': 2, 'changes': {'testing': {'new': 'Something pretended to change', 'old': 'Unchanged'}}}, 'test_|-always-changes-and-fails_|-foo_|-fail_with_changes': {'comment': 'Failure!', 'name': 'foo', 'start_time': '05:16:26.115561', 'result': False, 'duration': 1, '__run_num__': 3, 'changes': {'testing': {'new': 'Something pretended to change', 'old': 'Unchanged'}}}}}
{'myminion': {'foo': {'list': ['Hello', 'World'], 'bar': 'baz', 'dictionary': {'abc': 123, 'def': 456}}}}
'saltdev': {'test_|-always-passes_|-foo_|-succeed_without_changes': {'comment': 'Success!', 'name': 'foo', 'start_time': '05:16:26.111814', 'result': True, 'duration': 1, '__run_num__': 0, 'changes': {}}, 'test_|-my-custom-combo_|-foo_|-configurable_test_state': {'comment': 'bar.baz', 'name': 'foo', 'start_time': '05:16:26.117177', 'result': False, 'duration': 1, '__run_num__': 4, 'changes': {'testing': {'new': 'Something pretended to change', 'old': 'Unchanged'}}}, 'test_|-always-fails_|-foo_|-fail_without_changes': {'comment': 'Failure!', 'name': 'foo', 'start_time': '05:16:26.113124', 'result': False, 'duration': 1, '__run_num__': 1, 'changes': {}}, 'test_|-always-changes-and-succeeds_|-foo_|-succeed_with_changes': {'comment': 'Success!', 'name': 'foo', 'start_time': '05:16:26.114570', 'result': True, 'duration': 0, '__run_num__': 2, 'changes': {'testing': {'new': 'Something pretended to change', 'old': 'Unchanged'}}}, 'test_|-always-changes-and-fails_|-foo_|-fail_with_changes': {'comment': 'Failure!', 'name': 'foo', 'start_time': '05:16:26.115561', 'result': False, 'duration': 1, '__run_num__': 3, 'changes': {'testing': {'new': 'Something pretended to change', 'old': 'Unchanged'}}}}}{'myminion': {'foo': {'list': ['Hello', 'World'], 'bar': 'baz', 'dictionary': {'abc': 123, 'def': 456}}}}
'''
from __future__ import absolute_import

View file

@ -9,14 +9,14 @@ share your pillar data with others that you trust. I dont advise making your pil
regardless if they are encrypted or not.
The following configurations can be defined in the master config
so your users can create encrypted passwords using the runner nacl.
so your users can create encrypted passwords using the runner nacl::
cat /etc/salt/master.d/nacl.conf
nacl.config:
key: None
keyfile: /root/.nacl
Now with the config in the master you can use the runner nacl like:
Now with the config in the master you can use the runner nacl like::
salt-run nacl.enc 'data'

View file

@ -2983,7 +2983,8 @@ class BaseHighState(object):
try:
top = self.get_top()
except SaltRenderError as err:
ret[tag_name]['comment'] = err.error
ret[tag_name]['comment'] = 'Unable to render top file: '
ret[tag_name]['comment'] += err.error
return ret
except Exception:
trb = traceback.format_exc()

View file

@ -322,14 +322,31 @@ def present(
ret['result'] = _ret['result']
if ret['result'] is False:
return ret
_ret = _cnames_present(name, cnames, region, key, keyid, profile,
wait_for_sync)
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
ret['comment'] = ' '.join([ret['comment'], _ret['comment']])
if not _ret['result']:
ret['result'] = _ret['result']
if ret['result'] is False:
return ret
if cnames:
lb = __salt__['boto_elb.get_elb_config'](
name, region, key, keyid, profile
)
for cname in cnames:
_ret = __salt__['state.single'](
'boto_route53.present',
name=cname.get('name'),
value=lb['dns_name'],
zone=cname.get('zone'),
record_type='CNAME',
identifier=cname.get('identifier', None),
ttl=cname.get('ttl', None),
region=region,
key=key,
keyid=keyid,
profile=profile
)
_ret = _ret.values()[0]
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
ret['comment'] = ' '.join([ret['comment'], _ret['comment']])
if not _ret['result']:
ret['result'] = _ret['result']
if ret['result'] is False:
return ret
_ret = _alarms_present(name, alarms, alarms_from_pillar, region, key, keyid, profile)
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
ret['comment'] = ' '.join([ret['comment'], _ret['comment']])
@ -866,109 +883,6 @@ def _subnets_present(
return ret
def _cnames_present(
name,
cnames,
region,
key,
keyid,
profile,
wait_for_sync):
ret = {'result': True, 'comment': '', 'changes': {}}
if not cnames:
cnames = []
lb = __salt__['boto_elb.get_elb_config'](name, region, key, keyid, profile)
if not lb:
if not __opts__['test']:
ret['result'] = False
msg = 'Failed to retrieve ELB {0}.'.format(name)
ret['comment'] = msg
return ret
to_create = []
to_update = []
for cname in cnames:
_name = cname.get('name', None)
_zone = cname.get('zone', None)
if not _name or not _zone:
raise SaltInvocationError('cnames must provide name and zone'
' attributes.')
record = __salt__['boto_route53.get_record'](_name, _zone, 'CNAME',
False, region, key,
keyid, profile)
if not record:
to_create.append(cname)
elif record['value'].rstrip('.') != lb['dns_name'].rstrip('.'):
to_update.append(cname)
if to_create or to_update:
if __opts__['test']:
msg = 'ELB {0} to have cnames modified.'.format(name)
ret['comment'] = msg
ret['result'] = None
return ret
if to_create:
created = []
not_created = []
for cname in to_create:
_name = cname.get('name')
_zone = cname.get('zone')
_iden = cname.get('identifier', None)
_ttl = cname.get('ttl', None)
_created = __salt__['boto_route53.add_record'](
_name, lb['dns_name'], _zone, 'CNAME', _iden, _ttl, region,
key, keyid, profile)
if _created:
created.append(_name)
else:
not_created.append(_name)
if created:
msg = 'Created cnames {0}.'.format(','.join(created))
ret['comment'] = msg
if not_created:
msg = 'Failed to create cnames {0}.'
msg = msg.format(','.join(not_created))
if 'comment' in ret:
ret['comment'] = ret['comment'] + ' ' + msg
else:
ret['comment'] = msg
ret['result'] = False
if to_update:
updated = []
not_updated = []
for cname in to_update:
_name = cname.get('name')
_zone = cname.get('zone')
_iden = cname.get('identifier', None)
_ttl = cname.get('ttl', None)
_updated = __salt__['boto_route53.update_record'](
_name, lb['dns_name'], _zone, 'CNAME', _iden, _ttl, region,
key, keyid, profile)
if _updated:
updated.append(_name)
else:
not_updated.append(_name)
if updated:
msg = 'Updated cnames {0}.'.format(','.join(updated))
if 'comment' in ret:
ret['comment'] = ret['comment'] + ' ' + msg
else:
ret['comment'] = msg
if not_updated:
msg = 'Failed to update cnames {0}.'
msg = msg.format(','.join(not_updated))
if 'comment' in ret:
ret['comment'] = ret['comment'] + ' ' + msg
else:
ret['comment'] = msg
ret['result'] = False
# We can't track old, since we'd need to know the zone to
# search for the ELB in the value.
ret['changes']['new'] = {'cnames': to_create + to_update}
else:
msg = 'cnames already set on ELB {0}.'.format(name)
ret['comment'] = msg
return ret
def _alarms_present(name, alarms, alarms_from_pillar, region, key, keyid, profile):
'''helper method for present. ensure that cloudwatch_alarms are set'''
# load data from alarms_from_pillar
@ -996,7 +910,7 @@ def _alarms_present(name, alarms, alarms_from_pillar, region, key, keyid, profil
ret = __salt__["state.single"]('boto_cloudwatch_alarm.present', **kwargs)
results = next(six.itervalues(ret))
if not results["result"]:
merged_return_value["result"] = False
merged_return_value["result"] = results["result"]
if results.get("changes", {}) != {}:
merged_return_value["changes"][info["name"]] = results["changes"]
if "comment" in results:

View file

@ -157,9 +157,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
@ -184,7 +183,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

@ -2412,7 +2412,7 @@ def replace(name,
Filesystem path to the file to be edited.
pattern
Python's `regular expression search<https://docs.python.org/2/library/re.html>`_.
Python's `regular expression search <https://docs.python.org/2/library/re.html>`_.
repl
The replacement text.

View file

@ -6,23 +6,23 @@ Ensure a Linux ACL is present
.. code-block:: yaml
root:
acl.present:
- name: /root
- acl_type: users
- acl_name: damian
- perms: rwx
root:
acl.present:
- name: /root
- acl_type: users
- acl_name: damian
- perms: rwx
Ensure a Linux ACL does not exist
.. code-block:: yaml
root:
acl.absent:
- name: /root
- acl_type: user
- acl_name: damian
- perms: rwx
root:
acl.absent:
- name: /root
- acl_type: user
- acl_name: damian
- perms: rwx
'''
# Import Python libs

View file

@ -42,6 +42,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,
@ -70,41 +103,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 six.iteritems(element):
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)
)
@ -112,26 +173,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

@ -50,14 +50,22 @@ def present(name,
.. deprecated:: Beryllium
owner
Initial owner permission to set on the VHost, if present
.. deprecated:: Beryllium
conf
Initial conf string to apply to the VHost and user. Defaults to .*
.. deprecated:: Beryllium
write
Initial write permissions to apply to the VHost and user.
Defaults to .*
.. deprecated:: Beryllium
read
Initial read permissions to apply to the VHost and user.
Defaults to .*
.. deprecated:: Beryllium
runas
Name of the user to run the command
@ -72,38 +80,18 @@ def present(name,
'removed in Salt Beryllium. Ping s0undt3ch for additional '
'information or see #6961.'
)
if user:
# Warn users about the deprecation
if any(user, owner, conf, write, read):
salt.utils.warn_until(
'Beryllium',
'The \'user\' argument is being deprecated in favor of \'owner\', '
'and will be removed in Salt Beryllium. Please update your state '
'files.'
'Passed \'owner\', \'user\', \'conf\', \'write\' or \'read\' '
'arguments. These are being deprecated, and will be removed in '
'Salt Beryllium. Please update your state files, and set '
'permissions for user instead. See rabbitmq_user.present.'
)
if user is not None and owner is not None:
# owner wins over user but let warn about the deprecation.
salt.utils.warn_until(
'Beryllium',
'Passed both the \'owner\' and \'user\' arguments. \'user\' is '
'being ignored in favor of \'owner\' as the \'user\' argument is '
'being deprecated in favor of \'owner\' and will be removed in '
'Salt Beryllium. Please update your state files.'
)
user = None
elif user is not None:
# Support old runas usage
owner = user
user = None
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]:
ret['comment'] = 'Nothing to do'
return ret
if __opts__['test']:
ret['result'] = None
if vhost_exists:
@ -111,17 +99,10 @@ def present(name,
else:
ret['comment'] = 'Creating VHost {0}'.format(name)
if user is not None:
ret['comment'] += (
' Setting permissions for {0} {1} {2} {3}'.format(
owner,
conf or '.*',
write or '.*',
read or '.*'
)
)
else:
if not vhost_exists:
if vhost_exists:
ret['comment'] = 'VHost {0} already exists'.format(name)
else:
result = __salt__['rabbitmq.add_vhost'](name, runas=runas)
if 'Error' in result:
ret['result'] = False
@ -129,21 +110,6 @@ def present(name,
elif 'Added' in result:
ret['comment'] = result['Added']
ret['changes'] = {'old': '', 'new': name}
else:
ret['comment'] = 'VHost {0} already exists'.format(name)
if owner is not None:
conf = conf or '.*'
write = write or '.*'
read = read or '.*'
result = __salt__['rabbitmq.set_permissions'](
name, owner, conf, write, read, runas=runas)
if 'Error' in result:
ret['result'] = False
ret['comment'] = result['Error']
elif 'Permissions Set':
ret['comment'] += ' {0}'.format(result['Permissions Set'])
return ret

View file

@ -17,6 +17,7 @@ This state is useful for sending messages to Slack during state runs.
- api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15
The api key can be specified in the master or minion configuration like below:
.. code-block:: yaml
slack:

View file

@ -83,16 +83,15 @@ def removed(name):
the server is restarted.
Example:
Run ``salt MinionName win_servermanager.list_installed`` to get a list of all features installed. Use the top
Run ``salt MinionName win_servermanager.list_installed`` to get a list of all features installed. Use the top
name listed for each feature, not the indented one. Do not use the role or feature names mentioned in the
PKGMGR documentation.
.. code-block:: yaml
ISWebserverRole:
win_servermanager.removed:
- name: Web-Server
.. code-block:: yaml
ISWebserverRole:
win_servermanager.removed:
- name: Web-Server
'''
ret = {'name': name,
'result': True,

View file

@ -19,24 +19,42 @@ from salt.serializers.yamlex \
log = logging.getLogger(__name__)
def update(dest, upd):
for key, val in six.iteritems(upd):
try:
if isinstance(val, OrderedDict):
klass = OrderedDict
else:
klass = dict
dest_subkey = dest.get(key, klass())
except AttributeError:
dest_subkey = None
def update(dest, upd, recursive_update=True):
'''
Recursive version of the default dict.update
if isinstance(dest_subkey, collections.Mapping) \
and isinstance(val, collections.Mapping):
ret = update(dest_subkey, val)
dest[key] = ret
elif key:
dest[key] = upd[key]
return dest
Merges upd recursively into dest
If recursive_update=False, will use the classic dict.update, or fall back
on a manual merge (helpful for non-dict types like FunctionWrapper)
'''
if dest is None:
return upd
if recursive_update:
for key, val in six.iteritems(upd):
try:
if isinstance(val, OrderedDict):
valtype = OrderedDict
else:
valtype = dict
dest_subkey = dest.get(key, None)
except AttributeError:
dest_subkey = None
if isinstance(dest_subkey, collections.Mapping) \
and isinstance(val, collections.Mapping):
ret = update(dest_subkey, val)
dest[key] = ret
else:
dest[key] = upd[key]
return dest
else:
try:
dest.update(upd)
except AttributeError:
# this mapping is not a dict
for k in upd:
dest[k] = upd[k]
return dest
def merge_list(obj_a, obj_b):
@ -50,7 +68,7 @@ def merge_list(obj_a, obj_b):
def merge_recurse(obj_a, obj_b):
copied = copy.copy(obj_a)
copied = copy.deepcopy(obj_a)
return update(copied, obj_b)

View file

@ -66,7 +66,6 @@ def update_config(file_name, yaml_contents):
'client': 'wheel',
'eauth': 'pam',
}
'''
file_name = '{0}{1}'.format(file_name, '.conf')
dir_path = os.path.join(__opts__['config_dir'],

View file

@ -5,6 +5,7 @@ from __future__ import absolute_import
# Import Salt Testing libs
import integration
from salttesting import skipIf
# Import Salt libs
import salt.runner
@ -56,6 +57,7 @@ class RunnerModuleTest(integration.TestCase, integration.AdaptedConfigurationTes
'token': token['token'],
})
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_cmd_sync(self):
low = {
'client': 'runner',
@ -74,6 +76,7 @@ class RunnerModuleTest(integration.TestCase, integration.AdaptedConfigurationTes
self.runner.cmd_async(low)
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_cmd_sync_w_arg(self):
low = {
'fun': 'test.arg',
@ -86,6 +89,7 @@ class RunnerModuleTest(integration.TestCase, integration.AdaptedConfigurationTes
self.assertEqual(ret['kwargs']['foo'], 'Foo!')
self.assertEqual(ret['kwargs']['bar'], 'Bar!')
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_wildcard_auth(self):
low = {
'username': 'the_s0und_of_t3ch',

View file

@ -77,6 +77,7 @@ class TestSaltAPIHandler(SaltnadoTestCase):
self.assertEqual(response.headers['Location'], '/login')
# Local client tests
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_simple_local_post(self):
'''
Test a basic API of /
@ -116,6 +117,7 @@ class TestSaltAPIHandler(SaltnadoTestCase):
self.assertEqual(response_obj['return'], ["No minions matched the target. No command was sent, no jid was assigned."])
# local_batch tests
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_simple_local_batch_post(self):
'''
Basic post against local_batch
@ -136,6 +138,7 @@ class TestSaltAPIHandler(SaltnadoTestCase):
self.assertEqual(response_obj['return'], [{'minion': True, 'sub_minion': True}])
# local_batch tests
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_full_local_batch_post(self):
'''
Test full parallelism of local_batch
@ -315,6 +318,7 @@ class TestMinionSaltAPIHandler(SaltnadoTestCase):
for minion_id, grains in six.iteritems(response_obj['return'][0]):
self.assertEqual(minion_id, grains['id'])
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_get(self):
response = self.fetch('/minions/minion',
method='GET',
@ -398,6 +402,7 @@ class TestJobsSaltAPIHandler(SaltnadoTestCase):
application.event_listener = saltnado.EventListener({}, self.opts)
return application
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_get(self):
# test with no JID
self.http_client.fetch(self.get_url('/jobs'),
@ -450,6 +455,7 @@ class TestRunSaltAPIHandler(SaltnadoTestCase):
application.event_listener = saltnado.EventListener({}, self.opts)
return application
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_get(self):
low = [{'client': 'local',
'tgt': '*',

View file

@ -6,6 +6,7 @@ Tests for the salt-run command
from __future__ import absolute_import
# Import Salt Testing libs
from salttesting import skipIf
from salttesting.helpers import ensure_in_syspath
ensure_in_syspath('../../')
@ -33,6 +34,7 @@ class ManageTest(integration.ShellCase):
self.assertEqual(ret['fun'], {})
self.assertEqual(ret['out'], [])
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_list_jobs(self):
'''
jobs.list_jobs

View file

@ -103,6 +103,7 @@ class CallTest(integration.ShellCase, integration.ShellCaseCommonTestsMixIn):
self.assertNotEqual(0, retcode)
@skipIf(sys.platform.startswith('win'), 'This test does not apply on Win')
@skipIf(True, 'to be reenabled when #23623 is merged')
def test_return(self):
self.run_call('cmd.run "echo returnTOmaster"')
jobs = [a for a in self.run_run('jobs.list_jobs')]

View file

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View file

@ -0,0 +1,175 @@
# coding: utf-8
# Python libs
from __future__ import absolute_import
import os
import shutil
import tempfile
# Salt libs
from salt.beacons import inotify
# Salt testing libs
from salttesting import skipIf, TestCase
from salttesting.helpers import destructiveTest, ensure_in_syspath
from salttesting.mock import NO_MOCK, NO_MOCK_REASON
# Third-party libs
try:
import pyinotify # pylint: disable=unused-import
HAS_PYINOTIFY = True
except ImportError:
HAS_PYINOTIFY = False
ensure_in_syspath('../../')
@skipIf(not HAS_PYINOTIFY, 'pyinotify is not available')
@skipIf(NO_MOCK, NO_MOCK_REASON)
class INotifyBeaconTestCase(TestCase):
'''
Test case for salt.beacons.inotify
'''
def setUp(self):
inotify.__context__ = {}
def test_empty_config(self, *args, **kwargs):
config = {}
ret = inotify.beacon(config)
self.assertEqual(ret, [])
def test_file_open(self, *args, **kwargs):
path = os.path.realpath(__file__)
config = {path: {'mask': ['open']}}
ret = inotify.beacon(config)
self.assertEqual(ret, [])
with open(path, 'r') as f:
pass
ret = inotify.beacon(config)
self.assertEqual(len(ret), 1)
self.assertEqual(ret[0]['path'], path)
self.assertEqual(ret[0]['change'], 'IN_OPEN')
@destructiveTest
def test_dir_no_auto_add(self, *args, **kwargs):
tmpdir = None
try:
tmpdir = tempfile.mkdtemp()
config = {tmpdir: {'mask': ['create']}}
ret = inotify.beacon(config)
self.assertEqual(ret, [])
fp = os.path.join(tmpdir, 'tmpfile')
with open(fp, 'w') as f:
pass
ret = inotify.beacon(config)
self.assertEqual(len(ret), 1)
self.assertEqual(ret[0]['path'], fp)
self.assertEqual(ret[0]['change'], 'IN_CREATE')
with open(fp, 'r') as f:
pass
ret = inotify.beacon(config)
self.assertEqual(ret, [])
finally:
if tmpdir:
shutil.rmtree(tmpdir)
@destructiveTest
def test_dir_auto_add(self, *args, **kwargs):
tmpdir = None
try:
tmpdir = tempfile.mkdtemp()
config = {tmpdir: {'mask': ['create', 'open'], 'auto_add': True}}
ret = inotify.beacon(config)
self.assertEqual(ret, [])
fp = os.path.join(tmpdir, 'tmpfile')
with open(fp, 'w') as f:
pass
ret = inotify.beacon(config)
self.assertEqual(len(ret), 2)
self.assertEqual(ret[0]['path'], fp)
self.assertEqual(ret[0]['change'], 'IN_CREATE')
self.assertEqual(ret[1]['path'], fp)
self.assertEqual(ret[1]['change'], 'IN_OPEN')
with open(fp, 'r') as f:
pass
ret = inotify.beacon(config)
self.assertEqual(len(ret), 1)
self.assertEqual(ret[0]['path'], fp)
self.assertEqual(ret[0]['change'], 'IN_OPEN')
finally:
if tmpdir:
shutil.rmtree(tmpdir)
@destructiveTest
def test_dir_recurse(self, *args, **kwargs):
tmpdir = None
try:
tmpdir = tempfile.mkdtemp()
dp1 = os.path.join(tmpdir, 'subdir1')
os.mkdir(dp1)
dp2 = os.path.join(dp1, 'subdir2')
os.mkdir(dp2)
fp = os.path.join(dp2, 'tmpfile')
with open(fp, 'w') as f:
pass
config = {tmpdir: {'mask': ['open'], 'recurse': True}}
ret = inotify.beacon(config)
self.assertEqual(ret, [])
with open(fp) as f:
pass
ret = inotify.beacon(config)
self.assertEqual(len(ret), 3)
self.assertEqual(ret[0]['path'], dp1)
self.assertEqual(ret[0]['change'], 'IN_OPEN|IN_ISDIR')
self.assertEqual(ret[1]['path'], dp2)
self.assertEqual(ret[1]['change'], 'IN_OPEN|IN_ISDIR')
self.assertEqual(ret[2]['path'], fp)
self.assertEqual(ret[2]['change'], 'IN_OPEN')
finally:
if tmpdir:
shutil.rmtree(tmpdir)
@destructiveTest
def test_dir_recurse_auto_add(self, *args, **kwargs):
tmpdir = None
try:
tmpdir = tempfile.mkdtemp()
dp1 = os.path.join(tmpdir, 'subdir1')
os.mkdir(dp1)
config = {tmpdir: {'mask': ['create', 'delete'],
'recurse': True,
'auto_add': True}}
ret = inotify.beacon(config)
self.assertEqual(ret, [])
dp2 = os.path.join(dp1, 'subdir2')
os.mkdir(dp2)
ret = inotify.beacon(config)
self.assertEqual(len(ret), 1)
self.assertEqual(ret[0]['path'], dp2)
self.assertEqual(ret[0]['change'], 'IN_CREATE|IN_ISDIR')
fp = os.path.join(dp2, 'tmpfile')
with open(fp, 'w') as f:
pass
ret = inotify.beacon(config)
self.assertEqual(len(ret), 1)
self.assertEqual(ret[0]['path'], fp)
self.assertEqual(ret[0]['change'], 'IN_CREATE')
os.remove(fp)
ret = inotify.beacon(config)
self.assertEqual(len(ret), 1)
self.assertEqual(ret[0]['path'], fp)
self.assertEqual(ret[0]['change'], 'IN_DELETE')
finally:
if tmpdir:
shutil.rmtree(tmpdir)
if __name__ == '__main__':
from integration import run_tests
run_tests(INotifyBeaconTestCase, needs_daemon=False)

View file

@ -39,78 +39,100 @@ class BotoElbTestCase(TestCase):
name = 'myelb'
listeners = [{'elb_port': 'ELBPORT', 'instance_port': 'PORT',
'elb_protocol': 'HTTPS', 'certificate': 'A'}]
attributes = {'alarm_actions': ['arn:aws:sns:us-east-1:12345:myalarm'],
'insufficient_data_actions': [],
'ok_actions': ['arn:aws:sns:us-east-1:12345:myalarm']}
alarms = {'MyAlarm': {'name': name,
'attributes': {'description': 'A'}}}
attrs = {'alarm_actions': ['arn:aws:sns:us-east-1:12345:myalarm'],
'insufficient_data_actions': [],
'ok_actions': ['arn:aws:sns:us-east-1:12345:myalarm']}
health_check = {'target:': 'HTTP:80/'}
avail_zones = ['us-east-1a', 'us-east-1c', 'us-east-1d']
alarms = {'alarm_actions': {'name': name,
'attributes': {'description': 'A'}}}
cnames = [{'name': 'www.test.com', 'zone': 'test.com', 'ttl': 60}]
ret = {'name': name,
'result': False,
'result': True,
'changes': {},
'comment': ''}
ret1 = copy.deepcopy(ret)
mock = MagicMock(return_value={})
mock_bool = MagicMock(return_value=False)
with patch.dict(boto_elb.__salt__,
{'config.option': mock,
'boto_elb.exists': mock_bool,
'boto_elb.create': mock_bool,
'boto_elb.get_attributes': mock}):
with patch.dict(boto_elb.__opts__, {'test': False}):
comt = (' Failed to create myelb ELB.')
ret.update({'comment': comt})
self.assertDictEqual(boto_elb.present
(name, listeners, attributes=attributes,
availability_zones=avail_zones), ret)
mock_false_bool = MagicMock(return_value=False)
mock_true_bool = MagicMock(return_value=True)
mock_attributes = MagicMock(return_value=attrs)
mock_health_check = MagicMock(return_value=health_check)
mock_ret = MagicMock(return_value={'myelb': ret1})
mock = MagicMock(return_value={})
mock_ret = MagicMock(return_value={'result': {'result': False}})
comt1 = (' Failed to retrieve health_check for ELB myelb.')
with patch.dict(boto_elb.__salt__,
{'config.option': mock,
'boto_elb.get_attributes': mock,
'boto_elb.get_health_check': mock,
'boto_elb.exists': mock_false_bool,
'boto_elb.create': mock_false_bool}):
with patch.dict(boto_elb.__opts__, {'test': False}):
ret = boto_elb.present(
name,
listeners,
availability_zones=avail_zones
)
self.assertTrue(boto_elb.__salt__['boto_elb.exists'].called)
self.assertTrue(boto_elb.__salt__['boto_elb.create'].called)
self.assertIn('Failed to create myelb ELB.', ret['comment'])
self.assertFalse(ret['result'])
mock = MagicMock(return_value={})
mock_ret = MagicMock(return_value={'myelb': ret1})
with patch.dict(boto_elb.__salt__,
{'config.option': mock,
'boto_elb.exists': mock_false_bool,
'boto_elb.create': mock_true_bool,
'boto_elb.get_attributes': mock_attributes,
'boto_elb.get_health_check': mock_health_check,
'boto_elb.get_elb_config': mock,
'state.single': mock_ret}):
with patch.dict(boto_elb.__opts__, {'test': False}):
ret1.update({'result': True})
mock_elb_present = MagicMock(return_value=ret1)
with patch.object(boto_elb, '_elb_present', mock_elb_present):
comt = (' Failed to retrieve attributes for ELB myelb.')
ret.update({'comment': comt})
self.assertDictEqual(boto_elb.present
(name, listeners), ret)
ret = boto_elb.present(
name,
listeners,
availability_zones=avail_zones,
health_check=health_check,
alarms=alarms
)
self.assertTrue(boto_elb.__salt__['boto_elb.exists'].called)
self.assertTrue(boto_elb.__salt__['boto_elb.create'].called)
self.assertTrue(boto_elb.__salt__['state.single'].called)
self.assertTrue(
boto_elb.__salt__['boto_elb.get_attributes'].called
)
self.assertTrue(
boto_elb.__salt__['boto_elb.get_health_check'].called
)
self.assertIn('ELB myelb created.', ret['comment'])
self.assertTrue(ret['result'])
with patch.object(boto_elb, '_attributes_present',
mock_elb_present):
ret.update({'comment': comt1})
self.assertDictEqual(boto_elb.present
(name, listeners), ret)
with patch.object(boto_elb, '_health_check_present',
mock_elb_present):
comt = (' Failed to retrieve ELB myelb.')
ret.update({'comment': comt})
self.assertDictEqual(boto_elb.present
(name, listeners), ret)
with patch.object(boto_elb, '_cnames_present',
mock_elb_present):
comt = (' ')
ret.update({'comment': comt})
self.assertDictEqual(boto_elb.present
(name, listeners,
alarms=alarms), ret)
with patch.object(boto_elb, '_alarms_present',
mock_elb_present):
ret.update({'result': True})
self.assertDictEqual(boto_elb.present
(name, listeners,
alarms=alarms), ret)
mock = MagicMock(return_value={})
mock_elb = MagicMock(return_value={'dns_name': 'myelb.amazon.com'})
mock_ret = MagicMock(return_value={'myelb': ret1})
with patch.dict(boto_elb.__salt__,
{'config.option': mock,
'boto_elb.exists': mock_false_bool,
'boto_elb.create': mock_true_bool,
'boto_elb.get_attributes': mock_attributes,
'boto_elb.get_health_check': mock_health_check,
'boto_elb.get_elb_config': mock_elb,
'state.single': mock_ret}):
with patch.dict(boto_elb.__opts__, {'test': False}):
ret = boto_elb.present(
name,
listeners,
availability_zones=avail_zones,
health_check=health_check,
cnames=cnames
)
self.assertTrue(boto_elb.__salt__['state.single'].called)
cname_call = boto_elb.__salt__['state.single'].mock_calls[0]
self.assertEqual(
cname_call[1][0],
'boto_route53.present'
)
self.assertTrue(ret['result'])
# 'register_instances' function tests: 1

View file

@ -252,12 +252,12 @@ class FileTestCase(TestCase):
group=group), ret)
# 'absent' function tests: 1
@patch.object(os.path, 'islink', MagicMock(return_value=False))
def test_absent(self):
'''
Test to make sure that the named file or directory is absent.
'''
name = '/etc/grub.conf'
name = '/fake/file.conf'
ret = {'name': name,
'result': False,

View file

@ -4,6 +4,7 @@
'''
# Import Python libs
from __future__ import absolute_import
import os
# Import Salt Testing Libs
from salttesting import skipIf, TestCase
@ -33,6 +34,7 @@ class LibvirtTestCase(TestCase):
'''
# 'keys' function tests: 1
@skipIf(os.geteuid() != 0, 'you must be root to run this test')
@patch('os.path.isfile', MagicMock(return_value=False))
def test_keys(self):
'''

View file

@ -0,0 +1,68 @@
# -*- 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.states import pagerduty
pagerduty.__salt__ = {}
pagerduty.__opts__ = {}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class PagerdutyTestCase(TestCase):
'''
Test cases for salt.states.pagerduty
'''
# 'create_event' function tests: 1
def test_create_event(self):
'''
Test to create an event on the PagerDuty service.
'''
name = 'This is a server warning message'
details = 'This is a much more detailed message'
service_key = '9abcd123456789efabcde362783cdbaf'
profile = 'my-pagerduty-account'
ret = {'name': name,
'result': None,
'comment': '',
'changes': {}}
with patch.dict(pagerduty.__opts__, {'test': True}):
comt = ('Need to create event: {0}'.format(name))
ret.update({'comment': comt})
self.assertDictEqual(pagerduty.create_event(name, details,
service_key, profile),
ret)
with patch.dict(pagerduty.__opts__, {'test': False}):
mock_t = MagicMock(return_value=True)
with patch.dict(pagerduty.__salt__,
{'pagerduty.create_event': mock_t}):
comt = ('Created event: {0}'.format(name))
ret.update({'comment': comt, 'result': True})
self.assertDictEqual(pagerduty.create_event(name, details,
service_key,
profile), ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(PagerdutyTestCase, needs_daemon=False)

View file

@ -0,0 +1,101 @@
# -*- 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.states import pecl
pecl.__salt__ = {}
pecl.__opts__ = {}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class PeclTestCase(TestCase):
'''
Test cases for salt.states.pecl
'''
# 'installed' function tests: 1
def test_installed(self):
'''
Test to make sure that a pecl extension is installed.
'''
name = 'mongo'
ver = '1.0.1'
ret = {'name': name,
'result': None,
'comment': '',
'changes': {}}
mock_lst = MagicMock(return_value={name: 'stable'})
mock_t = MagicMock(return_value=True)
with patch.dict(pecl.__salt__, {'pecl.list': mock_lst,
'pecl.install': mock_t}):
comt = ('Pecl extension {0} is already installed.'.format(name))
ret.update({'comment': comt, 'result': True})
self.assertDictEqual(pecl.installed(name), ret)
with patch.dict(pecl.__opts__, {'test': True}):
comt = ('Pecl extension mongo-1.0.1 would have been installed')
ret.update({'comment': comt, 'result': None})
self.assertDictEqual(pecl.installed(name, version=ver), ret)
with patch.dict(pecl.__opts__, {'test': False}):
comt = ('Pecl extension mongo-1.0.1 was successfully installed')
ret.update({'comment': comt, 'result': True,
'changes': {'mongo-1.0.1': 'Installed'}})
self.assertDictEqual(pecl.installed(name, version=ver), ret)
# 'removed' function tests: 1
def test_removed(self):
'''
Test to make sure that a pecl extension is not installed.
'''
name = 'mongo'
ret = {'name': name,
'result': None,
'comment': '',
'changes': {}}
mock_lst = MagicMock(side_effect=[{}, {name: 'stable'},
{name: 'stable'}])
mock_t = MagicMock(return_value=True)
with patch.dict(pecl.__salt__, {'pecl.list': mock_lst,
'pecl.uninstall': mock_t}):
comt = ('Pecl extension {0} is not installed.'.format(name))
ret.update({'comment': comt, 'result': True})
self.assertDictEqual(pecl.removed(name), ret)
with patch.dict(pecl.__opts__, {'test': True}):
comt = ('Pecl extension mongo would have been removed')
ret.update({'comment': comt, 'result': None})
self.assertDictEqual(pecl.removed(name), ret)
with patch.dict(pecl.__opts__, {'test': False}):
comt = ('Pecl extension mongo was successfully removed.')
ret.update({'comment': comt, 'result': True,
'changes': {name: 'Removed'}})
self.assertDictEqual(pecl.removed(name), ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(PeclTestCase, needs_daemon=False)

View file

@ -0,0 +1,51 @@
# -*- 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.states import pkgng
pkgng.__salt__ = {}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class PkgngTestCase(TestCase):
'''
Test cases for salt.states.pkgng
'''
# 'update_packaging_site' function tests: 1
def test_update_packaging_site(self):
'''
Test to execute update_packaging_site.
'''
name = "http://192.168.0.2"
ret = {'name': name,
'result': True,
'comment': '',
'changes': {}}
mock_t = MagicMock(return_value=True)
with patch.dict(pkgng.__salt__, {'pkgng.update_package_site': mock_t}):
self.assertDictEqual(pkgng.update_packaging_site(name), ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(PkgngTestCase, needs_daemon=False)

View file

@ -0,0 +1,87 @@
# -*- 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.states import portage_config
portage_config.__salt__ = {}
portage_config.__opts__ = {'test': True}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class PortageConfigTestCase(TestCase):
'''
Test cases for salt.states.portage_config
'''
# 'mod_init' function tests: 1
def test_mod_init(self):
'''
Test to enforce a nice structure on the configuration files.
'''
name = 'salt'
mock = MagicMock(side_effect=[True, Exception])
with patch.dict(portage_config.__salt__,
{'portage_config.enforce_nice_config': mock}):
self.assertTrue(portage_config.mod_init(name))
self.assertFalse(portage_config.mod_init(name))
# 'flags' function tests: 1
@patch('traceback.format_exc', MagicMock(return_value='SALTSTACK'))
def test_flags(self):
'''
Test to enforce the given flags on the given package or ``DEPEND`` atom.
'''
name = 'salt'
ret = {'name': name,
'result': False,
'comment': 'SALTSTACK',
'changes': {}}
mock = MagicMock(side_effect=Exception('error'))
with patch.dict(portage_config.__salt__,
{'portage_config.get_missing_flags': mock}):
self.assertDictEqual(portage_config.flags(name, use='openssl'), ret)
self.assertDictEqual(portage_config.flags(name,
accept_keywords=True),
ret)
self.assertDictEqual(portage_config.flags(name, env=True), ret)
self.assertDictEqual(portage_config.flags(name, license=True), ret)
self.assertDictEqual(portage_config.flags(name, properties=True),
ret)
self.assertDictEqual(portage_config.flags(name, mask=True), ret)
self.assertDictEqual(portage_config.flags(name, unmask=True), ret)
ret.update({'comment': '', 'result': True})
self.assertDictEqual(portage_config.flags(name), ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(PortageConfigTestCase, needs_daemon=False)

View file

@ -0,0 +1,146 @@
# -*- 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
from salt.exceptions import SaltInvocationError
ensure_in_syspath('../../')
# Import Salt Libs
from salt.states import ports
import os
ports.__salt__ = {}
ports.__opts__ = {}
class MockModule(object):
"""
Mock of __module__
"""
__module__ = 'A'
class MockContext(object):
"""
Mock of __context__
"""
__context__ = {'ports.install_error': 'salt'}
class MockSys(object):
"""
Mock of sys
"""
def __init__(self):
self.modules = {'A': MockContext()}
ports.sys = MockSys()
@skipIf(NO_MOCK, NO_MOCK_REASON)
class PortsTestCase(TestCase):
'''
Test cases for salt.states.ports
'''
# 'installed' function tests: 1
def test_installed(self):
'''
Test to verify that the desired port is installed,
and that it was compiled with the desired options.
'''
name = 'security/nmap'
options = [{'IPV6': 'on'}]
ret = {'name': name,
'result': None,
'comment': '',
'changes': {}}
mock = MagicMock(side_effect=SaltInvocationError)
with patch.dict(ports.__salt__, {'ports.showconfig': mock}):
comt = ('Unable to get configuration for {0}. Port name may '
'be invalid, or ports tree may need to be updated. '
'Error message: '.format(name))
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(ports.installed(name), ret)
mock = MagicMock(return_value={})
mock_lst = MagicMock(return_value={'origin': {'origin': name}})
with patch.dict(ports.__salt__, {'ports.showconfig': mock,
'pkg.list_pkgs': mock_lst}):
comt = ('security/nmap is already installed')
ret.update({'comment': comt, 'result': True})
self.assertDictEqual(ports.installed(name), ret)
comt = ('security/nmap does not have any build options,'
' yet options were specified')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(ports.installed(name, options), ret)
mock_dict = MagicMock(return_value={'origin': {'origin': 'salt'}})
with patch.dict(ports.__salt__, {'pkg.list_pkgs': mock_dict}):
with patch.dict(ports.__opts__, {'test': True}):
comt = ('{0} will be installed'.format(name))
ret.update({'comment': comt, 'result': None})
self.assertDictEqual(ports.installed(name), ret)
mock = MagicMock(return_value={'salt': {'salt': 'salt'}})
mock_dict = MagicMock(return_value={'origin': {'origin': 'salt'}})
mock_f = MagicMock(return_value=False)
mock_t = MagicMock(return_value=True)
with patch.dict(ports.__salt__, {'ports.showconfig': mock,
'pkg.list_pkgs': mock_dict,
'ports.config': mock_f,
'ports.rmconfig': mock_t}):
with patch.dict(ports.__opts__, {'test': True}):
comt = ('The following options are not available'
' for security/nmap: IPV6')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(ports.installed(name, options), ret)
comt = ('security/nmap will be installed with the '
'default build options')
ret.update({'comment': comt, 'result': None})
self.assertDictEqual(ports.installed(name), ret)
with patch.dict(ports.__opts__, {'test': False}):
comt = ('Unable to set options for security/nmap')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(ports.installed(name, [{'salt': 'salt'}]),
ret)
with patch.object(os.path, 'isfile', mock_t):
with patch.object(os.path, 'isdir', mock_t):
comt = ('Unable to clear options for security/nmap')
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(ports.installed(name), ret)
with patch.dict(ports.__salt__, {'ports.config': mock_t,
'ports.install': mock_t,
'test.ping': MockModule()}):
comt = ('Failed to install security/nmap.'
' Error message:\nsalt')
ret.update({'comment': comt, 'result': False,
'changes': True})
self.assertDictEqual(ports.installed(name,
[{'salt': 'salt'}]),
ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(PortsTestCase, needs_daemon=False)

View file

@ -0,0 +1,76 @@
# -*- 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.states import quota
quota.__opts__ = {}
quota.__salt__ = {}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class QuotaTestCase(TestCase):
'''
Test cases for salt.states.quota
'''
# 'mode' function tests: 1
def test_mode(self):
'''
Test to set the quota for the system.
'''
name = '/'
mode = True
quotatype = 'user'
ret = {'name': name,
'changes': {},
'result': False,
'comment': ''}
mock_bool = MagicMock(side_effect=[True, False])
mock = MagicMock(return_value={name: {quotatype: 'on'}})
with patch.dict(quota.__salt__, {'quota.get_mode': mock}):
comt = ('Quota for / already set to on')
ret.update({'comment': comt, 'result': True})
self.assertDictEqual(quota.mode(name, mode, quotatype), ret)
mock = MagicMock(return_value={name: {quotatype: 'off'}})
with patch.dict(quota.__salt__, {'quota.get_mode': mock,
'quota.on': mock_bool}):
with patch.dict(quota.__opts__, {'test': True}):
comt = ('Quota for / needs to be set to on')
ret.update({'comment': comt, 'result': None})
self.assertDictEqual(quota.mode(name, mode, quotatype), ret)
with patch.dict(quota.__opts__, {'test': False}):
comt = ('Set quota for / to on')
ret.update({'comment': comt, 'result': True,
'changes': {'quota': name}})
self.assertDictEqual(quota.mode(name, mode, quotatype), ret)
comt = ('Failed to set quota for / to on')
ret.update({'comment': comt, 'result': False, 'changes': {}})
self.assertDictEqual(quota.mode(name, mode, quotatype), ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(QuotaTestCase, needs_daemon=False)