Parsers(master, minion, syndic) cleanup code.

Moved the minion, master and syndic parsers to use mixins to clean up, reuse, and automate some of the required procedures.
This commit is contained in:
Pedro Algarvio 2012-08-04 19:58:32 +01:00
parent 5f3552862b
commit d776705e49
8 changed files with 543 additions and 334 deletions

View file

@ -1,7 +1,6 @@
'''
Make me some salt!
'''
from salt.version import __version__
# Import python libs
import os
@ -9,370 +8,143 @@ import sys
# Import salt libs, the try block bypasses an issue at build time so that c
# modules don't cause the build to fail
from salt.version import __version__
try:
import salt.config
from salt.utils import parser as optparse
from salt.utils.process import set_pidfile
from salt.utils import parsers
from salt.utils.verify import check_user, verify_env, verify_socket
except ImportError as e:
if e.args[0] != 'No module named _msgpack':
raise
class Master(object):
class Master(parsers.MasterOptionParser):
'''
Creates a master server
'''
def __init__(self):
self.cli = self.__parse_cli()
# command line overrides config
if self.cli['user']:
self.opts['user'] = self.cli['user']
# Send the pidfile location to the opts
if self.cli['pidfile']:
self.opts['pidfile'] = self.cli['pidfile']
def __parse_cli(self):
'''
Parse the cli for options passed to a master daemon
'''
import salt.log
parser = optparse.OptionParser(version="%%prog %s" % __version__)
parser.add_option('-d',
'--daemon',
dest='daemon',
default=False,
action='store_true',
help='Run the master as a daemon')
parser.add_option('-c',
'--config',
dest='config',
default='/etc/salt/master',
help='Pass in an alternative configuration file')
parser.add_option('-u',
'--user',
dest='user',
help='Specify user to run master')
parser.add_option('--pid-file',
dest='pidfile',
help=('Specify the location of the pidfile.'))
parser.add_option('-l',
'--log-level',
dest='log_level',
choices=list(salt.log.LOG_LEVELS),
help='Console log level. One of %s. For the logfile settings '
'see the config file. Default: \'warning\'.' %
', '.join([repr(l) for l in salt.log.SORTED_LEVEL_NAMES]))
options, args = parser.parse_args()
self.opts = salt.config.master_config(options.config)
if not options.log_level:
options.log_level = self.opts['log_level']
salt.log.setup_console_logger(
options.log_level,
log_format=self.opts['log_fmt_console'],
date_format=self.opts['log_datefmt']
)
cli = {'daemon': options.daemon,
'config': options.config,
'user': options.user,
'pidfile': options.pidfile}
return cli
def start(self):
'''
Run the sequence to start a salt master server
'''
self.parse_args()
try:
verify_env([
self.opts['pki_dir'],
os.path.join(self.opts['pki_dir'], 'minions'),
os.path.join(self.opts['pki_dir'], 'minions_pre'),
os.path.join(self.opts['pki_dir'], 'minions_rejected'),
self.opts['cachedir'],
os.path.join(self.opts['cachedir'], 'jobs'),
os.path.dirname(self.opts['log_file']),
self.opts['sock_dir'],
], self.opts['user'],
permissive=self.opts['permissive_pki_access'])
self.config['pki_dir'],
os.path.join(self.config['pki_dir'], 'minions'),
os.path.join(self.config['pki_dir'], 'minions_pre'),
os.path.join(self.config['pki_dir'], 'minions_rejected'),
self.config['cachedir'],
os.path.join(self.config['cachedir'], 'jobs'),
os.path.dirname(self.config['log_file']),
self.config['sock_dir'],
], self.config['user'],
permissive=self.config['permissive_pki_access'])
except OSError, err:
sys.exit(err.errno)
import salt.log
salt.log.setup_logfile_logger(
self.opts['log_file'],
self.opts['log_level_logfile'] or self.opts['log_level'],
log_format=self.opts['log_fmt_logfile'],
date_format=self.opts['log_datefmt']
)
for name, level in self.opts['log_granular_levels'].items():
salt.log.set_logger_level(name, level)
self.setup_logfile_logger()
import logging
log = logging.getLogger(__name__)
# Late import so logging works correctly
if not verify_socket(
self.opts['interface'],
self.opts['publish_port'],
self.opts['ret_port']
):
log.critical('The ports are not available to bind')
sys.exit(4)
if not verify_socket(self.config['interface'],
self.config['publish_port'],
self.config['ret_port']):
self.exit(4, 'The ports are not available to bind')
import salt.master
master = salt.master.Master(self.opts)
if self.cli['daemon']:
# Late import so logging works correctly
import salt.utils
salt.utils.daemonize()
set_pidfile(self.opts['pidfile'])
if check_user(self.opts['user'], log):
master = salt.master.Master(self.config)
self.daemonize_if_required()
self.set_pidfile()
if check_user(self.config['user'], log):
try:
master.start()
except salt.master.MasterExit:
sys.exit()
class Minion(object):
class Minion(parsers.MinionOptionParser):
'''
Create a minion server
'''
def __init__(self):
self.cli = self.__parse_cli()
# command line overrides config
if self.cli['user']:
self.opts['user'] = self.cli['user']
def __parse_cli(self):
'''
Parse the cli input
'''
import salt.log
parser = optparse.OptionParser(version="%%prog %s" % __version__)
parser.add_option('-d',
'--daemon',
dest='daemon',
default=False,
action='store_true',
help='Run the minion as a daemon')
parser.add_option('-c',
'--config',
dest='config',
default='/etc/salt/minion',
help='Pass in an alternative configuration file')
parser.add_option('-u',
'--user',
dest='user',
help='Specify user to run minion')
parser.add_option('--pid-file',
dest='pidfile',
default='/var/run/salt-minion.pid',
help=('Specify the location of the pidfile. Default'
' %default'))
parser.add_option('-l',
'--log-level',
dest='log_level',
choices=list(salt.log.LOG_LEVELS),
help='Console log level. One of %s. For the logfile settings '
'see the config file. Default: \'warning\'.' %
', '.join([repr(l) for l in salt.log.SORTED_LEVEL_NAMES]))
options, args = parser.parse_args()
self.opts = salt.config.minion_config(options.config)
if not options.log_level:
options.log_level = self.opts['log_level']
salt.log.setup_console_logger(
options.log_level,
log_format=self.opts['log_fmt_console'],
date_format=self.opts['log_datefmt']
)
cli = {'daemon': options.daemon,
'config': options.config,
'user': options.user,
'pidfile': options.pidfile}
return cli
def start(self):
'''
Execute this method to start up a minion.
'''
self.parse_args()
try:
verify_env([
self.opts['pki_dir'],
self.opts['cachedir'],
self.opts['sock_dir'],
self.opts['extension_modules'],
os.path.dirname(self.opts['log_file']),
], self.opts['user'],
permissive=self.opts['permissive_pki_access'])
self.config['pki_dir'],
self.config['cachedir'],
self.config['sock_dir'],
self.config['extension_modules'],
os.path.dirname(self.config['log_file']),
], self.config['user'],
permissive=self.config['permissive_pki_access'])
except OSError, err:
sys.exit(err.errno)
import salt.log
salt.log.setup_logfile_logger(
self.opts['log_file'],
self.opts['log_level_logfile'] or self.opts['log_level'],
log_format=self.opts['log_fmt_logfile'],
date_format=self.opts['log_datefmt']
)
for name, level in self.opts['log_granular_levels'].items():
salt.log.set_logger_level(name, level)
self.setup_logfile_logger()
import logging
# Late import so logging works correctly
import salt.minion
log = logging.getLogger(__name__)
if self.cli['daemon']:
# Late import so logging works correctly
import salt.utils
# If the minion key has not been accepted, then Salt enters a loop
# waiting for it, if we daemonize later then the minion could halt
# the boot process waiting for a key to be accepted on the master.
# This is the latest safe place to daemonize
salt.utils.daemonize()
# If the minion key has not been accepted, then Salt enters a loop
# waiting for it, if we daemonize later then the minion could halt
# the boot process waiting for a key to be accepted on the master.
# This is the latest safe place to daemonize
self.daemonize_if_required()
try:
minion = salt.minion.Minion(self.opts)
set_pidfile(self.cli['pidfile'])
if check_user(self.opts['user'], log):
minion = salt.minion.Minion(self.config)
self.set_pidfile()
if check_user(self.config['user'], log):
minion.tune_in()
except KeyboardInterrupt:
log.warn('Stopping the Salt Minion')
raise SystemExit('\nExiting on Ctrl-c')
class Syndic(object):
class Syndic(parsers.SyndicOptionParser):
'''
Create a syndic server
'''
def __init__(self):
self.cli = self.__parse_cli()
# command line overrides config
if self.cli['user']:
self.opts['user'] = self.cli['user']
def __prep_opts(self, cli):
'''
Generate the opts used by the syndic
'''
opts = salt.config.master_config(cli['master_config'])
opts['_minion_conf_file'] = opts['conf_file']
opts.update(salt.config.minion_config(cli['minion_config']))
if 'syndic_master' in opts:
# Some of the opts need to be changed to match the needed opts
# in the minion class.
opts['master'] = opts['syndic_master']
opts['master_ip'] = salt.utils.dns_check(opts['master'])
opts['master_uri'] = ('tcp://' + opts['master_ip'] +
':' + str(opts['master_port']))
opts['_master_conf_file'] = opts['conf_file']
opts.pop('conf_file')
return opts
err = ('The syndic_master needs to be configured in the salt master '
'config, EXITING!\n')
sys.stderr.write(err)
sys.exit(2)
def __parse_cli(self):
'''
Parse the cli for options passed to a syndic daemon
'''
import salt.log
parser = optparse.OptionParser(version="%%prog %s" % __version__)
parser.add_option('-d',
'--daemon',
dest='daemon',
default=False,
action='store_true',
help='Run the syndic as a daemon')
parser.add_option('--master-config',
dest='master_config',
default='/etc/salt/master',
help='Pass in an alternative master configuration file')
parser.add_option('--minion-config',
dest='minion_config',
default='/etc/salt/minion',
help='Pass in an alternative minion configuration file')
parser.add_option('-u',
'--user',
dest='user',
help='Specify user to run syndic')
parser.add_option('--pid-file',
dest='pidfile',
default='/var/run/salt-syndic.pid',
help=('Specify the location of the pidfile. Default'
' %default'))
parser.add_option('-l',
'--log-level',
dest='log_level',
choices=list(salt.log.LOG_LEVELS),
help='Console log level. One of %s. For the logfile settings '
'see the config file. Default: \'warning\'.' %
', '.join([repr(l) for l in salt.log.LOG_LEVELS]))
options, args = parser.parse_args()
cli = {'daemon': options.daemon,
'minion_config': options.minion_config,
'master_config': options.master_config,
'pidfile': options.pidfile,
'user': options.user}
self.opts = self.__prep_opts(cli)
if not options.log_level:
options.log_level = self.opts['log_level']
salt.log.setup_console_logger(
options.log_level,
log_format=self.opts['log_fmt_console'],
date_format=self.opts['log_datefmt']
)
return cli
def start(self):
'''
Execute this method to start up a syndic.
'''
self.parse_args()
try:
verify_env([
self.opts['pki_dir'], self.opts['cachedir'],
os.path.dirname(self.opts['log_file']),
], self.opts['user'],
permissive=self.opts['permissive_pki_access'])
self.config['pki_dir'], self.config['cachedir'],
os.path.dirname(self.config['log_file']),
],
self.config['user'],
permissive=self.config['permissive_pki_access']
)
except OSError, err:
sys.exit(err.errno)
import salt.log
salt.log.setup_logfile_logger(
self.opts['log_file'], self.opts['log_level']
)
for name, level in self.opts['log_granular_levels'].items():
salt.log.set_logger_level(name, level)
self.setup_logfile_logger()
import logging
# Late import so logging works correctly
import salt.minion
log = logging.getLogger(__name__)
if self.cli['daemon']:
# Late import so logging works correctly
import salt.utils
salt.utils.daemonize()
set_pidfile(self.cli['pidfile'])
if check_user(self.opts['user'], log):
self.daemonize_if_required()
self.set_pidfile()
if check_user(self.config['user'], log):
try:
syndic = salt.minion.Syndic(self.opts)
syndic = salt.minion.Syndic(self.config)
syndic.tune_in()
except KeyboardInterrupt:
log.warn('Stopping the Salt Syndic Minion')

View file

@ -15,9 +15,10 @@ import salt.client
import salt.output
import salt.runner
from salt.utils import parser as optparse
#from salt.utils import parsers as optparse
import optparse
from salt.utils.verify import verify_env
from salt import __version__ as VERSION
from salt.version import __version__ as VERSION
from salt.exceptions import SaltInvocationError, SaltClientError, \
SaltException

View file

@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
"""
salt.utils.parser
~~~~~~~~~~~~~~~~~
:copyright: © 2012 UfSoft.org - :email:`Pedro Algarvio (pedro@algarvio.me)`
:license: Apache 2.0, see LICENSE for more details.
"""
import sys
import optparse
from salt import version
class OptionParser(optparse.OptionParser):
def __init__(self, *args, **kwargs):
kwargs.setdefault("version", version.__version__)
kwargs.setdefault('usage', '%prog')
optparse.OptionParser.__init__(self, *args, **kwargs)
def parse_args(self, args=None, values=None):
options, args = optparse.OptionParser.parse_args(self, args, values)
if options.versions_report:
self.print_versions_report()
return options, args
def _add_version_option(self):
optparse.OptionParser._add_version_option(self)
self.add_option(
'--versions-report', action='store_true',
help="show program's dependencies version number and exit"
)
def print_versions_report(self, file=sys.stdout):
print >> file, '\n'.join(version.versions_report())
self.exit()

353
salt/utils/parsers.py Normal file
View file

@ -0,0 +1,353 @@
# -*- coding: utf-8 -*-
"""
salt.utils.parser
~~~~~~~~~~~~~~~~~
:copyright: © 2012 UfSoft.org - :email:`Pedro Algarvio (pedro@algarvio.me)`
:license: Apache 2.0, see LICENSE for more details.
"""
import os
import sys
import optparse
from salt import config, log, version
def _sorted(mixins_or_funcs):
return sorted(
mixins_or_funcs, key=lambda mf: getattr(mf, '_mixin_prio_', 1000)
)
class MixInMeta(type):
# This attribute here won't actually do anything. But, if you need to
# specify an order or a dependency within the mix-ins, please define the
# attribute on your own MixIn
_mixin_prio_ = 0
def __new__(cls, name, bases, attrs):
instance = super(MixInMeta, cls).__new__(cls, name, bases, attrs)
if not hasattr(instance, '_mixin_setup'):
raise RuntimeError(
"Don't subclass {0} in {1} if you're not going to use it as a "
"salt parser mix-in.".format(cls.__name__, name)
)
return instance
class OptionParserMeta(MixInMeta):
def __new__(cls, name, bases, attrs):
instance = super(OptionParserMeta, cls).__new__(cls, name, bases, attrs)
if not hasattr(instance, '_mixin_setup_funcs'):
instance._mixin_setup_funcs = []
if not hasattr(instance, '_mixin_process_funcs'):
instance._mixin_process_funcs = []
if not hasattr(instance, '_mixin_after_parsed_funcs'):
instance._mixin_after_parsed_funcs = []
for base in _sorted(bases+(instance,)):
func = getattr(base, '_mixin_setup', None)
if func is not None and func not in instance._mixin_setup_funcs:
instance._mixin_setup_funcs.append(func)
func = getattr(base, '_mixin_after_parsed', None)
if func is not None and func not in instance._mixin_after_parsed_funcs:
instance._mixin_after_parsed_funcs.append(func)
# Mark process_<opt> functions with the base priority for sorting
for func in dir(base):
if not func.startswith('process_'):
continue
func = getattr(base, func)
if getattr(func, '_mixin_prio_', None) is not None:
# Function already has the attribute set, don't override it
continue
func.__func__._mixin_prio_ = getattr(base, '_mixin_prio_', 1000)
return instance
class OptionParser(optparse.OptionParser):
usage = "%prog"
epilog = ("You can find additional help about %prog issuing 'man %prog' "
"or on http://docs.saltstack.org/en/latest/index.html")
description = None
# Private attributes
_mixin_prio_ = 100
def __init__(self, *args, **kwargs):
kwargs.setdefault("version", "%prog {0}".format(version.__version__))
kwargs.setdefault("usage", self.usage)
if self.description:
kwargs.setdefault('description', self.description)
if self.epilog:
kwargs.setdefault('epilog', self.epilog)
optparse.OptionParser.__init__(self, *args, **kwargs)
if "%prog" in self.epilog:
self.epilog = self.epilog.replace("%prog", self.get_prog_name())
def parse_args(self, args=None, values=None):
options, args = optparse.OptionParser.parse_args(self, args, values)
if options.versions_report:
self.print_versions_report()
self.options, self.args = options, args
# Gather and run the process_<option> functions in the proper order
process_option_funcs = []
for option_key in options.__dict__.keys():
process_option_func = getattr(self, "process_%s" % option_key, None)
if process_option_func is not None:
process_option_funcs.append(process_option_func)
for process_option_func in _sorted(process_option_funcs):
process_option_func()
# Run the functions on self._mixin_after_parsed_funcs
for mixin_after_parsed_func in self._mixin_after_parsed_funcs:
mixin_after_parsed_func(self)
# Retain the standard behaviour of optparse to return options and args
return options, args
def _populate_option_list(self, option_list, add_help=True):
optparse.OptionParser._populate_option_list(
self, option_list, add_help=add_help
)
for mixin_setup_func in self._mixin_setup_funcs:
mixin_setup_func(self)
def _add_version_option(self):
optparse.OptionParser._add_version_option(self)
self.add_option(
'--versions-report', action='store_true',
help="show program's dependencies version number and exit"
)
def print_versions_report(self, file=sys.stdout):
print >> file, '\n'.join(version.versions_report())
self.exit()
class DeprecatedConfigMessage(object):
_mixin_prio_ = -10
def print_config_warning(self, *args, **kwargs):
self.error(
"The '-c/--config' option is deprecated. You should now use "
"-c/--config-dir to point to a directory which holds all of "
"salt's configuration files.\n"
)
class ConfigDirMixIn(DeprecatedConfigMessage):
__metaclass__ = MixInMeta
def _mixin_setup(self):
self.add_option(
'-c', '--config-dir', default='/etc/salt',
help=('Pass in an alternative configuration directory. Default: '
'%default')
)
def __merge_config_with_cli(self, *args):
for option in self.option_list:
if not option.dest:
# --version does not have dest attribute set for example.
# All options defined by us, even if not explicitly(by kwarg),
# will have the dest attribute set
continue
value = getattr(self.options, option.dest, None)
if value:
self.config[option.dest] = value
def process_config_dir(self):
# XXX: Remove deprecation warning in next release
if os.path.isfile(self.options.config_dir):
self.print_config_warning()
if hasattr(self, 'setup_config'):
self.config = self.setup_config()
# Add an additional function that will merge the cli options with
# the config options and if needed override them
self._mixin_after_parsed_funcs.append(self.__merge_config_with_cli)
def get_config_file_path(self, configfile):
return os.path.join(self.options.config_dir, configfile)
class DeprecatedMasterMinionMixIn(DeprecatedConfigMessage):
__metaclass__ = MixInMeta
def _mixin_setup(self):
# XXX: Remove deprecated option in next release
self.add_option(
'--config', action="callback", callback=self.print_config_warning,
help='DEPRECATED. Please use -c/--config-dir from now on.'
)
class DeprecatedSyndicOptionsMixIn(DeprecatedConfigMessage):
__metaclass__ = MixInMeta
def _mixin_setup(self):
# XXX: Remove deprecated option in next release
self.add_option(
'--master-config', '--minion-config',
action="callback", callback=self.print_config_warning,
help='DEPRECATED. Please use -c/--config-dir from now on.'
)
def process_config_dir(self, options):
# XXX: Remove deprecation warning in next release
if os.path.isfile(options.config_dir):
self.print_config_warning()
if hasattr(self, 'setup_config'):
self.config = self.setup_config()
class LogLevelMixIn(object):
__metaclass__ = MixInMeta
_mixin_prio_ = 10
_skip_console_logging_config_ = False
def _mixin_setup(self):
if getattr(self, '_skip_console_logging_config_', False):
return
self.add_option(
'-l', '--log-level',
choices=list(log.LOG_LEVELS),
help=('Logging log level. One of {0}. For the logfile settings see '
'the configuration file. Default: \'warning\'.').format(
', '.join([repr(l) for l in log.SORTED_LEVEL_NAMES])
)
)
def process_log_level(self):
if not self.options.log_level:
self.options.log_level = self.config['log_level']
log.setup_console_logger(
self.options.log_level,
log_format=self.config['log_fmt_console'],
date_format=self.config['log_datefmt']
)
def setup_logfile_logger(self):
log.setup_logfile_logger(
self.config['log_file'],
self.config['log_level_logfile'] or self.config['log_level'],
log_format=self.config['log_fmt_logfile'],
date_format=self.config['log_datefmt']
)
for name, level in self.config['log_granular_levels'].items():
log.set_logger_level(name, level)
class RunUserMixin(object):
__metaclass__ = MixInMeta
_mixin_prio_ = 20
def _mixin_setup(self):
self.add_option(
'-u', '--user',
help='Specify user to run {0}'.format(self.get_prog_name())
)
class DaemonMixIn(object):
__metaclass__ = MixInMeta
_mixin_prio_ = 30
def _mixin_setup(self):
self.add_option(
'-d', '--daemon',
default=False,
action='store_true',
help='Run the {0} as a daemon'.format(self.get_prog_name())
)
def daemonize_if_required(self):
if self.options.daemon:
# Late import so logging works correctly
import salt.utils
salt.utils.daemonize()
class PidfileMixin(object):
__metaclass__ = MixInMeta
_mixin_prio_ = 40
def _mixin_setup(self):
self.add_option(
'--pid-file', dest='pidfile',
default='/var/run/{0}.pid'.format(self.get_prog_name()),
help=('Specify the location of the pidfile. Default: %default')
)
def set_pidfile(self):
from salt.utils.process import set_pidfile
set_pidfile(self.config['pidfile'])
class MasterOptionParser(OptionParser, ConfigDirMixIn, LogLevelMixIn,
DeprecatedMasterMinionMixIn, RunUserMixin,
DaemonMixIn, PidfileMixin):
__metaclass__ = OptionParserMeta
description = "TODO: explain what salt-master is"
def setup_config(self):
return config.master_config(self.get_config_file_path('master'))
class MinionOptionParser(MasterOptionParser):
__metaclass__ = OptionParserMeta
description = "TODO: explain what salt-minion is"
def setup_config(self, options):
return config.minion_config(self.get_config_file_path('minion'))
class SyndicOptionParser(OptionParser, DeprecatedSyndicOptionsMixIn,
ConfigDirMixIn, LogLevelMixIn, RunUserMixin,
DaemonMixIn, PidfileMixin):
__metaclass__ = OptionParserMeta
description = ("A seamless master of masters. Scale Salt to thousands of "
"hosts or across many different networks.")
def setup_config(self, options):
opts = config.master_config(self.get_config_file_path('master'))
opts['_minion_conf_file'] = opts['conf_file']
opts.update(config.minion_config(self.get_config_file_path('minion')))
if 'syndic_master' not in opts:
self.error(
"The syndic_master needs to be configured in the salt master "
"config, EXITING!"
)
from salt import utils
# Some of the opts need to be changed to match the needed opts
# in the minion class.
opts['master'] = opts['syndic_master']
opts['master_ip'] = utils.dns_check(opts['master'])
opts['master_uri'] = 'tcp://{0}:{1}'.format(
opts['master_ip'], str(opts['master_port'])
)
opts['_master_conf_file'] = opts['conf_file']
opts.pop('conf_file')
return opts

View file

@ -320,7 +320,7 @@ class ShellCase(TestCase):
'''
Execute a test for a shell command
'''
def run_script(self, script, arg_str):
def run_script(self, script, arg_str, catch_stderr=False):
'''
Execute a script with the given argument string
'''
@ -329,11 +329,17 @@ class ShellCase(TestCase):
return False
ppath = 'PYTHONPATH={0}:{1}'.format(CODE_DIR, ':'.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
if catch_stderr:
out, err = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
).communicate()
return out.split('\n'), err.split('\n')
data = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE
).communicate()
return data[0].split('\n')
def run_salt(self, arg_str):
'''
@ -376,3 +382,33 @@ class ShellCase(TestCase):
mconf = os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'master')
arg_str = '-c {0} {1}'.format(mconf, arg_str)
return self.run_script('salt-key', arg_str)
class ShellCaseCommonTestsMixIn(object):
def test_deprecated_config(self):
"""
test for the --config deprecation warning
Once --config is fully deprecated, this test can be removed
"""
if getattr(self, '_call_binary_', None) is None:
self.skipTest("'_call_binary_' not defined.")
cfgfile = os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf', 'master')
out, err = self.run_script(
self._call_binary_, "--config {0}".format(cfgfile), catch_stderr=True
)
self.assertIn('Usage: {0}'.format(self._call_binary_), '\n'.join(err))
self.assertIn('deprecated', '\n'.join(err))
def test_version_includes_binary_name(self):
if getattr(self, '_call_binary_', None) is None:
self.skipTest("'_call_binary_' not defined.")
out = '\n'.join(self.run_script(self._call_binary_, "--version"))
self.assertIn(self._call_binary_, out)
self.assertIn(salt.__version__, out)

View file

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""
tests.integration.shell.master
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: © 2012 UfSoft.org - :email:`Pedro Algarvio (pedro@algarvio.me)`
:license: Apache 2.0, see LICENSE for more details.
"""
import sys
# Import salt libs
from saltunittest import TestLoader, TextTestRunner
import integration
from integration import TestDaemon
class MasterTest(integration.ShellCase, integration.ShellCaseCommonTestsMixIn):
_call_binary_ = 'salt-master'
if __name__ == "__main__":
loader = TestLoader()
tests = loader.loadTestsFromTestCase(MasterTest)
print('Setting up Salt daemons to execute tests')
with TestDaemon():
runner = TextTestRunner(verbosity=1).run(tests)
sys.exit(runner.wasSuccessful())

View file

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""
tests.integration.shell.minion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: © 2012 UfSoft.org - :email:`Pedro Algarvio (pedro@algarvio.me)`
:license: Apache 2.0, see LICENSE for more details.
"""
import sys
# Import salt libs
from saltunittest import TestLoader, TextTestRunner
import integration
from integration import TestDaemon
class MinionTest(integration.ShellCase, integration.ShellCaseCommonTestsMixIn):
_call_binary_ = 'salt-minion'
if __name__ == "__main__":
loader = TestLoader()
tests = loader.loadTestsFromTestCase(MinionTest)
print('Setting up Salt daemons to execute tests')
with TestDaemon():
runner = TextTestRunner(verbosity=1).run(tests)
sys.exit(runner.wasSuccessful())

View file

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""
tests.integration.shell.syndic
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: © 2012 UfSoft.org - :email:`Pedro Algarvio (pedro@algarvio.me)`
:license: Apache 2.0, see LICENSE for more details.
"""
import sys
# Import salt libs
from saltunittest import TestLoader, TextTestRunner
import integration
from integration import TestDaemon
class SyndicTest(integration.ShellCase, integration.ShellCaseCommonTestsMixIn):
_call_binary_ = 'salt-syndic'
if __name__ == "__main__":
loader = TestLoader()
tests = loader.loadTestsFromTestCase(SyndicTest)
print('Setting up Salt daemons to execute tests')
with TestDaemon():
runner = TextTestRunner(verbosity=1).run(tests)
sys.exit(runner.wasSuccessful())