Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2016.3] Merge forward from 2015.8 to 2016.3 #34186

Merged
merged 19 commits into from
Jun 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/topics/tutorials/states_pt1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Next, let's run the state we created. Open a terminal on the master and run:
salt '*' state.apply

Our master is instructing all targeted minions to run :func:`state.apply
<salt.modules.state.apply>`. When this function is executied without any SLS
<salt.modules.state.apply>`. When this function is executed without any SLS
targets, a minion will download the :ref:`top file <states-top>` and attempt to
match the expressions within it. When the minion does match an expression the
modules listed for it will be downloaded, compiled, and executed.
Expand Down
5 changes: 3 additions & 2 deletions salt/beacons/diskusage.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ def beacon(config):

'''
ret = []
for mount in config:
for mounts in config:
mount = mounts.keys()[0]

try:
_current_usage = psutil.disk_usage(mount)
Expand All @@ -78,7 +79,7 @@ def beacon(config):
continue

current_usage = _current_usage.percent
monitor_usage = config[mount]
monitor_usage = mounts[mount]
if '%' in monitor_usage:
monitor_usage = re.sub('%', '', monitor_usage)
monitor_usage = float(monitor_usage)
Expand Down
37 changes: 30 additions & 7 deletions salt/modules/grains.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ def setvals(grains, destructive=False):
'''
Set new grains values in the grains config file

:param Destructive: If an operation results in a key being removed, delete the key, too. Defaults to False.
destructive
If an operation results in a key being removed, delete the key, too.
Defaults to False.

CLI Example:

Expand Down Expand Up @@ -279,7 +281,15 @@ def setval(key, val, destructive=False):
'''
Set a grains value in the grains config file

:param Destructive: If an operation results in a key being removed, delete the key, too. Defaults to False.
key
The grain key to be set.

val
The value to set the grain key to.

destructive
If an operation results in a key being removed, delete the key, too.
Defaults to False.

CLI Example:

Expand All @@ -305,11 +315,13 @@ def append(key, val, convert=False, delimiter=DEFAULT_TARGET_DELIM):
val
The value to append to the grain key

:param convert: If convert is True, convert non-list contents into a list.
convert
If convert is True, convert non-list contents into a list.
If convert is False and the grain contains non-list contents, an error
is given. Defaults to False.

:param delimiter: The key can be a nested dict key. Use this parameter to
delimiter
The key can be a nested dict key. Use this parameter to
specify the delimiter you use, instead of the default ``:``.
You can now append values to a list in nested dictionary grains. If the
list doesn't exist at this level, it will be created.
Expand Down Expand Up @@ -351,12 +363,19 @@ def remove(key, val, delimiter=DEFAULT_TARGET_DELIM):

Remove a value from a list in the grains config file

:param delimiter: The key can be a nested dict key. Use this parameter to
key
The grain key to remove.

val
The value to remove.

delimiter
The key can be a nested dict key. Use this parameter to
specify the delimiter you use, instead of the default ``:``.
You can now append values to a list in nested dictionary grains. If the
list doesn't exist at this level, it will be created.

.. versionadded:: 2016.3.0
.. versionadded:: 2015.8.2

CLI Example:

Expand Down Expand Up @@ -387,7 +406,11 @@ def delval(key, destructive=False):

Delete a grain from the grains config file

:param destructive: Delete the key, too. Defaults to False.
key
The grain key from which to delete the value.

destructive
Delete the key, too. Defaults to False.

CLI Example:

Expand Down
2 changes: 1 addition & 1 deletion salt/modules/mine.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def _mine_get(load, opts):

def update(clear=False):
'''
Execute the configured functions and send the data back up to the master
Execute the configured functions and send the data back up to the master.
The functions to be executed are merged from the master config, pillar and
minion config under the option "function_cache":

Expand Down
3 changes: 1 addition & 2 deletions salt/utils/gitfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,6 @@ def _lock(self, lock_type='update', failhard=False):
# Lock file is empty, set pid to 0 so it evaluates as
# False.
pid = 0
#if self.opts.get("gitfs_global_lock") or pid and pid_exists(int(pid)):
global_lock_key = self.role + '_global_lock'
lock_file = self._get_lock_file(lock_type=lock_type)
if self.opts[global_lock_key]:
Expand All @@ -442,7 +441,7 @@ def _lock(self, lock_type='update', failhard=False):
'by another master.')
log.warning(msg)
if failhard:
raise
raise exc
return
elif pid and pid_exists(pid):
log.warning('Process %d has a %s %s lock (%s)',
Expand Down
53 changes: 53 additions & 0 deletions tests/integration/cli/grains.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,69 @@
'''
# Import Python libs
from __future__ import absolute_import
import os

# Import Salt Libs
import integration
import salt.utils

# Import Salt Testing Libs
from salttesting.helpers import ensure_in_syspath

ensure_in_syspath('../../')


class GrainsTargetingTest(integration.ShellCase):
'''
Integration tests for targeting with grains.
'''

def test_grains_targeting_os_running(self):
'''
Tests running "salt -G 'os:<system-os>' test.ping and minions both return True
'''
test_ret = ['sub_minion:', ' True', 'minion:', ' True']

os_grain = ''
for item in self.run_salt('minion grains.get os'):
if item != 'minion:':
os_grain = item.strip()

ret = self.run_salt('-G \'os:{0}\' test.ping'.format(os_grain))
self.assertEqual(sorted(ret), sorted(test_ret))

def test_grains_targeting_minion_id_running(self):
'''
Tests return of each running test minion targeting with minion id grain
'''
minion = self.run_salt('-G \'id:minion\' test.ping')
self.assertEqual(sorted(minion), sorted(['minion:', ' True']))

sub_minion = self.run_salt('-G \'id:sub_minion\' test.ping')
self.assertEqual(sorted(sub_minion), sorted(['sub_minion:', ' True']))

def test_grains_targeting_disconnected(self):
'''
Tests return of minion using grains targeting on a disconnected minion.
'''
test_ret = 'Minion did not return. [Not connected]'

# Create a minion key, but do not start the "fake" minion. This mimics a
# disconnected minion.
key_file = os.path.join(self.master_opts['pki_dir'], 'minions', 'disconnected')
salt.utils.fopen(key_file, 'a').close()

# ping disconnected minion and ensure it times out and returns with correct message
try:
ret = ''
for item in self.run_salt('-G \'id:disconnected\' test.ping'):
if item != 'disconnected:':
ret = item.strip()
self.assertEqual(ret, test_ret)
finally:
os.unlink(key_file)


class SSHGrainsTest(integration.SSHCase):
'''
Test salt-ssh grains functionality
Expand Down
74 changes: 72 additions & 2 deletions tests/integration/modules/grains.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# -*- coding: utf-8 -*-

'''
Test the grains module
'''

# Import python libs
from __future__ import absolute_import
import os
import time

# Import Salt Testing libs
from salttesting import skipIf
from salttesting.helpers import ensure_in_syspath
from salttesting.helpers import destructiveTest, ensure_in_syspath

ensure_in_syspath('../../')

# Import salt libs
Expand Down Expand Up @@ -105,6 +106,75 @@ def test_get(self):
['level1:level2']),
'foo')


class GrainsAppendTestCase(integration.ModuleCase):
'''
Tests written specifically for the grains.append function.
'''
GRAIN_KEY = 'salttesting-grain-key'
GRAIN_VAL = 'my-grain-val'

@destructiveTest
def tearDown(self):
test_grain = self.run_function('grains.get', [self.GRAIN_KEY])
if test_grain and test_grain == [self.GRAIN_VAL]:
self.run_function('grains.remove', [self.GRAIN_KEY, self.GRAIN_VAL])

@destructiveTest
def test_grains_append(self):
'''
Tests the return of a simple grains.append call.
'''
ret = self.run_function('grains.append', [self.GRAIN_KEY, self.GRAIN_VAL])
self.assertEqual(ret[self.GRAIN_KEY], [self.GRAIN_VAL])

@destructiveTest
def test_grains_append_val_already_present(self):
'''
Tests the return of a grains.append call when the value is already present in the grains list.
'''
messaging = 'The val {0} was already in the list salttesting-grain-key'.format(self.GRAIN_VAL)

# First, make sure the test grain is present
self.run_function('grains.append', [self.GRAIN_KEY, self.GRAIN_VAL])

# Now try to append again
ret = self.run_function('grains.append', [self.GRAIN_KEY, self.GRAIN_VAL])
self.assertEqual(messaging, ret)

@destructiveTest
def test_grains_append_val_is_list(self):
'''
Tests the return of a grains.append call when val is passed in as a list.
'''
second_grain = self.GRAIN_VAL + '-2'
ret = self.run_function('grains.append', [self.GRAIN_KEY, [self.GRAIN_VAL, second_grain]])
self.assertEqual(ret[self.GRAIN_KEY], [self.GRAIN_VAL, second_grain])

@destructiveTest
def test_grains_append_call_twice(self):
'''
Tests the return of a grains.append call when the value is already present
but also ensure the grain is not listed twice.
'''
# First, add the test grain.
self.run_function('grains.append', [self.GRAIN_KEY, self.GRAIN_VAL])

# Call the function again, which results in a string message, as tested in
# test_grains_append_val_already_present above.
self.run_function('grains.append', [self.GRAIN_KEY, self.GRAIN_VAL])

# Now make sure the grain doesn't show up twice.
grains = self.run_function('grains.items')
count = 0
for grain in grains.keys():
if grain == self.GRAIN_KEY:
count += 1

# We should only have hit the grain key once.
self.assertEqual(count, 1)


if __name__ == '__main__':
from integration import run_tests
run_tests(TestModulesGrains)
36 changes: 24 additions & 12 deletions tests/unit/modules/boto_vpc_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
# Import Python libs
from __future__ import absolute_import
from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module
import pkg_resources
from pkg_resources import DistributionNotFound
import random
import string

Expand Down Expand Up @@ -92,6 +94,19 @@ def _has_required_boto():
return True


def _get_moto_version():
'''
Returns the moto version
'''
try:
return LooseVersion(moto.__version__)
except AttributeError:
try:
return LooseVersion(pkg_resources.get_distribution('moto').version)
except DistributionNotFound:
return False


def _has_required_moto():
'''
Returns True/False boolean depending on if Moto is installed and correct
Expand All @@ -100,17 +115,8 @@ def _has_required_moto():
if not HAS_MOTO:
return False
else:
try:
if LooseVersion(moto.__version__) < LooseVersion(required_moto_version):
return False
except AttributeError:
import pkg_resources
from pkg_resources import DistributionNotFound
try:
if LooseVersion(pkg_resources.get_distribution('moto').version) < LooseVersion(required_moto_version):
return False
except DistributionNotFound:
return False
if _get_moto_version() < LooseVersion(required_moto_version):
return False
return True


Expand Down Expand Up @@ -506,13 +512,19 @@ def test_that_when_describing_vpc_by_id_it_returns_the_dict_of_properties_return
'''
Tests describing parameters via vpc id if vpc exist
'''
# With moto 0.4.25 is_default is set to True. 0.4.24 and older, is_default is False
if _get_moto_version() >= LooseVersion('0.4.25'):
is_default = True
else:
is_default = False

vpc = self._create_vpc(name='test', tags={'test': 'testvalue'})

describe_vpc = boto_vpc.describe(vpc_id=vpc.id, **conn_parameters)

vpc_properties = dict(id=vpc.id,
cidr_block=six.text_type(cidr_block),
is_default=False,
is_default=is_default,
state=u'available',
tags={u'Name': u'test', u'test': u'testvalue'},
dhcp_options_id=u'dopt-7a8b9c2d',
Expand Down