Merge branch '2015.8' into '2016.3'

Conflicts:
  - salt/cli/salt.py
  - salt/modules/groupadd.py
  - salt/states/service.py
This commit is contained in:
rallytime 2016-06-08 11:20:18 -06:00
commit c5b4ec0b0f
22 changed files with 1439 additions and 437 deletions

View file

@ -4,7 +4,7 @@
Debian GNU/Linux / Raspbian
===========================
Debian GNU/Linux distribution and some devariatives such as Raspbian already
Debian GNU/Linux distribution and some derivatives such as Raspbian already
have included Salt packages to their repositories. However, current stable
release codenamed "Jessie" contains old outdated Salt release. It is
recommended to use SaltStack repository for Debian as described
@ -23,96 +23,6 @@ Official SaltStack repository.
Instructions are at http://repo.saltstack.com/#debian.
Installation from the Community-Maintained Repository
=====================================================
The SaltStack community maintains a Debian repository at debian.saltstack.com.
Packages for Debian Old Stable, Stable, and Unstable (Wheezy, Jessie, and Sid)
for Salt 0.16 and later are published in this repository.
.. note::
Packages in this repository are community built, and it can
take a little while until the latest SaltStack release is available
in this repository.
Jessie (Stable)
---------------
For Jessie, the following line is needed in either
``/etc/apt/sources.list`` or a file in ``/etc/apt/sources.list.d``:
.. code-block:: bash
deb http://debian.saltstack.com/debian jessie-saltstack main
Wheezy (Old Stable)
-------------------
For Wheezy, the following line is needed in either
``/etc/apt/sources.list`` or a file in ``/etc/apt/sources.list.d``:
.. code-block:: bash
deb http://debian.saltstack.com/debian wheezy-saltstack main
Squeeze (Old Old Stable)
------------------------
For Squeeze, you will need to enable the Debian backports repository
as well as the debian.saltstack.com repository. To do so, add the
following to ``/etc/apt/sources.list`` or a file in
``/etc/apt/sources.list.d``:
.. code-block:: bash
deb http://debian.saltstack.com/debian squeeze-saltstack main
deb http://backports.debian.org/debian-backports squeeze-backports main
Stretch (Testing)
-----------------
For Stretch, the following line is needed in either
``/etc/apt/sources.list`` or a file in ``/etc/apt/sources.list.d``:
.. code-block:: bash
deb http://debian.saltstack.com/debian stretch-saltstack main
Sid (Unstable)
--------------
For Sid, the following line is needed in either
``/etc/apt/sources.list`` or a file in ``/etc/apt/sources.list.d``:
.. code-block:: bash
deb http://debian.saltstack.com/debian unstable main
Import the repository key
-------------------------
You will need to import the key used for signing.
.. code-block:: bash
wget -q -O- "http://debian.saltstack.com/debian-salt-team-joehealy.gpg.key" | apt-key add -
.. note::
You can optionally verify the key integrity with ``sha512sum`` using the
public key signature shown here. E.g:
.. code-block:: bash
echo "b702969447140d5553e31e9701be13ca11cc0a7ed5fe2b30acb8491567560ee62f834772b5095d735dfcecb2384a5c1a20045f52861c417f50b68dd5ff4660e6 debian-salt-team-joehealy.gpg.key" | sha512sum -c
Update the package database
---------------------------
.. code-block:: bash
apt-get update
.. _installation-debian-raspbian:
Installation from the Debian / Raspbian Official Repository

View file

@ -213,7 +213,10 @@ class SaltCMD(parsers.SaltCMDOptionParser):
if not self.options.batch:
self.config['batch'] = '100%'
batch = salt.cli.batch.Batch(self.config, eauth=eauth, quiet=True)
try:
batch = salt.cli.batch.Batch(self.config, eauth=eauth, quiet=True)
except salt.exceptions.SaltClientError as exc:
sys.exit(2)
ret = {}

View file

@ -166,10 +166,13 @@ def adduser(name, username, root=None):
if not then adds it.
'''
on_redhat_5 = __grains__.get('os_family') == 'RedHat' and __grains__.get('osmajorrelease') == '5'
on_suse_11 = __grains__.get('os_family') == 'Suse' and __grains__.get('osrelease_info')[0] == 11
if __grains__['kernel'] == 'Linux':
if on_redhat_5:
cmd = ('gpasswd', '-a', username, name)
elif on_suse_11:
cmd = ('usermod', '-A', name, username)
else:
cmd = ('gpasswd', '--add', username, name)
if root is not None:
@ -198,6 +201,7 @@ def deluser(name, username, root=None):
then returns True.
'''
on_redhat_5 = __grains__.get('os_family') == 'RedHat' and __grains__.get('osmajorrelease') == '5'
on_suse_11 = __grains__.get('os_family') == 'Suse' and __grains__.get('osrelease_info')[0] == 11
grp_info = __salt__['group.info'](name)
try:
@ -205,6 +209,8 @@ def deluser(name, username, root=None):
if __grains__['kernel'] == 'Linux':
if on_redhat_5:
cmd = ('gpasswd', '-d', username, name)
elif on_suse_11:
cmd = ('usermod', '-R', name, username)
else:
cmd = ('gpasswd', '--del', username, name)
if root is not None:
@ -239,10 +245,15 @@ def members(name, members_list, root=None):
foo:x:1234:user1,user2,user3,...
'''
on_redhat_5 = __grains__.get('os_family') == 'RedHat' and __grains__.get('osmajorrelease') == '5'
on_suse_11 = __grains__.get('os_family') == 'Suse' and __grains__.get('osrelease_info')[0] == 11
if __grains__['kernel'] == 'Linux':
if on_redhat_5:
cmd = ('gpasswd', '-M', members_list, name)
elif on_suse_11:
for old_member in __salt__['group.info'](name).get('members'):
__salt__['cmd.run']('groupmod -R {0} {1}'.format(old_member, name), python_shell=False)
cmd = ('groupmod', '-A', members_list, name)
else:
cmd = ('gpasswd', '--members', members_list, name)
if root is not None:

View file

@ -108,7 +108,7 @@ def locate(pattern, database='', limit=0, **kwargs):
'wholename': 'w',
}
for option in kwargs:
if bool(kwargs[option]) is True:
if bool(kwargs[option]) is True and option in toggles:
options += toggles[option]
if options:
options = '-{0}'.format(options)

View file

@ -1223,7 +1223,7 @@ def get_bufsize(iface):
.. code-block:: bash
salt '*' network.get_bufsize
salt '*' network.get_bufsize eth0
'''
if __grains__['kernel'] == 'Linux':
if os.path.exists('/sbin/ethtool'):

View file

@ -422,6 +422,12 @@ def set_hwclock(clock):
elif clock == 'localtime':
__salt__['file.sed']('/etc/default/rcS', '^UTC=.*', 'UTC=no')
elif 'Gentoo' in __grains__['os_family']:
if clock not in ('UTC', 'localtime'):
raise SaltInvocationError(
'Only \'UTC\' and \'localtime\' are allowed'
)
if clock == 'localtime':
clock = 'local'
__salt__['file.sed'](
'/etc/conf.d/hwclock', '^clock=.*', 'clock="{0}"'.format(clock))

View file

@ -83,8 +83,9 @@ def list_available():
salt '*' win_servermanager.list_available
'''
cmd = 'Import-Module ServerManager; ' \
'Get-WindowsFeature -erroraction silentlycontinue ' \
'-warningaction silentlycontinue'
'Get-WindowsFeature ' \
'-ErrorAction SilentlyContinue ' \
'-WarningAction SilentlyContinue'
return __salt__['cmd.shell'](cmd, shell='powershell')
@ -102,9 +103,10 @@ def list_installed():
salt '*' win_servermanager.list_installed
'''
cmd = 'Get-WindowsFeature -erroraction silentlycontinue ' \
'-warningaction silentlycontinue | ' \
'Select DisplayName,Name,Installed'
cmd = 'Get-WindowsFeature ' \
'-ErrorAction SilentlyContinue ' \
'-WarningAction SilentlyContinue ' \
'| Select DisplayName,Name,Installed'
features = _pshell_json(cmd)
ret = {}
@ -115,7 +117,7 @@ def list_installed():
return ret
def install(feature, recurse=False):
def install(feature, recurse=False, source=None, restart=False, exclude=None):
'''
Install a feature
@ -129,7 +131,21 @@ def install(feature, recurse=False):
:param str feature: The name of the feature to install
:param bool recurse: Install all sub-features
:param bool recurse: Install all sub-features. Default is False
:param str source: Path to the source files if missing from the target
system. None means that the system will use windows update services to
find the required files. Default is None
:param bool restart: Restarts the computer when installation is complete, if
required by the role/feature installed. Default is False
:param str exclude: The name of the feature to exclude when installing the
named feature.
..note:: As there is no exclude option for the ``Add-WindowsFeature``
command, the feature will be installed with other sub-features and
will then be removed.
:return: A dictionary containing the results of the install
:rtype: dict
@ -140,16 +156,33 @@ def install(feature, recurse=False):
salt '*' win_servermanager.install Telnet-Client
salt '*' win_servermanager.install SNMP-Service True
salt '*' win_servermanager.install TFTP-Client source=d:\\side-by-side
'''
mgmt_tools = ''
if salt.utils.version_cmp(__grains__['osversion'], '6.2') >= 0:
mgmt_tools = '-IncludeManagementTools'
sub = ''
if recurse:
sub = '-IncludeAllSubFeature'
cmd = 'Add-WindowsFeature -Name {0} {1} ' \
rst = ''
if restart:
rst = '-Restart'
src = ''
if source is not None:
src = '-Source {0}'.format(source)
cmd = 'Add-WindowsFeature -Name {0} {1} {2} {3} {4} ' \
'-ErrorAction SilentlyContinue ' \
'-WarningAction SilentlyContinue'.format(_cmd_quote(feature), sub)
'-WarningAction SilentlyContinue'\
.format(_cmd_quote(feature), mgmt_tools, sub, src, rst)
out = _pshell_json(cmd)
if exclude is not None:
remove(exclude, restart=restart)
if out['FeatureResult']:
return {'ExitCode': out['ExitCode'],
'DisplayName': out['FeatureResult'][0]['DisplayName'],
@ -162,8 +195,8 @@ def install(feature, recurse=False):
'Success': out['Success']}
def remove(feature):
'''
def remove(feature, remove_payload=False, restart=False):
r'''
Remove an installed feature
.. note::
@ -175,6 +208,13 @@ def remove(feature):
:param str feature: The name of the feature to remove
:param bool remove_payload: True will cause the feature to be removed from
the side-by-side store (``%SystemDrive%:\Windows\WinSxS``). Default is
False
:param bool restart: Restarts the computer when uninstall is complete, if
required by the role/feature removed. Default is False
:return: A dictionary containing the results of the uninstall
:rtype: dict
@ -184,9 +224,22 @@ def remove(feature):
salt -t 600 '*' win_servermanager.remove Telnet-Client
'''
cmd = 'Remove-WindowsFeature -Name {0} ' \
mgmt_tools = ''
if salt.utils.version_cmp(__grains__['osversion'], '6.2') >= 0:
mgmt_tools = '-IncludeManagementTools'
rmv = ''
if remove_payload:
rmv = '-Remove'
rst = ''
if restart:
rst = '-Restart'
cmd = 'Remove-WindowsFeature -Name {0} {1} {2} {3} ' \
'-ErrorAction SilentlyContinue ' \
'-WarningAction SilentlyContinue'.format(_cmd_quote(feature))
'-WarningAction SilentlyContinue'\
.format(_cmd_quote(feature), mgmt_tools, rmv, rst)
out = _pshell_json(cmd)
if out['FeatureResult']:

View file

@ -266,6 +266,11 @@ def save_minions(jid, minions, syndic_id=None):
minions_path = os.path.join(jid_dir, MINIONS_P)
try:
if not os.path.exists(jid_dir):
try:
os.makedirs(jid_dir)
except OSError:
pass
serial.dump(minions, salt.utils.fopen(minions_path, 'w+b'))
except IOError as exc:
log.error(

View file

@ -2503,14 +2503,16 @@ class BaseHighState(object):
)
if contents:
found = 1
tops[self.opts['environment']] = [
compile_template(
contents,
self.state.rend,
self.state.opts['renderer'],
saltenv=self.opts['environment']
)
]
tops[self.opts['environment']] = [
compile_template(
contents,
self.state.rend,
self.state.opts['renderer'],
saltenv=self.opts['environment']
)
]
else:
tops[self.opts['environment']] = [{}]
elif self.opts['top_file_merging_strategy'] == 'merge':
found = 0
if self.opts.get('state_top_saltenv', False):
@ -2521,28 +2523,6 @@ class BaseHighState(object):
)
if contents:
found = found + 1
else:
log.debug('No contents loaded for env: {0}'.format(saltenv))
tops[saltenv].append(
compile_template(
contents,
self.state.rend,
self.state.opts['renderer'],
saltenv=saltenv
)
)
else:
for saltenv in self._get_envs():
contents = self.client.cache_file(
self.opts['state_top'],
saltenv
)
if contents:
found = found + 1
else:
log.debug('No contents loaded for env: {0}'.format(saltenv))
tops[saltenv].append(
compile_template(
contents,
@ -2551,6 +2531,28 @@ class BaseHighState(object):
saltenv=saltenv
)
)
else:
tops[saltenv].append({})
log.debug('No contents loaded for env: {0}'.format(saltenv))
else:
for saltenv in self._get_envs():
contents = self.client.cache_file(
self.opts['state_top'],
saltenv
)
if contents:
found = found + 1
tops[saltenv].append(
compile_template(
contents,
self.state.rend,
self.state.opts['renderer'],
saltenv=saltenv
)
)
else:
tops[saltenv].append({})
log.debug('No contents loaded for env: {0}'.format(saltenv))
if found > 1:
log.warning('Top file merge strategy set to \'merge\' and multiple top files found. '
'Top file merging order is undefined; '

View file

@ -532,8 +532,8 @@ def mod_watch(name,
The name of the init or rc script used to manage the service
sfun
The original function which triggered the mod_watch call
(`service.running`, for example).
Required. The original function which triggered the mod_watch call.
Must be one of ``running`` or ``dead``.
sig
The string to search for when looking for the service process with ps
@ -587,7 +587,7 @@ def mod_watch(name,
if not past_participle:
past_participle = verb + 'ed'
else:
ret['comment'] = 'Unable to trigger watch for service.{0}'.format(sfun)
ret['comment'] = 'sfun must be set to either "running" or "dead"'
ret['result'] = False
return ret

View file

@ -189,6 +189,8 @@ def configurable_test_state(name, changes=True, result=True, comment=''):
Do we return successfully or not?
Accepts True, False, and 'Random'
Default is True
If test is True and changes is True, this will be None. If test is
True and and changes is False, this will be True.
comment:
String to fill the comment field with.
Default is ''
@ -199,33 +201,29 @@ def configurable_test_state(name, changes=True, result=True, comment=''):
'result': False,
'comment': comment
}
change_data = {
'testing': {
'old': 'Unchanged',
'new': 'Something pretended to change'
}
}
if changes == 'Random':
if random.choice([True, False]):
# Following the docs as written here
# http://docs.saltstack.com/ref/states/writing.html#return-data
ret['changes'] = {
'testing': {
'old': 'Unchanged',
'new': 'Something pretended to change'
}
}
ret['changes'] = change_data
elif changes is True:
# If changes is True we place our dummy change dictionary into it.
# Following the docs as written here
# http://docs.saltstack.com/ref/states/writing.html#return-data
ret['changes'] = {
'testing': {
'old': 'Unchanged',
'new': 'Something pretended to change'
}
}
ret['changes'] = change_data
elif changes is False:
ret['changes'] = {}
else:
err = ('You have specified the state option \'Changes\' with'
' invalid arguments. It must be either '
' \'True\', \'False\', or \'Random\'')
' invalid arguments. It must be either '
' \'True\', \'False\', or \'Random\'')
raise SaltInvocationError(err)
if result == 'Random':
@ -242,8 +240,8 @@ def configurable_test_state(name, changes=True, result=True, comment=''):
'\'Random\'')
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'This is a test'
ret['result'] = True if changes is False else None
ret['comment'] = 'This is a test' if not comment else comment
return ret

View file

@ -14,29 +14,40 @@ def __virtual__():
return 'win_servermanager' if 'win_servermanager.install' in __salt__ else False
def installed(name, recurse=False, force=False):
def installed(name,
recurse=False,
force=False,
source=None,
restart=False,
exclude=None):
'''
Install the windows feature
name:
short name of the feature (the right column in win_servermanager.list_available)
recurse:
install all sub-features as well
force:
if the feature is installed but on of its sub-features are not installed set this to True to force
the installation of the sub-features
Args:
name (str): Short name of the feature (the right column in
win_servermanager.list_available)
recurse (Optional[bool]): install all sub-features as well
force (Optional[bool]): if the feature is installed but one of its
sub-features are not installed set this to True to force the
installation of the sub-features
source (Optional[str]): Path to the source files if missing from the
target system. None means that the system will use windows update
services to find the required files. Default is None
restart (Optional[bool]): Restarts the computer when installation is
complete, if required by the role/feature installed. Default is
False
exclude (Optional[str]): The name of the feature to exclude when
installing the named feature.
Note:
Some features require reboot after un/installation. If so, until the server is restarted
other features can not be installed!
Some features require reboot after un/installation. If so, until the
server is restarted other features can not be installed!
Example:
Run ``salt MinionName win_servermanager.list_available`` to get a list of available roles and features. Use
the name in the right column. Do not use the role or feature names mentioned in the PKGMGR documentation. In
this example for IIS-WebServerRole the name to be used is Web-Server.
Run ``salt MinionName win_servermanager.list_available`` to get a list
of available roles and features. Use the name in the right column. Do
not use the role or feature names mentioned in the PKGMGR documentation.
In this example for IIS-WebServerRole the name to be used is Web-Server.
.. code-block:: yaml
@ -73,7 +84,8 @@ def installed(name, recurse=False, force=False):
ret['changes'] = {}
# Install the features
status = __salt__['win_servermanager.install'](name, recurse)
status = __salt__['win_servermanager.install'](
name, recurse, source, restart, exclude)
ret['result'] = status['Success']
if not ret['result']:
@ -91,23 +103,27 @@ def installed(name, recurse=False, force=False):
return ret
def removed(name):
def removed(name, remove_payload=False, restart=False):
'''
Remove the windows feature
name:
short name of the feature (the right column in win_servermanager.list_available)
Args:
name (str): Short name of the feature (the right column in
win_servermanager.list_available)
remove_payload (Optional[bool]): True will case the feature to be
removed from the side-by-side store
restart (Optional[bool]): Restarts the computer when uninstall is
complete, if required by the role/feature removed. Default is False
.. note::
Some features require a reboot after uninstallation. If so the feature will not be completely uninstalled until
the server is restarted.
Note:
Some features require a reboot after uninstallation. If so the feature
will not be completely uninstalled until the server is restarted.
Example:
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.
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
@ -134,7 +150,7 @@ def removed(name):
ret['changes'] = {}
# Remove the features
status = __salt__['win_servermanager.remove'](name)
status = __salt__['win_servermanager.remove'](name, remove_payload, restart)
ret['result'] = status['Success']
if not ret['result']:

View file

@ -1045,11 +1045,14 @@ class Pygit2(GitProvider):
return None
remote_head = 'refs/remotes/origin/' + branch_name
if remote_head not in refs:
log.error(
'Unable to find remote ref \'{0}\' in {1} remote '
'\'{2}\''.format(head_ref, self.role, self.id)
)
return None
# No remote ref for HEAD exists. This can happen in
# the first-time git_pillar checkout when when the
# remote repo does not have a master branch. Since
# we need a HEAD reference to keep pygit2 from
# throwing an error, and none exists in
# refs/remotes/origin, we'll just point HEAD at the
# remote_ref.
remote_head = remote_ref
self.repo.create_reference(
head_ref,
self.repo.lookup_reference(remote_head).target

View file

@ -0,0 +1,151 @@
# -*- coding: utf-8 -*-
'''
Integration tests for Ruby Gem module
'''
# Import Python libs
from __future__ import absolute_import
import platform
# Import Salt Testing libs
from salttesting import skipIf
from salttesting.helpers import ensure_in_syspath, destructiveTest
ensure_in_syspath('../../')
# Import salt libs
import integration
import salt.utils
import salt.utils.http
GEM = 'rake'
GEM_VER = '11.1.2'
OLD_GEM = 'thor'
OLD_VERSION = '0.17.0'
DEFAULT_GEMS = ['bigdecimal', 'rake', 'json', 'rdoc']
ON_UBUNTU = False
if 'Ubuntu' in platform.dist():
ON_UBUNTU = True
def check_status():
'''
Check the status of the rubygems source
'''
ret = salt.utils.http.query('https://rubygems.org', status=True)
return ret['status'] == 200
@destructiveTest
@skipIf(not salt.utils.which('gem'), 'Gem is not available')
@skipIf(not check_status(), 'External source \'https://rubygems.org\' is not available')
class GemModuleTest(integration.ModuleCase):
'''
Validate gem module
'''
def test_install_uninstall(self):
'''
gem.install
gem.uninstall
'''
# Remove gem if it is already installed
if self.run_function('gem.list', [GEM]):
self.run_function('gem.uninstall', [GEM])
self.run_function('gem.install', [GEM])
gem_list = self.run_function('gem.list', [GEM])
self.assertIn(GEM, gem_list)
self.run_function('gem.uninstall', [GEM])
self.assertFalse(self.run_function('gem.list', [GEM]))
def test_install_version(self):
'''
gem.install rake version=11.1.2
'''
# Remove gem if it is already installed
if self.run_function('gem.list', [GEM]):
self.run_function('gem.uninstall', [GEM])
self.run_function('gem.install', [GEM], version=GEM_VER)
gem_list = self.run_function('gem.list', [GEM])
self.assertIn(GEM, gem_list)
self.assertIn(GEM_VER, gem_list[GEM])
self.run_function('gem.uninstall', [GEM])
self.assertFalse(self.run_function('gem.list', [GEM]))
def test_list(self):
'''
gem.list
'''
self.run_function('gem.install', [GEM])
all_ret = self.run_function('gem.list')
if not ON_UBUNTU:
for gem in DEFAULT_GEMS:
self.assertIn(gem, all_ret)
single_ret = self.run_function('gem.list', [GEM])
self.assertIn(GEM, single_ret)
self.assertIn(GEM_VER, single_ret[GEM])
self.run_function('gem.uninstall', [GEM])
def test_list_upgrades(self):
'''
gem.list_upgrades
'''
# install outdated gem
self.run_function('gem.install', [OLD_GEM], version=OLD_VERSION)
ret = self.run_function('gem.list_upgrades')
self.assertIn(OLD_GEM, ret)
self.run_function('gem.uninstall', [OLD_GEM])
def test_sources_add_remove(self):
'''
gem.sources_add
gem.sources_remove
'''
source = 'http://gems.github.com'
self.run_function('gem.sources_add', [source])
sources_list = self.run_function('gem.sources_list')
self.assertIn(source, sources_list)
self.run_function('gem.sources_remove', [source])
sources_list = self.run_function('gem.sources_list')
self.assertNotIn(source, sources_list)
def test_update(self):
'''
gem.update
'''
# Remove gem if it is already installed
if self.run_function('gem.list', [OLD_GEM]):
self.run_function('gem.uninstall', [OLD_GEM])
self.run_function('gem.install', [OLD_GEM], version=OLD_VERSION)
gem_list = self.run_function('gem.list', [OLD_GEM])
self.assertEqual({'thor': ['0.17.0']}, gem_list)
self.run_function('gem.update', [OLD_GEM])
gem_list = self.run_function('gem.list', [OLD_GEM])
self.assertEqual({'thor': ['0.19.1', '0.17.0']}, gem_list)
self.run_function('gem.uninstall', [OLD_GEM])
self.assertFalse(self.run_function('gem.list', [OLD_GEM]))
def test_udpate_system(self):
'''
gem.udpate_system
'''
ret = self.run_function('gem.update_system')
self.assertTrue(ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(GemModuleTest)

View file

@ -53,6 +53,63 @@ _PKG_TARGETS_EPOCH = {
}
def pkgmgr_avail(run_function, grains):
'''
Return True if the package manager is available for use
'''
def proc_fd_lsof(path):
'''
Return True if any entry in /proc/locks points to path. Example data:
.. code-block:: bash
# cat /proc/locks
1: FLOCK ADVISORY WRITE 596 00:0f:10703 0 EOF
2: FLOCK ADVISORY WRITE 14590 00:0f:11282 0 EOF
3: POSIX ADVISORY WRITE 653 00:0f:11422 0 EOF
'''
import glob
# https://www.centos.org/docs/5/html/5.2/Deployment_Guide/s2-proc-locks.html
locks = run_function('cmd.run', ['cat /proc/locks']).splitlines()
for line in locks:
fields = line.split()
try:
major, minor, inode = fields[5].split(':')
inode = int(inode)
except (IndexError, ValueError):
return False
for fd in glob.glob('/proc/*/fd'):
fd_path = os.path.realpath(fd)
# If the paths match and the inode is locked
if fd_path == path and os.stat(fd_path).st_ino == inode:
return True
return False
def get_lock(path):
'''
Return True if any locks are found for path
'''
# Try lsof if it's available
if salt.utils.which('lsof'):
lock = run_function('cmd.run', ['lsof {0}'.format(path)])
return True if len(lock) else False
# Try to find any locks on path from /proc/locks
elif grains.get('kernel') == 'Linux':
return proc_fd_lsof(path)
return False
if 'Debian' in grains.get('os_family', ''):
for path in ['/var/lib/apt/lists/lock']:
if get_lock(path):
return False
return True
@destructiveTest
@requires_salt_modules('pkg.version', 'pkg.latest_version')
class PkgTest(integration.ModuleCase,
@ -66,6 +123,10 @@ class PkgTest(integration.ModuleCase,
'''
This is a destructive test as it installs and then removes a package
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
os_family = grains.get('os_family', '')
pkg_targets = _PKG_TARGETS.get(os_family, [])
@ -93,6 +154,10 @@ class PkgTest(integration.ModuleCase,
'''
This is a destructive test as it installs and then removes a package
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
os_family = grains.get('os_family', '')
pkg_targets = _PKG_TARGETS.get(os_family, [])
@ -134,6 +199,10 @@ class PkgTest(integration.ModuleCase,
'''
This is a destructive test as it installs and then removes two packages
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
os_family = grains.get('os_family', '')
pkg_targets = _PKG_TARGETS.get(os_family, [])
@ -146,7 +215,7 @@ class PkgTest(integration.ModuleCase,
# If this assert fails, we need to find new targets, this test needs to
# be able to test successful installation of packages, so these
# packages need to not be installed before we run the states below
# self.assertFalse(any(version.values()))
#self.assertFalse(any(version.values()))
ret = self.run_state('pkg.installed', name=None, pkgs=pkg_targets)
self.assertSaltTrueReturn(ret)
@ -159,6 +228,10 @@ class PkgTest(integration.ModuleCase,
'''
This is a destructive test as it installs and then removes two packages
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
os_family = grains.get('os_family', '')
pkg_targets = _PKG_TARGETS.get(os_family, [])
@ -201,6 +274,10 @@ class PkgTest(integration.ModuleCase,
'''
This is a destructive test as it installs and then removes a package
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
os_name = grains.get('os', '')
target = _PKG_TARGETS_32.get(os_name, '')
@ -232,6 +309,10 @@ class PkgTest(integration.ModuleCase,
'''
This is a destructive test as it installs and then removes a package
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
os_name = grains.get('os', '')
target = _PKG_TARGETS_32.get(os_name, '')
@ -275,6 +356,10 @@ class PkgTest(integration.ModuleCase,
This is a destructive test as it installs a package
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
os_family = grains.get('os_family', '')
os_version = grains.get('osmajorrelease', [''])[0]
target = _PKG_TARGETS_DOT.get(os_family, {}).get(os_version)
@ -299,6 +384,10 @@ class PkgTest(integration.ModuleCase,
This is a destructive test as it installs a package
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
os_family = grains.get('os_family', '')
os_version = grains.get('osmajorrelease', [''])[0]
target = _PKG_TARGETS_EPOCH.get(os_family, {}).get(os_version)
@ -323,6 +412,9 @@ class PkgTest(integration.ModuleCase,
This is a destructive test as it installs a package
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
ret = self.run_function('state.sls', mods='pkg_latest_epoch')
self.assertSaltTrueReturn(ret)
@ -336,6 +428,9 @@ class PkgTest(integration.ModuleCase,
a seperate method so I can add the requires_salt_modules
decorator to only the pkg.info_installed command.
'''
# Skip test if package manager not available
if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
self.skipTest('Package manager is not available')
package = 'bash-completion'
pkgquery = 'version'

View file

@ -0,0 +1,705 @@
# -*- coding: utf-8 -*-
'''
Tests for the service state
'''
# Import python libs
from __future__ import absolute_import
import os
# Import Salt Testing libs
from salttesting import skipIf
from salttesting.helpers import ensure_in_syspath, destructiveTest
ensure_in_syspath('../../')
# Import salt libs
from integration import ModuleCase, SaltReturnAssertsMixIn
# used to cache the status of whether the package was installed for quick test
# skipping if it was not
PKG_INSTALLED = None
def installed(run_function, package):
'''
Install apache prior to running tests so that they may be skipped if the
package fails to download
'''
global PKG_INSTALLED
if not PKG_INSTALLED:
run_function('state.single', ['pkg.installed', package])
PKG_INSTALLED = True if run_function('pkg.version', [package]) else False
return PKG_INSTALLED
@destructiveTest
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
class ServiceTest(ModuleCase,
SaltReturnAssertsMixIn):
'''
Test service state module
'''
def setUp(self):
'''
Setup package and service names
'''
# Taken from https://github.com/saltstack-formulas/apache-formula/blob/master/apache/map.jinja
os_family = self.run_function('grains.get', ['os_family'])
if os_family == 'Debian':
self.package = 'apache2'
self.service = 'apache2'
elif os_family == 'RedHat':
self.package = 'httpd'
self.service = 'httpd'
elif os_family == 'Suse':
self.package = 'apache2'
self.service = 'apache2'
elif os_family == 'FreeBSD':
self.package = 'apache22'
self.service = 'apache22'
elif os_family == 'MacOS':
self.package = 'homebrew/apache/httpd24'
self.service = 'org.apache.httpd'
else:
self.skipTest('This platform, {0}, has not yet been configured'
' to run this test'.format(os_family))
def test_aaa_setUp_package(self):
'''
Install apache package
'''
installed(self.run_function, self.package)
def test_zzz_tearDown_package(self):
'''
Remove apache package
'''
# Skip if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
self.run_function('state.single', ['pkg.removed', self.package])
def test_running(self):
'''
Test service.running
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
state_params = [
'service.running',
'name={0}'.format(self.service),
]
# Setup initial state, run base test and inductive test
self.run_function('state.single', ['service.dead', self.service])
start_ret = self.run_function('state.single', state_params)
already_ret = self.run_function('state.single', state_params)
# Validate base state
self.assertSaltTrueReturn(start_ret)
self.assertInSaltComment('Started Service {0}'.format(self.service), start_ret)
self.assertSaltStateChangesEqual(start_ret, {self.service: True})
# Validate inductive state
self.assertSaltTrueReturn(already_ret)
self.assertInSaltComment('The service {0} is already running'.format(self.service), already_ret)
self.assertSaltStateChangesEqual(already_ret, {})
def test_running_test(self):
'''
Test service.running with test=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
state_params = [
'service.running',
'name={0}'.format(self.service),
'test=True',
]
# apply the state in test mode
self.run_function('state.single', ['service.dead', self.service])
test_ret = self.run_function('state.single', state_params)
# Validate test state
self.assertSaltNoneReturn(test_ret)
self.assertInSaltComment('Service {0} is set to start'.format(self.service), test_ret)
self.assertSaltStateChangesEqual(test_ret, {})
def test_running_enabled(self):
'''
Test service.running with enable=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
for func in 'enable', 'enabled':
if not self.run_function('sys.doc', ['service.{0}'.format(func)]):
self.skipTest('service.{0} function is not available on this system'.format(func))
# Configure state parameters
enabled_params = [
'service.running',
'name={0}'.format(self.service),
'enable=True',
]
# Apply state with enable parameter True
self.run_function('state.single', ['service.dead', self.service, 'enable=False'])
enabled_ret = self.run_function('state.single', enabled_params)
# Validate enabled state
self.assertSaltTrueReturn(enabled_ret)
self.assertInSaltComment('enabled', enabled_ret)
self.assertSaltStateChangesEqual(enabled_ret, {self.service: True})
# Apply state a second time with enable parameter True
self.run_function('state.single', ['service.dead', self.service])
already_enabled_ret = self.run_function('state.single', enabled_params)
# Validate enabled state
self.assertSaltTrueReturn(already_enabled_ret)
self.assertInSaltComment('already enabled', already_enabled_ret)
self.assertSaltStateChangesEqual(already_enabled_ret, {self.service: True})
def test_running_disabled(self):
'''
Test service.running with enable=False
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
for func in 'disable', 'disabled':
if not self.run_function('sys.doc', ['service.{0}'.format(func)]):
self.skipTest('service.{0} function is not available on this system'.format(func))
# Configure state parameters
disabled_params = [
'service.running',
'name={0}'.format(self.service),
'enable=False',
]
# Apply state with enable parameter False
self.run_function('state.single', ['service.dead', self.service, 'enable=True'])
disabled_ret = self.run_function('state.single', disabled_params)
# Validate disabled state
self.assertSaltTrueReturn(disabled_ret)
self.assertInSaltComment('disabled', disabled_ret)
self.assertSaltStateChangesEqual(disabled_ret, {self.service: True})
# Apply state a second time with enable parameter False
self.run_function('state.single', ['service.dead', self.service])
already_disabled_ret = self.run_function('state.single', disabled_params)
self.assertSaltStateChangesEqual(disabled_ret, {self.service: True})
# Validate disabled state
self.assertSaltTrueReturn(already_disabled_ret)
self.assertInSaltComment('already disabled', already_disabled_ret)
self.assertSaltStateChangesEqual(already_disabled_ret, {self.service: True})
def test_running_delayed(self):
'''
Test service.running with delay
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
init_delay = 6.2832
delayed_params = [
'service.running',
'name={0}'.format(self.service),
'init_delay={0}'.format(init_delay)
]
state_key = 'service_|-{0}_|-{0}_|-running'.format(self.service)
# Apply state with init_delay parameter
self.run_function('state.single', ['service.dead', self.service])
delayed_ret = self.run_function('state.single', delayed_params)
# Validate delayed state
self.assertSaltTrueReturn(delayed_ret)
self.assertInSaltComment('Delayed return for {0} seconds'.format(init_delay), delayed_ret)
self.assertSaltStateChangesEqual(delayed_ret, {self.service: True})
self.assertTrue(delayed_ret[state_key]['duration']/1000 >= init_delay)
def test_dead(self):
'''
Test service.dead
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
state_params = [
'service.dead',
'name={0}'.format(self.service),
]
# Setup initial state, run base test and inductive test
self.run_function('state.single', ['service.running', self.service, 'init_delay=3'])
kill_ret = self.run_function('state.single', state_params)
already_ret = self.run_function('state.single', state_params)
# Validate base state
self.assertSaltTrueReturn(kill_ret)
self.assertInSaltComment('Service {0} was killed'.format(self.service), kill_ret)
self.assertSaltStateChangesEqual(kill_ret, {self.service: True})
# Validate inductive state
self.assertSaltTrueReturn(already_ret)
self.assertInSaltComment('The service {0} is already dead'.format(self.service), already_ret)
self.assertSaltStateChangesEqual(already_ret, {})
def test_dead_test(self):
'''
Test service.dead with test=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
state_params = [
'service.dead',
'name={0}'.format(self.service),
'test=True',
]
# apply the state in test mode
self.run_function('state.single', ['service.running', self.service, 'init_delay=3'])
test_ret = self.run_function('state.single', state_params)
# Validate base state
self.assertSaltNoneReturn(test_ret)
self.assertInSaltComment('Service {0} is set to be killed'.format(self.service), test_ret)
self.assertSaltStateChangesEqual(test_ret, {})
def test_dead_enabled(self):
'''
Test service.dead with enable=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
for func in 'enable', 'enabled':
if not self.run_function('sys.doc', ['service.{0}'.format(func)]):
self.skipTest('service.{0} function is not available on this system'.format(func))
# Configure state parameters
enabled_params = [
'service.dead',
'name={0}'.format(self.service),
'enable=True',
]
# Apply state with enable parameter True
self.run_function('state.single', ['service.running', self.service, 'enable=False', 'init_delay=3'])
enabled_ret = self.run_function('state.single', enabled_params)
# Validate enabled state
self.assertSaltTrueReturn(enabled_ret)
self.assertInSaltComment('enabled', enabled_ret)
self.assertSaltStateChangesEqual(enabled_ret, {self.service: True})
# Apply state a second time with enable parameter True
self.run_function('state.single', ['service.running', self.service, 'init_delay=3'])
already_enabled_ret = self.run_function('state.single', enabled_params)
# Validate enabled state
self.assertSaltTrueReturn(already_enabled_ret)
self.assertInSaltComment('already enabled', already_enabled_ret)
self.assertSaltStateChangesEqual(already_enabled_ret, {self.service: True})
def test_dead_disabled(self):
'''
Test service.dead with enable=False
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
for func in 'disable', 'disabled':
if not self.run_function('sys.doc', ['service.{0}'.format(func)]):
self.skipTest('service.{0} function is not available on this system'.format(func))
# Configure state parameters
disabled_params = [
'service.dead',
'name={0}'.format(self.service),
'enable=False',
]
# Apply state with enable parameter False
self.run_function('state.single', ['service.running', self.service, 'enable=True', 'init_delay=3'])
disabled_ret = self.run_function('state.single', disabled_params)
# Validate disabled state
self.assertSaltTrueReturn(disabled_ret)
self.assertInSaltComment('disabled', disabled_ret)
self.assertSaltStateChangesEqual(disabled_ret, {self.service: True})
# Apply state a second time with enable parameter False
self.run_function('state.single', ['service.running', self.service, 'init_delay=3'])
already_disabled_ret = self.run_function('state.single', disabled_params)
self.assertSaltStateChangesEqual(disabled_ret, {self.service: True})
# Validate disabled state
self.assertSaltTrueReturn(already_disabled_ret)
self.assertInSaltComment('already disabled', already_disabled_ret)
self.assertSaltStateChangesEqual(already_disabled_ret, {self.service: True})
def test_enabled(self):
'''
Test service.enabled
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
for func in 'enable', 'enabled':
if not self.run_function('sys.doc', ['service.{0}'.format(func)]):
self.skipTest('service.{0} function is not available on this system'.format(func))
# Configure state parameters
state_params = [
'service.enabled',
'name={0}'.format(self.service),
]
# Apply state
self.run_function('state.single', ['service.disabled', self.service])
enabled_ret = self.run_function('state.single', state_params)
# Validate enabled state
self.assertSaltTrueReturn(enabled_ret)
self.assertInSaltComment('enabled', enabled_ret)
self.assertSaltStateChangesEqual(enabled_ret, {self.service: True})
# Apply state a second time
already_enabled_ret = self.run_function('state.single', state_params)
# Validate enabled state
self.assertSaltTrueReturn(already_enabled_ret)
self.assertInSaltComment('already enabled', already_enabled_ret)
self.assertSaltStateChangesEqual(already_enabled_ret, {})
def test_enabled_test(self):
'''
Test service.enabled with test=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
for func in 'enable', 'enabled':
if not self.run_function('sys.doc', ['service.{0}'.format(func)]):
self.skipTest('service.{0} function is not available on this system'.format(func))
# Configure state parameters
state_params = [
'service.enabled',
'name={0}'.format(self.service),
'test=True',
]
# apply the state in test mode
self.run_function('state.single', ['service.disabled', self.service])
test_ret = self.run_function('state.single', state_params)
# Validate base state
self.assertSaltNoneReturn(test_ret)
self.assertInSaltComment('Service {0} set to be enabled'.format(self.service), test_ret)
self.assertSaltStateChangesEqual(test_ret, {})
def test_disabled(self):
'''
Test service.disabled
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
for func in 'disable', 'disabled':
if not self.run_function('sys.doc', ['service.{0}'.format(func)]):
self.skipTest('service.{0} function is not available on this system'.format(func))
# Configure state parameters
state_params = [
'service.disabled',
'name={0}'.format(self.service),
]
# Apply state
self.run_function('state.single', ['service.enabled', self.service])
disabled_ret = self.run_function('state.single', state_params)
# Validate disabled state
self.assertSaltTrueReturn(disabled_ret)
self.assertInSaltComment('disabled', disabled_ret)
self.assertSaltStateChangesEqual(disabled_ret, {self.service: True})
# Apply state a second time
already_disabled_ret = self.run_function('state.single', state_params)
# Validate disabled state
self.assertSaltTrueReturn(already_disabled_ret)
self.assertInSaltComment('already disabled', already_disabled_ret)
self.assertSaltStateChangesEqual(already_disabled_ret, {})
def test_disabled_test(self):
'''
Test service.disabled with test=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
for func in 'disable', 'disabled':
if not self.run_function('sys.doc', ['service.{0}'.format(func)]):
self.skipTest('service.{0} function is not available on this system'.format(func))
# Configure state parameters
state_params = [
'service.disabled',
'name={0}'.format(self.service),
'test=True',
]
# apply the state in test mode
self.run_function('state.single', ['service.enabled', self.service])
test_ret = self.run_function('state.single', state_params)
# Validate base state
self.assertSaltNoneReturn(test_ret)
self.assertInSaltComment('Service {0} set to be disabled'.format(self.service), test_ret)
self.assertSaltStateChangesEqual(test_ret, {})
def test_mod_watch_test(self):
'''
Test service.mod_watch with test=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
state_params = [
'service.mod_watch',
'name={0}'.format(self.service),
'sfun=running',
'test=True',
]
# apply the state in test mode
self.run_function('state.single', ['service.dead', self.service])
test_ret = self.run_function('state.single', state_params)
# Validate base state
self.assertSaltNoneReturn(test_ret)
self.assertInSaltComment('Service is set to be started', test_ret)
self.assertSaltStateChangesEqual(test_ret, {})
def test_mod_watch_no_sfun(self):
'''
Test service.mod_watch without sfun argument
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
state_params = [
'service.mod_watch',
'name={0}'.format(self.service),
]
# Apply the state
mod_watch_ret = self.run_function('state.single', state_params)
# Validate state return
self.assertSaltFalseReturn(mod_watch_ret)
self.assertInSaltComment('sfun must be set to either "running" or "dead"', mod_watch_ret)
self.assertSaltStateChangesEqual(mod_watch_ret, {})
def test_mod_watch_running(self):
'''
Test service.mod_watch with sfun=running
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
state_params = [
'service.mod_watch',
'name={0}'.format(self.service),
'sfun=running',
]
# Apply state
self.run_function('state.single', ['service.dead', self.service])
running_ret = self.run_function('state.single', state_params)
# Validate state return
self.assertSaltTrueReturn(running_ret)
self.assertInSaltComment('Service started', running_ret)
self.assertSaltStateChangesEqual(running_ret, {self.service: True})
# Apply state a second time
already_running_ret = self.run_function('state.single', state_params)
# Validate disabled state
self.assertSaltTrueReturn(already_running_ret)
self.assertInSaltComment('Service restarted', already_running_ret)
self.assertSaltStateChangesEqual(already_running_ret, {self.service: True})
def test_mod_watch_running_reload(self):
'''
Test service.mod_watch with sfun=running and reload=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
if not self.run_function('sys.doc', ['service.reload']):
self.skipTest('service.reload function is not available on this system')
# Configure state parameters
state_params = [
'service.mod_watch',
'name={0}'.format(self.service),
'sfun=running',
'reload=True',
]
# Apply state
self.run_function('state.single', ['service.running', self.service, 'init_delay=3'])
state_ret = self.run_function('state.single', state_params)
# Validate disabled state
self.assertSaltTrueReturn(state_ret)
self.assertInSaltComment('Service reloaded', state_ret)
self.assertSaltStateChangesEqual(state_ret, {self.service: True})
def test_mod_watch_running_force(self):
'''
Test service.mod_watch with sfun=running and force=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
for func in 'reload', 'force_reload':
if not self.run_function('sys.doc', ['service.{0}'.format(func)]):
self.skipTest('service.{0} function is not available on this system'.format(func))
# Configure state parameters
state_params = [
'service.mod_watch',
'name={0}'.format(self.service),
'sfun=running',
'reload=True',
'force=True',
]
# Apply state
self.run_function('state.single', ['service.running', self.service, 'init_delay=3'])
state_ret = self.run_function('state.single', state_params)
# Validate disabled state
self.assertSaltTrueReturn(state_ret)
self.assertInSaltComment('Service forcefully reloaded', state_ret)
self.assertSaltStateChangesEqual(state_ret, {self.service: True})
def test_mod_watch_running_full_restart(self):
'''
Test service.mod_watch with sfun=running and full_restart=True
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Skip test if functionality not present on system
if not self.run_function('sys.doc', ['service.full_restart']):
self.skipTest('service.full_restart function is not available on this system')
# Configure state parameters
state_params = [
'service.mod_watch',
'name={0}'.format(self.service),
'sfun=running',
'full_restart=True',
]
# Apply state
self.run_function('state.single', ['service.running', self.service, 'init_delay=3'])
state_ret = self.run_function('state.single', state_params)
# Validate state return
self.assertSaltTrueReturn(state_ret)
self.assertInSaltComment('Service fully restarted', state_ret)
self.assertSaltStateChangesEqual(state_ret, {self.service: True})
def test_mod_watch_running_init_delay(self):
'''
Test service.mod_watch with sfun=running and init_delay
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
init_delay = 6.2832
state_params = [
'service.mod_watch',
'name={0}'.format(self.service),
'sfun=running',
'init_delay={0}'.format(init_delay),
]
state_key = 'service_|-{0}_|-{0}_|-mod_watch'.format(self.service)
# Apply state
self.run_function('state.single', ['service.dead', self.service])
state_ret = self.run_function('state.single', state_params)
# Validate state return
self.assertSaltTrueReturn(state_ret)
self.assertInSaltComment('Service started', state_ret)
self.assertSaltStateChangesEqual(state_ret, {self.service: True})
self.assertTrue(state_ret[state_key]['duration']/1000 >= init_delay)
def test_mod_watch_dead(self):
'''
Test service.mod_watch with sfun=dead
'''
# Skip test if package was not installed
if not PKG_INSTALLED:
self.skipTest('Package containing service used by test was not installed')
# Configure state parameters
state_params = [
'service.mod_watch',
'name={0}'.format(self.service),
'sfun=dead',
]
# Apply state
self.run_function('state.single', ['service.running', self.service, 'init_delay=3'])
mod_watch_ret = self.run_function('state.single', state_params)
# Validate state return
self.assertSaltTrueReturn(mod_watch_ret)
self.assertInSaltComment('Service stopped', mod_watch_ret)
self.assertSaltStateChangesEqual(mod_watch_ret, {self.service: True})
# Apply state a second time
already_mod_watch_ret = self.run_function('state.single', state_params)
# Validate disabled state
self.assertSaltTrueReturn(already_mod_watch_ret)
self.assertInSaltComment('Service is already stopped', already_mod_watch_ret)
self.assertSaltStateChangesEqual(already_mod_watch_ret, {})
if __name__ == '__main__':
from integration import run_tests
run_tests(ServiceTest)

View file

@ -112,14 +112,26 @@ class GroupAddTestCase(TestCase):
'''
Tests if specified user gets added in the group.
'''
mock = MagicMock(return_value={'retcode': 0})
with patch.dict(groupadd.__grains__, {'kernel': 'Linux'}):
with patch.dict(groupadd.__salt__, {'cmd.retcode': mock}):
self.assertFalse(groupadd.adduser('test', 'root'))
os_version_list = [
{'grains': {'kernel': 'Linux', 'os_family': 'RedHat', 'osmajorrelease': '5'},
'cmd': 'gpasswd -a root test'},
with patch.dict(groupadd.__grains__, {'kernel': ''}):
with patch.dict(groupadd.__salt__, {'cmd.retcode': mock}):
self.assertFalse(groupadd.adduser('test', 'root'))
{'grains': {'kernel': 'Linux', 'os_family': 'Suse', 'osrelease_info': [11, 2]},
'cmd': 'usermod -A test root'},
{'grains': {'kernel': 'Linux'},
'cmd': 'gpasswd --add root test'},
{'grains': {'kernel': 'OTHERKERNEL'},
'cmd': 'usermod -G test root'},
]
for os_version in os_version_list:
mock = MagicMock(return_value={'retcode': 0})
with patch.dict(groupadd.__grains__, os_version['grains']):
with patch.dict(groupadd.__salt__, {'cmd.retcode': mock}):
self.assertFalse(groupadd.adduser('test', 'root'))
groupadd.__salt__['cmd.retcode'].assert_called_once_with(os_version['cmd'], python_shell=False)
# 'deluser' function tests: 1
@ -127,22 +139,34 @@ class GroupAddTestCase(TestCase):
'''
Tests if specified user gets deleted from the group.
'''
mock_ret = MagicMock(return_value={'retcode': 0})
mock_info = MagicMock(return_value={'passwd': '*',
'gid': 0,
'name': 'test',
'members': ['root']})
with patch.dict(groupadd.__grains__, {'kernel': 'Linux'}):
with patch.dict(groupadd.__salt__, {'cmd.retcode': mock_ret,
'group.info': mock_info}):
self.assertFalse(groupadd.deluser('test', 'root'))
os_version_list = [
{'grains': {'kernel': 'Linux', 'os_family': 'RedHat', 'osmajorrelease': '5'},
'cmd': 'gpasswd -d root test'},
mock_stdout = MagicMock(return_value={'cmd.run_stdout': 1})
with patch.dict(groupadd.__grains__, {'kernel': 'OpenBSD'}):
with patch.dict(groupadd.__salt__, {'cmd.retcode': mock_ret,
'group.info': mock_info,
'cmd.run_stdout': mock_stdout}):
self.assertTrue(groupadd.deluser('foo', 'root'))
{'grains': {'kernel': 'Linux', 'os_family': 'Suse', 'osrelease_info': [11, 2]},
'cmd': 'usermod -R test root'},
{'grains': {'kernel': 'Linux'},
'cmd': 'gpasswd --del root test'},
{'grains': {'kernel': 'OpenBSD'},
'cmd': 'usermod -S foo root'},
]
for os_version in os_version_list:
mock_ret = MagicMock(return_value={'retcode': 0})
mock_stdout = MagicMock(return_value='test foo')
mock_info = MagicMock(return_value={'passwd': '*',
'gid': 0,
'name': 'test',
'members': ['root']})
with patch.dict(groupadd.__grains__, os_version['grains']):
with patch.dict(groupadd.__salt__, {'cmd.retcode': mock_ret,
'group.info': mock_info,
'cmd.run_stdout': mock_stdout}):
self.assertFalse(groupadd.deluser('test', 'root'))
groupadd.__salt__['cmd.retcode'].assert_called_once_with(os_version['cmd'], python_shell=False)
# 'deluser' function tests: 1
@ -150,24 +174,36 @@ class GroupAddTestCase(TestCase):
'''
Tests if members of the group, get replaced with a provided list.
'''
mock_ret = MagicMock(return_value={'retcode': 0})
mock_info = MagicMock(return_value={'passwd': '*',
'gid': 0,
'name': 'test',
'members': ['root']})
with patch.dict(groupadd.__grains__, {'kernel': 'Linux'}):
with patch.dict(groupadd.__salt__, {'cmd.retcode': mock_ret,
'group.info': mock_info}):
self.assertFalse(groupadd.members('test', ['foo']))
os_version_list = [
{'grains': {'kernel': 'Linux', 'os_family': 'RedHat', 'osmajorrelease': '5'},
'cmd': "gpasswd -M foo test"},
mock_stdout = MagicMock(return_value={'cmd.run_stdout': 1})
mock = MagicMock()
with patch.dict(groupadd.__grains__, {'kernel': 'OpenBSD'}):
with patch.dict(groupadd.__salt__, {'cmd.retcode': mock_ret,
'group.info': mock_info,
'cmd.run_stdout': mock_stdout,
'cmd.run': mock}):
self.assertFalse(groupadd.members('foo', ['root']))
{'grains': {'kernel': 'Linux', 'os_family': 'Suse', 'osrelease_info': [11, 2]},
'cmd': 'groupmod -A foo test'},
{'grains': {'kernel': 'Linux'},
'cmd': 'gpasswd --members foo test'},
{'grains': {'kernel': 'OpenBSD'},
'cmd': 'usermod -G test foo'},
]
for os_version in os_version_list:
mock_ret = MagicMock(return_value={'retcode': 0})
mock_stdout = MagicMock(return_value={'cmd.run_stdout': 1})
mock_info = MagicMock(return_value={'passwd': '*',
'gid': 0,
'name': 'test',
'members': ['root']})
mock = MagicMock(return_value=True)
with patch.dict(groupadd.__grains__, os_version['grains']):
with patch.dict(groupadd.__salt__, {'cmd.retcode': mock_ret,
'group.info': mock_info,
'cmd.run_stdout': mock_stdout,
'cmd.run': mock}):
self.assertFalse(groupadd.members('test', 'foo'))
groupadd.__salt__['cmd.retcode'].assert_called_once_with(os_version['cmd'], python_shell=False)
if __name__ == '__main__':

View file

@ -1,179 +0,0 @@
# -*- coding: utf-8 -*-
'''
:codeauthor: :email:`Rupesh Tare <rupesht@saltstack.com>`
'''
# Import Python Libs
from __future__ import absolute_import
# Import Salt Testing Libs
from salttesting import TestCase, skipIf
from salttesting.mock import (
MagicMock,
patch,
NO_MOCK,
NO_MOCK_REASON
)
from salttesting.helpers import ensure_in_syspath
ensure_in_syspath('../../')
# Import Salt Libs
from salt.modules import match
import salt.ext.six.moves.builtins as __builtin__ # pylint: disable=import-error,no-name-in-module
# Globals
match.__grains__ = {}
match.__salt__ = {}
match.__opts__ = {}
match.__pillar__ = {}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class MatchTestCase(TestCase):
'''
Test cases for salt.modules.match
'''
@patch('salt.minion.Matcher')
def test_compound(self, mock_matcher):
'''
Test for Return True if the minion ID matches the given compound target
'''
with patch.dict(match.__grains__, {'id': 101}):
mock_matcher.side_effect = MagicMock()
with patch.object(mock_matcher, 'compound_match', MagicMock()):
self.assertTrue(match.compound('tgt'))
mock_matcher.side_effect = MagicMock(return_value='B')
self.assertFalse(match.compound('tgt'))
@patch('salt.minion.Matcher')
def test_ipcidr(self, mock_matcher):
'''
Test for Return True if the minion matches the given ipcidr target
'''
with patch.dict(match.__grains__, {'id': 101}):
mock_matcher.side_effect = MagicMock()
with patch.object(mock_matcher, 'ipcidr_match', MagicMock()):
self.assertTrue(match.ipcidr('tgt'))
mock_matcher.side_effect = MagicMock(return_value='B')
self.assertFalse(match.ipcidr('tgt'))
@patch('salt.minion.Matcher')
def test_pillar(self, mock_matcher):
'''
Test for Return True if the minion matches the given pillar target.
'''
with patch.dict(match.__grains__, {'id': 101}):
mock_matcher.side_effect = MagicMock()
with patch.object(mock_matcher, 'pillar_match', MagicMock()):
self.assertTrue(match.pillar('tgt'))
mock_matcher.side_effect = MagicMock(return_value='B')
self.assertFalse(match.pillar('tgt'))
@patch('salt.minion.Matcher')
def test_data(self, mock_matcher):
'''
Test for Return True if the minion matches the given data target
'''
with patch.dict(match.__grains__, {'id': 101}):
mock_matcher.side_effect = MagicMock()
with patch.object(mock_matcher, 'data_match', MagicMock()):
self.assertTrue(match.data('tgt'))
mock_matcher.side_effect = MagicMock(return_value='B')
self.assertFalse(match.data('tgt'))
@patch('salt.minion.Matcher')
def test_grain_pcre(self, mock_matcher):
'''
Test for Return True if the minion matches the given grain_pcre target
'''
with patch.dict(match.__grains__, {'id': 101}):
mock_matcher.side_effect = MagicMock()
with patch.object(mock_matcher, 'grain_pcre_match', MagicMock()):
self.assertTrue(match.grain_pcre('tgt'))
mock_matcher.side_effect = MagicMock(return_value='B')
self.assertFalse(match.grain_pcre('tgt'))
@patch('salt.minion.Matcher')
def test_grain(self, mock_matcher):
'''
Test for Return True if the minion matches the given grain target
'''
with patch.dict(match.__grains__, {'id': 101}):
mock_matcher.side_effect = MagicMock()
with patch.object(mock_matcher, 'grain_match', MagicMock()):
self.assertTrue(match.grain('tgt'))
mock_matcher.side_effect = MagicMock(return_value='B')
self.assertFalse(match.grain('tgt'))
@patch('salt.minion.Matcher')
def test_list_(self, mock_matcher):
'''
Test for Return True if the minion ID matches the given list target
'''
with patch.dict(match.__grains__, {'id': 101}):
mock_matcher.side_effect = MagicMock()
with patch.object(mock_matcher, 'list_match', MagicMock()):
self.assertTrue(match.list_('tgt'))
mock_matcher.side_effect = MagicMock(return_value='B')
self.assertFalse(match.list_('tgt'))
@patch('salt.minion.Matcher')
def test_pcre(self, mock_matcher):
'''
Test for Return True if the minion ID matches the given pcre target
'''
mock_matcher.side_effect = MagicMock()
with patch.dict(match.__grains__, {'id': 101}):
with patch.object(mock_matcher, 'pcre_match', MagicMock()):
self.assertTrue(match.pcre('tgt'))
mock_matcher.side_effect = MagicMock(return_value='B')
with patch.dict(match.__grains__, {'id': 101}):
self.assertFalse(match.pcre('tgt'))
@patch('salt.minion.Matcher')
def test_glob(self, mock_matcher):
'''
Test for Return True if the minion ID matches the given glob target
'''
with patch.dict(match.__grains__, {'id': 101}):
mock_matcher.side_effect = MagicMock()
with patch.object(mock_matcher, 'glob_match', MagicMock()):
self.assertTrue(match.glob('tgt'))
mock_matcher.side_effect = MagicMock(return_value='B')
self.assertFalse(match.glob('tgt'))
def test_filter_by(self):
'''
Test for Return the first match in a dictionary of target patterns
'''
with patch.object(__builtin__, 'dict', MagicMock()):
self.assertEqual(match.filter_by({'key': 'value'},
minion_id=101), 'value')
self.assertEqual(match.filter_by({'key': 'value'}), 'value')
self.assertEqual(match.filter_by({}), None)
if __name__ == '__main__':
from integration import run_tests
run_tests(MatchTestCase, needs_daemon=False)

View file

@ -117,7 +117,7 @@ class PkgresTestCase(TestCase):
'''
Test to add a package to a dict of installed packages.
'''
self.assertIsNone(pkg_resource.add_pkg('pkgs', 'name', 'version'))
self.assertIsNone(pkg_resource.add_pkg({'pkgs': []}, 'name', 'version'))
def test_sort_pkglist(self):
'''

View file

@ -18,6 +18,7 @@ from salt.modules import win_servermanager
# Globals
win_servermanager.__salt__ = {}
win_servermanager.__grains__ = {}
@skipIf(NO_MOCK, NO_MOCK_REASON)
@ -56,13 +57,15 @@ class WinServermanagerTestCase(TestCase):
'FeatureResult':
[{'DisplayName': 'Spongebob',
'RestartNeeded': False}]})
with patch.object(win_servermanager, '_pshell_json', mock):
expected = {'ExitCode': 0,
'DisplayName': 'Spongebob',
'RestartNeeded': False,
'Success': True}
self.assertDictEqual(
win_servermanager.install('Telnet-Client'), expected)
with patch.dict(
win_servermanager.__grains__, {'osversion': '10.0.15130'}):
with patch.object(win_servermanager, '_pshell_json', mock):
expected = {'ExitCode': 0,
'DisplayName': 'Spongebob',
'RestartNeeded': False,
'Success': True}
self.assertDictEqual(
win_servermanager.install('Telnet-Client'), expected)
def test_remove(self):
'''
@ -73,13 +76,15 @@ class WinServermanagerTestCase(TestCase):
'FeatureResult':
[{'DisplayName': 'Spongebob',
'RestartNeeded': False}]})
with patch.object(win_servermanager, '_pshell_json', mock):
expected = {'ExitCode': 0,
'DisplayName': 'Spongebob',
'RestartNeeded': False,
'Success': True}
self.assertDictEqual(
win_servermanager.remove('Telnet-Client'), expected)
with patch.dict(
win_servermanager.__grains__, {'osversion': '10.0.15130'}):
with patch.object(win_servermanager, '_pshell_json', mock):
expected = {'ExitCode': 0,
'DisplayName': 'Spongebob',
'RestartNeeded': False,
'Success': True}
self.assertDictEqual(
win_servermanager.remove('Telnet-Client'), expected)
if __name__ == '__main__':

View file

@ -255,7 +255,7 @@ class ServiceTestCase(TestCase):
'comment': 'Service is already stopped', 'name': 'salt',
'result': True},
{'changes': {},
'comment': 'Unable to trigger watch for service.stack',
'comment': 'sfun must be set to either "running" or "dead"',
'name': 'salt', 'result': False},
{'changes': {},
'comment': 'Service is set to be started', 'name': 'salt',

View file

@ -18,6 +18,7 @@ from salttesting.mock import (
ensure_in_syspath('../../')
# Import Salt Libs
from salt.exceptions import SaltInvocationError
from salt.states import test
# Globals
@ -88,19 +89,200 @@ class TestTestCase(TestCase):
def test_configurable_test_state(self):
'''
Test of a configurable test state which
determines its output based on the inputs.
Test test.configurable_test_state with and without comment
'''
ret = {'name': 'salt',
'changes': {},
'result': True,
'comment': ''}
with patch.dict(test.__opts__, {"test": False}):
ret.update({'changes': {'testing': {'new': 'Something pretended'
' to change',
'old': 'Unchanged'}},
'comment': 'Success!'})
self.assertDictEqual(test.succeed_with_changes('salt'), ret)
# Configure mock parameters
mock_name = 'cheese_shop'
mock_comment = "I'm afraid we're fresh out of Red Leicester sir."
mock_changes = {
'testing': {
'old': 'Unchanged',
'new': 'Something pretended to change'
}
}
# Test default state with comment
with patch.dict(test.__opts__, {'test': False}):
mock_ret = {'name': mock_name,
'changes': mock_changes,
'result': True,
'comment': ''}
ret = test.configurable_test_state(mock_name)
self.assertDictEqual(ret, mock_ret)
# Test default state without comment
with patch.dict(test.__opts__, {'test': False}):
mock_ret = {'name': mock_name,
'changes': mock_changes,
'result': True,
'comment': mock_comment}
ret = test.configurable_test_state(mock_name,
comment=mock_comment)
self.assertDictEqual(ret, mock_ret)
def test_configurable_test_state_changes(self):
'''
Test test.configurable_test_state with permutations of changes and with
comment
'''
# Configure mock parameters
mock_name = 'cheese_shop'
mock_comment = "I'm afraid we're fresh out of Red Leicester sir."
mock_changes = {
'testing': {
'old': 'Unchanged',
'new': 'Something pretended to change'
}
}
# Test changes=Random and comment
with patch.dict(test.__opts__, {'test': False}):
ret = test.configurable_test_state(mock_name,
changes='Random',
comment=mock_comment)
self.assertEqual(ret['name'], mock_name)
self.assertIn(ret['changes'], [mock_changes, {}])
self.assertEqual(ret['result'], True)
self.assertEqual(ret['comment'], mock_comment)
# Test changes=True and comment
with patch.dict(test.__opts__, {'test': False}):
mock_ret = {'name': mock_name,
'changes': mock_changes,
'result': True,
'comment': mock_comment}
ret = test.configurable_test_state(mock_name,
changes=True,
comment=mock_comment)
self.assertDictEqual(ret, mock_ret)
# Test changes=False and comment
with patch.dict(test.__opts__, {'test': False}):
mock_ret = {'name': mock_name,
'changes': {},
'result': True,
'comment': mock_comment}
ret = test.configurable_test_state(mock_name,
changes=False,
comment=mock_comment)
self.assertDictEqual(ret, mock_ret)
# Test changes=Cheese
with patch.dict(test.__opts__, {'test': False}):
self.assertRaises(SaltInvocationError,
test.configurable_test_state,
mock_name,
changes='Cheese')
def test_configurable_test_state_result(self):
'''
Test test.configurable_test_state with permutations of result and with
comment
'''
# Configure mock parameters
mock_name = 'cheese_shop'
mock_comment = "I'm afraid we're fresh out of Red Leicester sir."
mock_changes = {
'testing': {
'old': 'Unchanged',
'new': 'Something pretended to change'
}
}
# Test result=Random and comment
with patch.dict(test.__opts__, {'test': False}):
ret = test.configurable_test_state(mock_name,
result='Random',
comment=mock_comment)
self.assertEqual(ret['name'], mock_name)
self.assertEqual(ret['changes'], mock_changes)
self.assertIn(ret['result'], [True, False])
self.assertEqual(ret['comment'], mock_comment)
# Test result=True and comment
with patch.dict(test.__opts__, {'test': False}):
mock_ret = {'name': mock_name,
'changes': mock_changes,
'result': True,
'comment': mock_comment}
ret = test.configurable_test_state(mock_name,
result=True,
comment=mock_comment)
self.assertDictEqual(ret, mock_ret)
# Test result=False and comment
with patch.dict(test.__opts__, {'test': False}):
mock_ret = {'name': mock_name,
'changes': mock_changes,
'result': False,
'comment': mock_comment}
ret = test.configurable_test_state(mock_name,
result=False,
comment=mock_comment)
self.assertDictEqual(ret, mock_ret)
# Test result=Cheese
with patch.dict(test.__opts__, {'test': False}):
self.assertRaises(SaltInvocationError,
test.configurable_test_state,
mock_name,
result='Cheese')
def test_configurable_test_state_test(self):
'''
Test test.configurable_test_state with test=True with and without
comment
'''
# Configure mock parameters
mock_name = 'cheese_shop'
mock_comment = "I'm afraid we're fresh out of Red Leicester sir."
mock_changes = {
'testing': {
'old': 'Unchanged',
'new': 'Something pretended to change'
}
}
# Test test=True without comment
with patch.dict(test.__opts__, {'test': True}):
mock_ret = {'name': mock_name,
'changes': mock_changes,
'result': None,
'comment': 'This is a test'}
ret = test.configurable_test_state(mock_name)
self.assertDictEqual(ret, mock_ret)
# Test test=True with comment
with patch.dict(test.__opts__, {'test': True}):
mock_ret = {'name': mock_name,
'changes': mock_changes,
'result': None,
'comment': mock_comment}
ret = test.configurable_test_state(mock_name,
comment=mock_comment)
self.assertDictEqual(ret, mock_ret)
# Test test=True and changes=True with comment
with patch.dict(test.__opts__, {'test': True}):
mock_ret = {'name': mock_name,
'changes': mock_changes,
'result': None,
'comment': mock_comment}
ret = test.configurable_test_state(mock_name,
changes=True,
comment=mock_comment)
self.assertDictEqual(ret, mock_ret)
# Test test=True and changes=False with comment
with patch.dict(test.__opts__, {'test': True}):
mock_ret = {'name': mock_name,
'changes': {},
'result': True,
'comment': mock_comment}
ret = test.configurable_test_state(mock_name,
changes=False,
comment=mock_comment)
self.assertDictEqual(ret, mock_ret)
def test_mod_watch(self):
'''