2012-03-28 06:10:13 +00:00
|
|
|
'''
|
|
|
|
Set up the Salt integration test suite
|
|
|
|
'''
|
|
|
|
|
|
|
|
# Import Python libs
|
2012-02-20 12:18:13 +00:00
|
|
|
import multiprocessing
|
|
|
|
import os
|
2012-04-21 23:27:59 +00:00
|
|
|
import sys
|
2012-03-28 06:10:13 +00:00
|
|
|
import shutil
|
2012-02-20 12:22:02 +00:00
|
|
|
import signal
|
2012-04-21 22:58:03 +00:00
|
|
|
import subprocess
|
2012-02-20 12:18:13 +00:00
|
|
|
|
2012-03-28 06:10:13 +00:00
|
|
|
# Import Salt libs
|
2012-02-20 12:18:13 +00:00
|
|
|
import salt
|
|
|
|
import salt.config
|
|
|
|
import salt.master
|
|
|
|
import salt.minion
|
2012-05-28 03:00:10 +00:00
|
|
|
import salt.runner
|
2012-03-09 07:47:34 +00:00
|
|
|
from salt.utils.verify import verify_env
|
2012-02-20 12:18:13 +00:00
|
|
|
from saltunittest import TestCase
|
|
|
|
|
|
|
|
INTEGRATION_TEST_DIR = os.path.dirname(os.path.normpath(os.path.abspath(__file__)))
|
2012-04-21 22:58:03 +00:00
|
|
|
CODE_DIR = os.path.dirname(os.path.dirname(INTEGRATION_TEST_DIR))
|
|
|
|
SCRIPT_DIR = os.path.join(CODE_DIR, 'scripts')
|
|
|
|
|
|
|
|
PYEXEC = 'python{0}.{1}'.format(sys.version_info[0], sys.version_info[1])
|
2012-02-20 12:18:13 +00:00
|
|
|
|
|
|
|
TMP = os.path.join(INTEGRATION_TEST_DIR, 'tmp')
|
|
|
|
FILES = os.path.join(INTEGRATION_TEST_DIR, 'files')
|
|
|
|
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2012-02-20 12:18:13 +00:00
|
|
|
class TestDaemon(object):
|
|
|
|
'''
|
|
|
|
Set up the master and minion daemons, and run related cases
|
|
|
|
'''
|
|
|
|
def __enter__(self):
|
|
|
|
'''
|
|
|
|
Start a master and minion
|
|
|
|
'''
|
2012-03-09 07:47:34 +00:00
|
|
|
self.master_opts = salt.config.master_config(
|
2012-05-10 04:36:20 +00:00
|
|
|
os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'master'))
|
2012-03-09 07:47:34 +00:00
|
|
|
self.minion_opts = salt.config.minion_config(
|
2012-05-10 04:36:20 +00:00
|
|
|
os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'minion'))
|
2012-05-23 14:04:38 +00:00
|
|
|
self.sub_minion_opts = salt.config.minion_config(
|
|
|
|
os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'sub_minion'))
|
2012-03-29 04:14:31 +00:00
|
|
|
self.smaster_opts = salt.config.master_config(
|
2012-05-10 04:36:20 +00:00
|
|
|
os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'syndic_master'))
|
2012-03-29 07:03:37 +00:00
|
|
|
self.syndic_opts = salt.config.minion_config(
|
2012-05-10 04:36:20 +00:00
|
|
|
os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'syndic'))
|
2012-04-09 03:31:08 +00:00
|
|
|
self.syndic_opts['_master_conf_file'] = os.path.join(
|
|
|
|
INTEGRATION_TEST_DIR,
|
|
|
|
'files/conf/master'
|
|
|
|
)
|
2012-03-29 22:19:19 +00:00
|
|
|
# Set up config options that require internal data
|
|
|
|
self.master_opts['pillar_roots'] = {
|
2012-05-10 04:36:20 +00:00
|
|
|
'base': [os.path.join(FILES, 'pillar', 'base')]
|
2012-03-29 22:19:19 +00:00
|
|
|
}
|
2012-03-29 22:51:56 +00:00
|
|
|
self.master_opts['file_roots'] = {
|
2012-05-10 04:36:20 +00:00
|
|
|
'base': [os.path.join(FILES, 'file', 'base')]
|
2012-03-29 22:51:56 +00:00
|
|
|
}
|
2012-04-09 03:31:08 +00:00
|
|
|
self.master_opts['ext_pillar'] = [
|
|
|
|
{'cmd_yaml': 'cat {0}'.format(
|
|
|
|
os.path.join(
|
|
|
|
FILES,
|
|
|
|
'ext.yaml'
|
|
|
|
)
|
|
|
|
)}
|
|
|
|
]
|
2012-03-28 06:10:13 +00:00
|
|
|
# clean up the old files
|
2012-04-04 05:14:26 +00:00
|
|
|
self._clean()
|
2012-03-09 07:47:34 +00:00
|
|
|
self.master_opts['hosts.file'] = os.path.join(TMP, 'hosts')
|
|
|
|
self.minion_opts['hosts.file'] = os.path.join(TMP, 'hosts')
|
2012-03-29 04:14:31 +00:00
|
|
|
verify_env([
|
|
|
|
os.path.join(self.master_opts['pki_dir'], 'minions'),
|
2012-02-20 12:18:13 +00:00
|
|
|
os.path.join(self.master_opts['pki_dir'], 'minions_pre'),
|
|
|
|
os.path.join(self.master_opts['pki_dir'], 'minions_rejected'),
|
|
|
|
os.path.join(self.master_opts['cachedir'], 'jobs'),
|
2012-03-29 04:14:31 +00:00
|
|
|
os.path.join(self.smaster_opts['pki_dir'], 'minions'),
|
|
|
|
os.path.join(self.smaster_opts['pki_dir'], 'minions_pre'),
|
|
|
|
os.path.join(self.smaster_opts['pki_dir'], 'minions_rejected'),
|
|
|
|
os.path.join(self.smaster_opts['cachedir'], 'jobs'),
|
2012-02-20 12:18:13 +00:00
|
|
|
os.path.dirname(self.master_opts['log_file']),
|
|
|
|
self.minion_opts['extension_modules'],
|
2012-05-23 14:04:38 +00:00
|
|
|
self.sub_minion_opts['extension_modules'],
|
|
|
|
self.sub_minion_opts['pki_dir'],
|
2012-02-20 12:18:13 +00:00
|
|
|
self.master_opts['sock_dir'],
|
2012-03-29 04:14:31 +00:00
|
|
|
self.smaster_opts['sock_dir'],
|
2012-02-20 12:18:13 +00:00
|
|
|
])
|
|
|
|
|
|
|
|
master = salt.master.Master(self.master_opts)
|
|
|
|
self.master_process = multiprocessing.Process(target=master.start)
|
|
|
|
self.master_process.start()
|
|
|
|
|
|
|
|
minion = salt.minion.Minion(self.minion_opts)
|
|
|
|
self.minion_process = multiprocessing.Process(target=minion.tune_in)
|
|
|
|
self.minion_process.start()
|
|
|
|
|
2012-05-23 14:04:38 +00:00
|
|
|
sub_minion = salt.minion.Minion(self.sub_minion_opts)
|
|
|
|
self.sub_minion_process = multiprocessing.Process(
|
|
|
|
target=sub_minion.tune_in)
|
|
|
|
self.sub_minion_process.start()
|
|
|
|
|
2012-03-29 04:14:31 +00:00
|
|
|
smaster = salt.master.Master(self.smaster_opts)
|
|
|
|
self.smaster_process = multiprocessing.Process(target=smaster.start)
|
|
|
|
self.smaster_process.start()
|
|
|
|
|
|
|
|
syndic = salt.minion.Syndic(self.syndic_opts)
|
|
|
|
self.syndic_process = multiprocessing.Process(target=syndic.tune_in)
|
|
|
|
self.syndic_process.start()
|
|
|
|
|
2012-02-20 12:18:13 +00:00
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, type, value, traceback):
|
|
|
|
'''
|
|
|
|
Kill the minion and master processes
|
|
|
|
'''
|
2012-05-23 14:04:38 +00:00
|
|
|
self.sub_minion_process.terminate()
|
2012-02-20 12:18:13 +00:00
|
|
|
self.minion_process.terminate()
|
|
|
|
self.master_process.terminate()
|
2012-03-29 04:14:31 +00:00
|
|
|
self.syndic_process.terminate()
|
|
|
|
self.smaster_process.terminate()
|
2012-04-04 05:14:26 +00:00
|
|
|
self._clean()
|
2012-02-20 12:18:13 +00:00
|
|
|
|
2012-04-04 05:14:26 +00:00
|
|
|
def _clean(self):
|
|
|
|
'''
|
|
|
|
Clean out the tmp files
|
|
|
|
'''
|
2012-05-31 10:43:03 +00:00
|
|
|
if os.path.isdir(self.sub_minion_opts['root_dir']):
|
|
|
|
shutil.rmtree(self.sub_minion_opts['root_dir'])
|
2012-04-04 05:14:26 +00:00
|
|
|
if os.path.isdir(self.master_opts['root_dir']):
|
|
|
|
shutil.rmtree(self.master_opts['root_dir'])
|
2012-05-31 10:43:03 +00:00
|
|
|
if os.path.isdir(self.smaster_opts['root_dir']):
|
|
|
|
shutil.rmtree(self.smaster_opts['root_dir'])
|
2012-04-04 05:14:26 +00:00
|
|
|
for fn_ in os.listdir(TMP):
|
|
|
|
if fn_ == '_README':
|
|
|
|
continue
|
|
|
|
path = os.path.join(TMP, fn_)
|
|
|
|
if os.path.isdir(path):
|
|
|
|
shutil.rmtree(path)
|
|
|
|
elif os.path.isfile(path):
|
|
|
|
os.remove(path)
|
2012-05-13 04:36:46 +00:00
|
|
|
elif os.path.islink(path):
|
|
|
|
os.remove(path)
|
2012-02-20 12:18:13 +00:00
|
|
|
|
2012-05-28 03:00:10 +00:00
|
|
|
|
2012-02-20 12:18:13 +00:00
|
|
|
class ModuleCase(TestCase):
|
|
|
|
'''
|
|
|
|
Execute a module function
|
|
|
|
'''
|
|
|
|
def setUp(self):
|
|
|
|
'''
|
|
|
|
Generate the tools to test a module
|
|
|
|
'''
|
2012-03-29 04:25:59 +00:00
|
|
|
self.client = salt.client.LocalClient(
|
|
|
|
os.path.join(
|
|
|
|
INTEGRATION_TEST_DIR,
|
2012-05-10 04:36:20 +00:00
|
|
|
'files', 'conf', 'master'
|
2012-03-29 04:25:59 +00:00
|
|
|
)
|
|
|
|
)
|
2012-02-20 12:18:13 +00:00
|
|
|
|
2012-05-13 04:27:30 +00:00
|
|
|
def run_function(self, function, arg=(), **kwargs):
|
2012-02-20 12:18:13 +00:00
|
|
|
'''
|
|
|
|
Run a single salt function and condition the return down to match the
|
|
|
|
behavior of the raw function call
|
|
|
|
'''
|
2012-05-13 04:27:30 +00:00
|
|
|
orig = self.client.cmd('minion', function, arg, kwarg=kwargs)
|
2012-02-20 12:18:13 +00:00
|
|
|
return orig['minion']
|
|
|
|
|
2012-05-15 05:43:16 +00:00
|
|
|
def state_result(self, ret):
|
|
|
|
'''
|
|
|
|
Return the result data from a single state return
|
|
|
|
'''
|
2012-06-01 18:03:17 +00:00
|
|
|
return ret[next(iter(ret))]['result']
|
2012-05-13 02:40:28 +00:00
|
|
|
|
|
|
|
def run_state(self, function, **kwargs):
|
|
|
|
'''
|
|
|
|
Run the state.single command and return the state return structure
|
|
|
|
'''
|
2012-05-13 04:27:30 +00:00
|
|
|
return self.run_function('state.single', [function], **kwargs)
|
2012-05-13 02:40:28 +00:00
|
|
|
|
2012-02-20 12:18:13 +00:00
|
|
|
def minion_opts(self):
|
|
|
|
'''
|
|
|
|
Return the options used for the minion
|
|
|
|
'''
|
|
|
|
return salt.config.minion_config(
|
|
|
|
os.path.join(
|
|
|
|
INTEGRATION_TEST_DIR,
|
2012-05-10 04:36:20 +00:00
|
|
|
'files', 'conf', 'minion'
|
2012-02-20 12:18:13 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
def master_opts(self):
|
|
|
|
'''
|
|
|
|
Return the options used for the minion
|
|
|
|
'''
|
|
|
|
return salt.config.minion_config(
|
|
|
|
os.path.join(
|
|
|
|
INTEGRATION_TEST_DIR,
|
2012-05-10 04:36:20 +00:00
|
|
|
'files', 'conf', 'master'
|
2012-02-20 12:18:13 +00:00
|
|
|
)
|
|
|
|
)
|
2012-03-29 04:25:59 +00:00
|
|
|
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2012-03-29 04:25:59 +00:00
|
|
|
class SyndicCase(TestCase):
|
|
|
|
'''
|
|
|
|
Execute a syndic based execution test
|
|
|
|
'''
|
|
|
|
def setUp(self):
|
|
|
|
'''
|
|
|
|
Generate the tools to test a module
|
|
|
|
'''
|
|
|
|
self.client = salt.client.LocalClient(
|
|
|
|
os.path.join(
|
|
|
|
INTEGRATION_TEST_DIR,
|
2012-05-10 04:36:20 +00:00
|
|
|
'files', 'conf', 'syndic_master'
|
2012-03-29 04:25:59 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
def run_function(self, function, arg=()):
|
|
|
|
'''
|
|
|
|
Run a single salt function and condition the return down to match the
|
|
|
|
behavior of the raw function call
|
|
|
|
'''
|
|
|
|
orig = self.client.cmd('minion', function, arg)
|
|
|
|
return orig['minion']
|
2012-04-21 22:58:03 +00:00
|
|
|
|
2012-05-13 02:40:28 +00:00
|
|
|
|
2012-04-21 23:52:29 +00:00
|
|
|
class ShellCase(TestCase):
|
2012-04-21 22:58:03 +00:00
|
|
|
'''
|
|
|
|
Execute a test for a shell command
|
|
|
|
'''
|
|
|
|
def run_script(self, script, arg_str):
|
|
|
|
'''
|
|
|
|
Execute a script with the given argument string
|
|
|
|
'''
|
|
|
|
path = os.path.join(SCRIPT_DIR, script)
|
|
|
|
if not os.path.isfile(path):
|
|
|
|
return False
|
|
|
|
ppath = 'PYTHONPATH={0}'.format(':'.join(sys.path[1:]))
|
|
|
|
cmd = '{0} {1} {2} {3}'.format(ppath, PYEXEC, path, arg_str)
|
|
|
|
data = subprocess.Popen(
|
|
|
|
cmd,
|
|
|
|
shell=True,
|
|
|
|
stdout=subprocess.PIPE
|
|
|
|
).communicate()[0].split('\n')
|
|
|
|
return data
|
2012-04-21 23:27:59 +00:00
|
|
|
|
2012-04-21 23:52:29 +00:00
|
|
|
def run_salt(self, arg_str):
|
|
|
|
'''
|
2012-05-23 14:14:16 +00:00
|
|
|
Execute salt
|
2012-04-21 23:52:29 +00:00
|
|
|
'''
|
2012-05-10 04:36:20 +00:00
|
|
|
mconf = os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'master')
|
2012-04-21 23:52:29 +00:00
|
|
|
arg_str = '-c {0} {1}'.format(mconf, arg_str)
|
|
|
|
return self.run_script('salt', arg_str)
|
|
|
|
|
2012-04-22 00:04:50 +00:00
|
|
|
def run_run(self, arg_str):
|
2012-04-21 23:52:29 +00:00
|
|
|
'''
|
2012-05-23 14:14:16 +00:00
|
|
|
Execute salt-run
|
2012-04-21 23:52:29 +00:00
|
|
|
'''
|
2012-05-10 04:36:20 +00:00
|
|
|
mconf = os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'master')
|
2012-04-21 23:52:29 +00:00
|
|
|
arg_str = '-c {0} {1}'.format(mconf, arg_str)
|
|
|
|
return self.run_script('salt-run', arg_str)
|
|
|
|
|
2012-05-28 03:00:10 +00:00
|
|
|
def run_run_plus(self, fun, options='', *arg):
|
|
|
|
'''
|
|
|
|
Execute Salt run and the salt run function and return the data from
|
|
|
|
each in a dict
|
|
|
|
'''
|
|
|
|
ret = {}
|
|
|
|
ret['out'] = self.run_run(
|
|
|
|
'{0} {1} {2}'.format(options, fun, ' '.join(arg))
|
|
|
|
)
|
|
|
|
opts = salt.config.master_config(
|
|
|
|
os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'master'))
|
|
|
|
opts.update({'doc': False,
|
|
|
|
'fun': fun,
|
|
|
|
'arg': arg})
|
|
|
|
runner = salt.runner.Runner(opts)
|
|
|
|
ret['fun'] = runner.run()
|
|
|
|
return ret
|
|
|
|
|
2012-04-21 23:27:59 +00:00
|
|
|
def run_key(self, arg_str):
|
|
|
|
'''
|
|
|
|
Execute salt-key
|
|
|
|
'''
|
2012-05-10 04:36:20 +00:00
|
|
|
mconf = os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'master')
|
2012-04-21 23:27:59 +00:00
|
|
|
arg_str = '-c {0} {1}'.format(mconf, arg_str)
|
|
|
|
return self.run_script('salt-key', arg_str)
|