Merge branch 'nitrogen' into 'develop'

No conflicts.
This commit is contained in:
rallytime 2017-05-24 15:30:44 -06:00
commit 57166fd892
22 changed files with 865 additions and 63 deletions

View File

@ -1611,13 +1611,10 @@ DEFAULT_MASTER_OPTS = {
# ----- Salt Proxy Minion Configuration Defaults ----------------------------------->
# Note DEFAULT_MINION_OPTS
# is loaded first, then if we are setting up a proxy, the config is overwritten with
# these settings.
# These are merged with DEFAULT_MINION_OPTS since many of them also apply here.
DEFAULT_PROXY_MINION_OPTS = {
'conf_file': os.path.join(salt.syspaths.CONFIG_DIR, 'proxy'),
'log_file': os.path.join(salt.syspaths.LOGS_DIR, 'proxy'),
'sign_pub_messages': False,
'add_proxymodule_to_opts': False,
'proxy_merge_grains_in_module': True,
'append_minionid_config_dirs': ['cachedir', 'pidfile', 'default_include'],
@ -1630,9 +1627,11 @@ DEFAULT_PROXY_MINION_OPTS = {
'proxy_always_alive': True,
'proxy_keep_alive': True, # by default will try to keep alive the connection
'proxy_keep_alive_interval': 1 # frequency of the proxy keepalive in minutes
'proxy_keep_alive_interval': 1, # frequency of the proxy keepalive in minutes
'pki_dir': os.path.join(salt.syspaths.CONFIG_DIR, 'pki', 'proxy'),
'cachedir': os.path.join(salt.syspaths.CACHE_DIR, 'proxy'),
'sock_dir': os.path.join(salt.syspaths.SOCK_DIR, 'proxy'),
}
# ----- Salt Cloud Configuration Defaults ----------------------------------->
DEFAULT_CLOUD_OPTS = {
'verify_env': True,
@ -2139,9 +2138,6 @@ def minion_config(path,
if defaults is None:
defaults = DEFAULT_MINION_OPTS.copy()
if path is not None and path.endswith('proxy'):
defaults.update(DEFAULT_PROXY_MINION_OPTS)
if not os.environ.get(env_var, None):
# No valid setting was given using the configuration variable.
# Lets see is SALT_CONFIG_DIR is of any use
@ -2171,6 +2167,58 @@ def minion_config(path,
return opts
def proxy_config(path,
env_var='SALT_PROXY_CONFIG',
defaults=None,
cache_minion_id=False,
ignore_config_errors=True,
minion_id=None):
'''
Reads in the proxy minion configuration file and sets up special options
This is useful for Minion-side operations, such as the
:py:class:`~salt.client.Caller` class, and manually running the loader
interface.
.. code-block:: python
import salt.config
proxy_opts = salt.config.proxy_config('/etc/salt/proxy')
'''
if defaults is None:
defaults = DEFAULT_MINION_OPTS.copy()
defaults.update(DEFAULT_PROXY_MINION_OPTS)
if not os.environ.get(env_var, None):
# No valid setting was given using the configuration variable.
# Lets see is SALT_CONFIG_DIR is of any use
salt_config_dir = os.environ.get('SALT_CONFIG_DIR', None)
if salt_config_dir:
env_config_file_path = os.path.join(salt_config_dir, 'proxy')
if salt_config_dir and os.path.isfile(env_config_file_path):
# We can get a configuration file using SALT_CONFIG_DIR, let's
# update the environment with this information
os.environ[env_var] = env_config_file_path
overrides = load_config(path, env_var, DEFAULT_PROXY_MINION_OPTS['conf_file'])
default_include = overrides.get('default_include',
defaults['default_include'])
include = overrides.get('include', [])
overrides.update(include_config(default_include, path, verbose=False,
exit_on_config_errors=not ignore_config_errors))
overrides.update(include_config(include, path, verbose=True,
exit_on_config_errors=not ignore_config_errors))
opts = apply_minion_config(overrides, defaults,
cache_minion_id=cache_minion_id,
minion_id=minion_id)
apply_sdb(opts)
_validate_opts(opts)
return opts
def syndic_config(master_config_path,
minion_config_path,
master_env_var='SALT_MASTER_CONFIG',

View File

@ -13,8 +13,8 @@ import os
import re
import shlex
import stat
import subprocess
import tarfile
import tempfile
import zipfile
try:
from shlex import quote as _quote # pylint: disable=E0611
@ -164,7 +164,10 @@ def list_(name,
files = []
links = []
try:
with contextlib.closing(tarfile.open(cached)) as tar_archive:
open_kwargs = {'name': cached} \
if not isinstance(cached, subprocess.Popen) \
else {'fileobj': cached.stdout, 'mode': 'r|'}
with contextlib.closing(tarfile.open(**open_kwargs)) as tar_archive:
for member in tar_archive.getmembers():
if member.issym():
links.append(member.name)
@ -175,7 +178,15 @@ def list_(name,
return dirs, files, links
except tarfile.ReadError:
if not failhard:
if failhard:
if isinstance(cached, subprocess.Popen):
stderr = cached.communicate()[1]
if cached.returncode != 0:
raise CommandExecutionError(
'Failed to decompress {0}'.format(name),
info={'error': stderr}
)
else:
if not salt.utils.which('tar'):
raise CommandExecutionError('\'tar\' command not available')
if decompress_cmd is not None:
@ -194,29 +205,12 @@ def list_(name,
decompress_cmd = 'xz --decompress --stdout'
if decompress_cmd:
fd, decompressed = tempfile.mkstemp()
os.close(fd)
try:
cmd = '{0} {1} > {2}'.format(decompress_cmd,
_quote(cached),
_quote(decompressed))
result = __salt__['cmd.run_all'](cmd, python_shell=True)
if result['retcode'] != 0:
raise CommandExecutionError(
'Failed to decompress {0}'.format(name),
info={'error': result['stderr']}
)
return _list_tar(name, decompressed, None, True)
finally:
try:
os.remove(decompressed)
except OSError as exc:
if exc.errno != errno.ENOENT:
log.warning(
'Failed to remove intermediate '
'decompressed archive %s: %s',
decompressed, exc.__str__()
)
decompressed = subprocess.Popen(
'{0} {1}'.format(decompress_cmd, _quote(cached)),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
return _list_tar(name, decompressed, None, True)
raise CommandExecutionError(
'Unable to list contents of {0}. If this is an XZ-compressed tar '

View File

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
'''
Package support for the dummy proxy used by the test suite
'''
from __future__ import absolute_import
# Import python libs
import logging
import salt.utils
log = logging.getLogger(__name__)
# Define the module's virtual name
__virtualname__ = 'pkg'
def __virtual__():
'''
Only work on systems that are a proxy minion
'''
try:
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'dummy':
return __virtualname__
except KeyError:
return (False, 'The dummyproxy_package execution module failed to load. Check the proxy key in pillar or /etc/salt/proxy.')
return (False, 'The dummyproxy_package execution module failed to load: only works on a dummy proxy minion.')
def list_pkgs(versions_as_list=False, **kwargs):
return __proxy__['dummy.package_list']()
def install(name=None, refresh=False, fromrepo=None,
pkgs=None, sources=None, **kwargs):
return __proxy__['dummy.package_install'](name, **kwargs)
def remove(name=None, pkgs=None, **kwargs):
return __proxy__['dummy.package_remove'](name)
def version(*names, **kwargs):
'''
Returns a string representing the package version or an empty string if not
installed. If more than one package name is specified, a dict of
name/version pairs is returned.
CLI Example:
.. code-block:: bash
salt '*' pkg.version <package name>
salt '*' pkg.version <package1> <package2> <package3> ...
'''
if len(names) == 1:
vers = __proxy__['dummy.package_status'](names[0])
return vers[names[0]]
else:
results = {}
for n in names:
vers = __proxy__['dummy.package_status'](n)
results.update(vers)
return results
def upgrade(name=None, pkgs=None, refresh=True, skip_verify=True,
normalize=True, **kwargs):
old = __proxy__['dummy.package_list']()
new = __proxy__['dummy.uptodate']()
pkg_installed = __proxy__['dummy.upgrade']()
ret = salt.utils.compare_dicts(old, pkg_installed)
return ret
def installed(name,
version=None,
refresh=False,
fromrepo=None,
skip_verify=False,
pkgs=None,
sources=None,
**kwargs):
p = __proxy__['dummy.package_status'](name)
if version is None:
if 'ret' in p:
return str(p['ret'])
else:
return True
else:
if p is not None:
return version == str(p)

View File

@ -0,0 +1,156 @@
# -*- coding: utf-8 -*-
'''
Provide the service module for the dummy proxy used in integration tests
'''
# Import python libs
from __future__ import absolute_import
import salt.utils
import logging
log = logging.getLogger(__name__)
__func_alias__ = {
'list_': 'list'
}
# Define the module's virtual name
__virtualname__ = 'service'
def __virtual__():
'''
Only work on systems that are a proxy minion
'''
try:
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'dummy':
return __virtualname__
except KeyError:
return (False, 'The dummyproxy_service execution module failed to load. Check the proxy key in pillar or /etc/salt/proxy.')
return (False, 'The dummyproxy_service execution module failed to load: only works on the integration testsuite dummy proxy minion.')
def get_all():
'''
Return a list of all available services
.. versionadded:: 2016.11.3
CLI Example:
.. code-block:: bash
salt '*' service.get_all
'''
proxy_fn = 'dummy.service_list'
return __proxy__[proxy_fn]()
def list_():
'''
Return a list of all available services.
.. versionadded:: 2016.11.3
CLI Example:
.. code-block:: bash
salt '*' service.list
'''
return get_all()
def start(name, sig=None):
'''
Start the specified service on the dummy
.. versionadded:: 2016.11.3
CLI Example:
.. code-block:: bash
salt '*' service.start <service name>
'''
proxy_fn = 'dummy.service_start'
return __proxy__[proxy_fn](name)
def stop(name, sig=None):
'''
Stop the specified service on the dummy
.. versionadded:: 2016.11.3
CLI Example:
.. code-block:: bash
salt '*' service.stop <service name>
'''
proxy_fn = 'dummy.service_stop'
return __proxy__[proxy_fn](name)
def restart(name, sig=None):
'''
Restart the specified service with dummy.
.. versionadded:: 2016.11.3
CLI Example:
.. code-block:: bash
salt '*' service.restart <service name>
'''
proxy_fn = 'dummy.service_restart'
return __proxy__[proxy_fn](name)
def status(name, sig=None):
'''
Return the status for a service via dummy, returns a bool
whether the service is running.
.. versionadded:: 2016.11.3
CLI Example:
.. code-block:: bash
salt '*' service.status <service name>
'''
proxy_fn = 'dummy.service_status'
resp = __proxy__[proxy_fn](name)
if resp['comment'] == 'stopped':
return False
if resp['comment'] == 'running':
return True
def running(name, sig=None):
'''
Return whether this service is running.
.. versionadded:: 2016.11.3
'''
return status(name).get(name, False)
def enabled(name, sig=None):
'''
Only the 'redbull' service is 'enabled' in the test
.. versionadded:: 2016.11.3
'''
return name == 'redbull'

View File

@ -93,6 +93,20 @@ def set_(name, value, **kwargs):
if 'jail' in kwargs:
cmd += ' -j '+kwargs['jail']
# This is here because the YAML parser likes to convert the string literals
# YES, NO, Yes, No, True, False, etc. to boolean types. However, in this case,
# we will check to see if that happened and replace it with "YES" or "NO" because
# those items are accepted in sysrc.
if type(value) == bool:
if value:
value = "YES"
else:
value = "NO"
# This is here for the same reason, except for numbers
if type(value) == int:
value = str(value)
cmd += ' '+name+"=\""+value+"\""
sysrcs = __salt__['cmd.run'](cmd)
@ -105,9 +119,6 @@ def set_(name, value, **kwargs):
newval = sysrc.split(': ')[2].split(" -> ")[1]
if rcfile not in ret:
ret[rcfile] = {}
#ret[rcfile][var] = {}
#ret[rcfile][var]['old'] = oldval
#ret[rcfile][var]['new'] = newval
ret[rcfile][var] = newval
return ret

237
salt/proxy/dummy.py Normal file
View File

@ -0,0 +1,237 @@
# -*- coding: utf-8 -*-
'''
This is a dummy proxy-minion designed for testing the proxy minion subsystem.
'''
from __future__ import absolute_import
# Import python libs
import os
import logging
import pickle
# This must be present or the Salt loader won't load this module
__proxyenabled__ = ['dummy']
# Variables are scoped to this module so we can have persistent data
# across calls to fns in here.
DETAILS = {}
DETAILS['services'] = {'apache': 'running', 'ntp': 'running', 'samba': 'stopped'}
DETAILS['packages'] = {'coreutils': '1.0', 'apache': '2.4', 'tinc': '1.4', 'redbull': '999.99'}
FILENAME = os.tmpnam()
# Want logging!
log = logging.getLogger(__file__)
# This does nothing, it's here just as an example and to provide a log
# entry when the module is loaded.
def __virtual__():
'''
Only return if all the modules are available
'''
log.debug('dummy proxy __virtual__() called...')
return True
def _save_state(details):
pck = open(FILENAME, 'wb') # pylint: disable=W8470
pickle.dump(details, pck)
pck.close()
def _load_state():
try:
pck = open(FILENAME, 'r') # pylint: disable=W8470
DETAILS = pickle.load(pck)
pck.close()
except IOError:
DETAILS = {}
DETAILS['initialized'] = False
_save_state(DETAILS)
return DETAILS
# Every proxy module needs an 'init', though you can
# just put DETAILS['initialized'] = True here if nothing
# else needs to be done.
def init(opts):
log.debug('dummy proxy init() called...')
DETAILS['initialized'] = True
_save_state(DETAILS)
def initialized():
'''
Since grains are loaded in many different places and some of those
places occur before the proxy can be initialized, return whether
our init() function has been called
'''
DETAILS = _load_state()
return DETAILS.get('initialized', False)
def grains():
'''
Make up some grains
'''
DETAILS = _load_state()
if 'grains_cache' not in DETAILS:
DETAILS['grains_cache'] = {'dummy_grain_1': 'one', 'dummy_grain_2': 'two', 'dummy_grain_3': 'three', }
_save_state(DETAILS)
return DETAILS['grains_cache']
def grains_refresh():
'''
Refresh the grains
'''
DETAILS = _load_state()
DETAILS['grains_cache'] = None
_save_state(DETAILS)
return grains()
def fns():
return {'details': 'This key is here because a function in '
'grains/rest_sample.py called fns() here in the proxymodule.'}
def service_start(name):
'''
Start a "service" on the dummy server
'''
DETAILS = _load_state()
DETAILS['services'][name] = 'running'
_save_state(DETAILS)
return 'running'
def service_stop(name):
'''
Stop a "service" on the dummy server
'''
DETAILS = _load_state()
DETAILS['services'][name] = 'stopped'
_save_state(DETAILS)
return 'stopped'
def service_restart(name):
'''
Restart a "service" on the REST server
'''
return True
def service_list():
'''
List "services" on the REST server
'''
DETAILS = _load_state()
return DETAILS['services'].keys()
def service_status(name):
'''
Check if a service is running on the REST server
'''
DETAILS = _load_state()
if DETAILS['services'][name] == 'running':
return {'comment': 'running'}
else:
return {'comment': 'stopped'}
def package_list():
'''
List "packages" installed on the REST server
'''
DETAILS = _load_state()
return DETAILS['packages']
def package_install(name, **kwargs):
'''
Install a "package" on the REST server
'''
DETAILS = _load_state()
if kwargs.get('version', False):
version = kwargs['version']
else:
version = '1.0'
DETAILS['packages'][name] = version
_save_state(DETAILS)
return {name: version}
def upgrade():
'''
"Upgrade" packages
'''
DETAILS = _load_state()
pkgs = uptodate()
DETAILS['packages'] = pkgs
_save_state(DETAILS)
return pkgs
def uptodate():
'''
Call the REST endpoint to see if the packages on the "server" are up to date.
'''
DETAILS = _load_state()
for p in DETAILS['packages']:
version_float = float(DETAILS['packages'][p])
version_float = version_float + 1.0
DETAILS['packages'][p] = str(version_float)
return DETAILS['packages']
def package_remove(name):
'''
Remove a "package" on the REST server
'''
DETAILS = _load_state()
DETAILS['packages'].pop(name)
_save_state(DETAILS)
return DETAILS['packages']
def package_status(name):
'''
Check the installation status of a package on the REST server
'''
DETAILS = _load_state()
if name in DETAILS['packages']:
return {name: DETAILS['packages'][name]}
def ping():
'''
Degenerate ping
'''
log.debug('dummy proxy returning ping')
return True
def shutdown(opts):
'''
For this proxy shutdown is a no-op
'''
log.debug('dummy proxy shutdown() called...')
DETAILS = _load_state()
if 'filename' in DETAILS:
os.unlink(DETAILS['filename'])
def test_from_state():
'''
Test function so we have something to call from a state
:return:
'''
log.debug('test_from_state called')
return 'testvalue'

View File

@ -283,7 +283,7 @@ def proxy_minion_process(queue):
sys.exit(status)
def salt_proxy_minion():
def salt_proxy():
'''
Start a proxy minion.
'''

View File

@ -92,7 +92,7 @@ def installed(name, version=None, source=None, force=False, pre_versions=False,
# Determine action
# Package not installed
if name not in pre_install:
if name not in [package.split('|')[0].lower() for package in pre_install.splitlines()]:
if version:
ret['changes'] = {name: 'Version {0} will be installed'
''.format(version)}
@ -193,7 +193,7 @@ def uninstalled(name, version=None, uninstall_args=None, override_args=False):
pre_uninstall = __salt__['chocolatey.list'](local_only=True)
# Determine if package is installed
if name in pre_uninstall:
if name in [package.split('|')[0].lower() for package in pre_uninstall.splitlines()]:
ret['changes'] = {name: '{0} version {1} will be removed'
''.format(name, pre_uninstall[name][0])}
else:

View File

@ -1700,7 +1700,9 @@ def is_proxy():
# then this will fail.
is_proxy = False
try:
if 'salt-proxy' in main.__file__:
# Changed this from 'salt-proxy in main...' to 'proxy in main...'
# to support the testsuite's temp script that is called 'cli_salt_proxy'
if 'proxy' in main.__file__:
is_proxy = True
except AttributeError:
pass
@ -2912,6 +2914,14 @@ def repack_dictlist(data,
return ret
def get_default_group(user):
if HAS_GRP is False or HAS_PWD is False:
# We don't work on platforms that don't have grp and pwd
# Just return an empty list
return None
return grp.getgrgid(pwd.getpwnam(user).pw_gid).gr_name
def get_group_list(user=None, include_default=True):
'''
Returns a list of all of the system group names of which the user
@ -2950,7 +2960,7 @@ def get_group_list(user=None, include_default=True):
log.trace('Trying generic group list for \'{0}\''.format(user))
group_names = [g.gr_name for g in grp.getgrall() if user in g.gr_mem]
try:
default_group = grp.getgrgid(pwd.getpwnam(user).pw_gid).gr_name
default_group = get_default_group(user)
if default_group not in group_names:
group_names.append(default_group)
except KeyError:

View File

@ -1786,7 +1786,7 @@ class ProxyMinionOptionParser(six.with_metaclass(OptionParserMeta,
except AttributeError:
minion_id = None
return config.minion_config(self.get_config_file_path(),
return config.proxy_config(self.get_config_file_path(),
cache_minion_id=False,
minion_id=minion_id)

View File

@ -1,9 +1,11 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
This script is used to kick off a salt proxy minion daemon
'''
from salt.scripts import salt_proxy_minion
from __future__ import absolute_import
from salt.scripts import salt_proxy
from salt.utils import is_windows
from multiprocessing import freeze_support
@ -23,4 +25,4 @@ if __name__ == '__main__':
# This handles the bootstrapping code that is included with frozen
# scripts. It is a no-op on unfrozen code.
freeze_support()
salt_proxy_minion()
salt_proxy()

View File

@ -742,6 +742,16 @@ class TestDaemon(object):
syndic_master_opts['root_dir'] = os.path.join(TMP, 'rootdir-syndic-master')
syndic_master_opts['pki_dir'] = os.path.join(TMP, 'rootdir-syndic-master', 'pki', 'master')
# This proxy connects to master
# proxy_opts = salt.config._read_conf_file(os.path.join(CONF_DIR, 'proxy'))
# proxy_opts['cachedir'] = os.path.join(TMP, 'rootdir', 'cache')
# proxy_opts['user'] = running_tests_user
# proxy_opts['config_dir'] = TMP_CONF_DIR
# proxy_opts['root_dir'] = os.path.join(TMP, 'rootdir')
# proxy_opts['pki_dir'] = os.path.join(TMP, 'rootdir', 'pki')
# proxy_opts['hosts.file'] = os.path.join(TMP, 'rootdir', 'hosts')
# proxy_opts['aliases.file'] = os.path.join(TMP, 'rootdir', 'aliases')
if transport == 'raet':
master_opts['transport'] = 'raet'
master_opts['raet_port'] = 64506
@ -938,6 +948,7 @@ class TestDaemon(object):
cls.master_opts = master_opts
cls.minion_opts = minion_opts
# cls.proxy_opts = proxy_opts
cls.sub_minion_opts = sub_minion_opts
cls.syndic_opts = syndic_opts
cls.syndic_master_opts = syndic_master_opts
@ -949,6 +960,8 @@ class TestDaemon(object):
'''
self.sub_minion_process.terminate()
self.minion_process.terminate()
# if hasattr(self, 'proxy_process'):
# self.proxy_process.terminate()
self.master_process.terminate()
try:
self.syndic_process.terminate()

View File

@ -0,0 +1,50 @@
# basic config
# Connects to master
master: localhost
master_port: 64506
interface: 127.0.0.1
tcp_pub_port: 64510
tcp_pull_port: 64511
sock_dir: proxy_sock
id: proxytest
open_mode: True
log_file: proxy.log
log_level_logfile: debug
pidfile: proxy.pid
# module extension
test.foo: baz
integration.test: True
# Grains addons
grains:
test_grain: cheese
script: grail
alot: many
planets:
- mercury
- venus
- earth
- mars
level1:
level2: foo
companions:
one:
- susan
- ian
- barbara
config_test:
spam: eggs
mine_functions:
test.ping: []
# sdb env module
osenv:
driver: env
add_proxymodule_to_opts: False
proxy:
proxytype: dummy

View File

@ -115,7 +115,7 @@ class TestModulesGrains(ModuleCase):
for grain in grains:
get_grain = self.run_function('grains.get', [grain])
if os == 'Arch' and grain in ['osmajorrelease', 'osrelease']:
if os == 'Arch' and grain in ['osmajorrelease']:
self.assertEqual(get_grain, '')
continue
if os == 'Windows' and grain in ['osmajorrelease']:

View File

@ -59,11 +59,13 @@ class LinuxAclModuleTest(ModuleCase, AdaptedConfigurationTestCaseMixin):
def test_getfacl_w_single_file_without_acl(self):
ret = self.run_function('acl.getfacl', arg=[self.myfile])
user = salt.utils.get_user()
group = salt.utils.get_default_group(user)
self.maxDiff = None
self.assertEqual(
ret,
{self.myfile: {'other': [{'': {'octal': 4, 'permissions': {'read': True, 'write': False, 'execute': False}}}],
'user': [{'root': {'octal': 6, 'permissions': {'read': True, 'write': True, 'execute': False}}}],
'group': [{'root': {'octal': 4, 'permissions': {'read': True, 'write': False, 'execute': False}}}],
'comment': {'owner': 'root', 'group': 'root', 'file': self.myfile}}}
'user': [{user: {'octal': 6, 'permissions': {'read': True, 'write': True, 'execute': False}}}],
'group': [{group: {'octal': 4, 'permissions': {'read': True, 'write': False, 'execute': False}}}],
'comment': {'owner': user, 'group': group, 'file': self.myfile}}}
)

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# Import python libs
from __future__ import absolute_import
import sys
# Import Salt Testing libs
from tests.support.case import ModuleCase
from tests.support.helpers import destructiveTest
from tests.support.unit import skipIf
class SysrcModuleTest(ModuleCase):
def setUp(self):
super(SysrcModuleTest, self).setUp()
ret = self.run_function('cmd.has_exec', ['sysrc'])
if not ret:
self.skipTest('sysrc not found')
@skipIf(not sys.platform.startswith('freebsd'), 'FreeBSD specific')
def test_show(self):
ret = self.run_function('sysrc.get')
self.assertIsInstance(ret, dict, 'sysrc.get returned wrong type, expecting dictionary')
self.assertIn('/etc/rc.conf', ret, 'sysrc.get should have an rc.conf key in it.')
@skipIf(not sys.platform.startswith('freebsd'), 'FreeBSD specific')
@destructiveTest
def test_set(self):
ret = self.run_function('sysrc.set', ['test_var', '1'])
self.assertIsInstance(ret, dict, 'sysrc.get returned wrong type, expecting dictionary')
self.assertIn('/etc/rc.conf', ret, 'sysrc.set should have an rc.conf key in it.')
self.assertIn('1', ret['/etc/rc.conf']['test_var'], 'sysrc.set should return the value it set.')
ret = self.run_function('sysrc.remove', ['test_var'])
self.assertEqual('test_var removed', ret)
@skipIf(not sys.platform.startswith('freebsd'), 'FreeBSD specific')
@destructiveTest
def test_set_bool(self):
ret = self.run_function('sysrc.set', ['test_var', True])
self.assertIsInstance(ret, dict, 'sysrc.get returned wrong type, expecting dictionary')
self.assertIn('/etc/rc.conf', ret, 'sysrc.set should have an rc.conf key in it.')
self.assertIn('YES', ret['/etc/rc.conf']['test_var'], 'sysrc.set should return the value it set.')
ret = self.run_function('sysrc.remove', ['test_var'])
self.assertEqual('test_var removed', ret)

View File

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

View File

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
'''
Simple Smoke Tests for Connected Proxy Minion
'''
# Import Python libs
from __future__ import absolute_import
# Import Salt Testing libs
from tests.support.case import ModuleCase
class ProxyMinionSimpleTestCase(ModuleCase):
'''
Test minion blackout functionality
'''
def test_can_it_ping(self):
'''
Ensure the proxy can ping
'''
ret = self.run_function('test.ping', minion_tgt='proxytest')
self.assertEqual(ret, True)
def test_list_pkgs(self):
'''
Package test 1, really just tests that the virtual function capability
is working OK.
'''
ret = self.run_function('pkg.list_pkgs', minion_tgt='proxytest')
self.assertIn('coreutils', ret)
self.assertIn('apache', ret)
self.assertIn('redbull', ret)
def test_install_pkgs(self):
'''
Package test 2, really just tests that the virtual function capability
is working OK.
'''
ret = self.run_function('pkg.install', ['thispkg'], minion_tgt='proxytest')
self.assertEqual(ret['thispkg'], '1.0')
ret = self.run_function('pkg.list_pkgs', minion_tgt='proxytest')
self.assertEqual(ret['apache'], '2.4')
self.assertEqual(ret['redbull'], '999.99')
self.assertEqual(ret['thispkg'], '1.0')
def test_remove_pkgs(self):
ret = self.run_function('pkg.remove', ['apache'], minion_tgt='proxytest')
self.assertNotIn('apache', ret)
def test_upgrade(self):
ret = self.run_function('pkg.upgrade', minion_tgt='proxytest')
self.assertEqual(ret['coreutils']['new'], '2.0')
self.assertEqual(ret['redbull']['new'], '1000.99')
def test_service_list(self):
ret = self.run_function('service.list', minion_tgt='proxytest')
self.assertIn('ntp', ret)
def test_service_stop(self):
ret = self.run_function('service.stop', ['ntp'], minion_tgt='proxytest')
ret = self.run_function('service.status', ['ntp'], minion_tgt='proxytest')
self.assertFalse(ret)
def test_service_start(self):
ret = self.run_function('service.start', ['samba'], minion_tgt='proxytest')
ret = self.run_function('service.status', ['samba'], minion_tgt='proxytest')
self.assertTrue(ret)

View File

@ -157,3 +157,16 @@ class MasterTest(ShellCase, testprogram.TestProgramCase, ShellCaseCommonTestsMix
stderr=tests.integration.utils.decode_byte_list(stderr)
)
master.shutdown()
# Do the test again to check does master shut down correctly
stdout, stderr, status = master.run(
args=['-d'],
catch_stderr=True,
with_retcode=True,
)
self.assert_exit_status(
status, 'EX_OK',
message='correct usage',
stdout=stdout,
stderr=tests.integration.utils.decode_byte_list(stderr)
)
master.shutdown()

View File

@ -35,9 +35,24 @@ from salt.exceptions import CommandExecutionError
import salt.ext.six as six
class VirtualEnv(object):
def __init__(self, test, venv_dir):
self.venv_dir = venv_dir
self.test = test
def __enter__(self):
ret = self.test.run_function('virtualenv.create', [self.venv_dir])
self.test.assertEqual(ret['retcode'], 0)
def __exit__(self, exc_type, exc_value, traceback):
if os.path.isdir(self.venv_dir):
shutil.rmtree(self.venv_dir)
@skipIf(salt.utils.which_bin(KNOWN_BINARY_NAMES) is None, 'virtualenv not installed')
class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
@skip_if_not_root
def test_pip_installed_removed(self):
'''
Tests installed and removed states
@ -50,6 +65,17 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
ret = self.run_state('pip.removed', name=name)
self.assertSaltTrueReturn(ret)
def test_pip_installed_removed_venv(self):
venv_dir = os.path.join(
RUNTIME_VARS.TMP, 'pip_installed_removed'
)
with VirtualEnv(self, venv_dir):
name = 'pudb'
ret = self.run_state('pip.installed', name=name, bin_env=venv_dir)
self.assertSaltTrueReturn(ret)
ret = self.run_state('pip.removed', name=name, bin_env=venv_dir)
self.assertSaltTrueReturn(ret)
def test_pip_installed_errors(self):
venv_dir = os.path.join(
RUNTIME_VARS.TMP, 'pip-installed-errors'
@ -378,7 +404,7 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
# Let's install a fixed version pip over whatever pip was
# previously installed
ret = self.run_function(
'pip.install', ['pip==6.0'], upgrade=True,
'pip.install', ['pip==8.0'], upgrade=True,
bin_env=venv_dir
)
try:
@ -392,15 +418,15 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
pprint.pprint(ret)
raise
# Let's make sure we have pip 6.0 installed
# Let's make sure we have pip 8.0 installed
self.assertEqual(
self.run_function('pip.list', ['pip'], bin_env=venv_dir),
{'pip': '6.0'}
{'pip': '8.0.0'}
)
# Now the actual pip upgrade pip test
ret = self.run_state(
'pip.installed', name='pip==6.0.7', upgrade=True,
'pip.installed', name='pip==8.0.1', upgrade=True,
bin_env=venv_dir
)
try:
@ -408,7 +434,7 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
self.assertInSaltReturn(
'Installed',
ret,
['changes', 'pip==6.0.7']
['changes', 'pip==8.0.1']
)
except AssertionError:
import pprint

View File

@ -154,6 +154,9 @@ TEST_SUITES = {
'reactor':
{'display_name': 'Reactor',
'path': 'integration/reactor'},
'proxy':
{'display_name': 'Proxy',
'path': 'integration/proxy'},
}
@ -162,7 +165,8 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
support_destructive_tests_selection = True
source_code_basedir = SALT_ROOT
def _get_suites(self, include_unit=False, include_cloud_provider=False):
def _get_suites(self, include_unit=False, include_cloud_provider=False,
include_proxy=False):
'''
Return a set of all test suites except unit and cloud provider tests
unless requested
@ -172,24 +176,30 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
suites -= set(['unit'])
if not include_cloud_provider:
suites -= set(['cloud_provider'])
if not include_proxy:
suites -= set(['proxy'])
return suites
def _check_enabled_suites(self, include_unit=False, include_cloud_provider=False):
def _check_enabled_suites(self, include_unit=False,
include_cloud_provider=False, include_proxy=False):
'''
Query whether test suites have been enabled
'''
suites = self._get_suites(include_unit=include_unit,
include_cloud_provider=include_cloud_provider)
include_cloud_provider=include_cloud_provider,
include_proxy=include_proxy)
return any([getattr(self.options, suite) for suite in suites])
def _enable_suites(self, include_unit=False, include_cloud_provider=False):
def _enable_suites(self, include_unit=False, include_cloud_provider=False,
include_proxy=False):
'''
Enable test suites for current test run
'''
suites = self._get_suites(include_unit=include_unit,
include_cloud_provider=include_cloud_provider)
include_cloud_provider=include_cloud_provider,
include_proxy=include_proxy)
for suite in suites:
setattr(self.options, suite, True)
@ -399,6 +409,16 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
help='Run salt-api tests'
)
self.test_selection_group.add_option(
'-P',
'--proxy',
'--proxy-tests',
dest='proxy',
action='store_true',
default=False,
help='Run salt-proxy tests'
)
def validate_options(self):
if self.options.cloud_provider:
# Turn on expensive tests execution
@ -430,7 +450,9 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
# When no tests are specifically enumerated on the command line, setup
# a default run: +unit -cloud_provider
if not self.options.name and not \
self._check_enabled_suites(include_unit=True, include_cloud_provider=True):
self._check_enabled_suites(include_unit=True,
include_cloud_provider=True,
include_proxy=True):
self._enable_suites(include_unit=True)
self.start_coverage(
@ -471,6 +493,7 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
print_header(' * Salt daemons started')
master_conf = TestDaemon.config('master')
minion_conf = TestDaemon.config('minion')
proxy_conf = TestDaemon.config('proxy')
sub_minion_conf = TestDaemon.config('sub_minion')
syndic_conf = TestDaemon.config('syndic')
syndic_master_conf = TestDaemon.config('syndic_master')
@ -511,6 +534,15 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
print('tcp pull port: {0}'.format(sub_minion_conf['tcp_pull_port']))
print('\n')
print_header(' * Proxy Minion configuration values', top=True)
print('interface: {0}'.format(proxy_conf['interface']))
print('master: {0}'.format(proxy_conf['master']))
print('master port: {0}'.format(proxy_conf['master_port']))
if minion_conf['ipc_mode'] == 'tcp':
print('tcp pub port: {0}'.format(proxy_conf['tcp_pub_port']))
print('tcp pull port: {0}'.format(proxy_conf['tcp_pull_port']))
print('\n')
print_header(' Your client configuration is at {0}'.format(TestDaemon.config_location()))
print('To access the minion: salt -c {0} minion test.ping'.format(TestDaemon.config_location()))
@ -609,7 +641,7 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
status = []
# Return an empty status if no tests have been enabled
if not self._check_enabled_suites(include_cloud_provider=True) and not self.options.name:
if not self._check_enabled_suites(include_cloud_provider=True, include_proxy=True) and not self.options.name:
return status
with TestDaemon(self):

View File

@ -556,7 +556,7 @@ class ProxyMinionOptionParserTestCase(LogSettingsParserTests):
# Log file
self.log_file = '/tmp/salt_proxy_minion_parser_test'
# Function to patch
self.config_func = 'salt.config.minion_config'
self.config_func = 'salt.config.proxy_config'
# Mock log setup
self.setup_log()