Begin modifying proxy to be called from command line.

This commit is contained in:
C. R. Oldham 2015-08-11 12:31:00 -06:00
parent c60452715b
commit abdbbb6325
4 changed files with 153 additions and 82 deletions

View file

@ -192,6 +192,7 @@ class Minion(parsers.MinionOptionParser): # pylint: disable=no-init
confd = os.path.join(
os.path.dirname(self.config['conf_file']), 'minion.d'
)
v_dirs = [
self.config['pki_dir'],
self.config['cachedir'],
@ -199,11 +200,13 @@ class Minion(parsers.MinionOptionParser): # pylint: disable=no-init
self.config['extension_modules'],
confd,
]
if self.config.get('transport') == 'raet':
v_dirs.append(os.path.join(self.config['pki_dir'], 'accepted'))
v_dirs.append(os.path.join(self.config['pki_dir'], 'pending'))
v_dirs.append(os.path.join(self.config['pki_dir'], 'rejected'))
v_dirs.append(os.path.join(self.config['cachedir'], 'raet'))
verify_env(
v_dirs,
self.config['user'],
@ -315,7 +318,8 @@ class ProxyMinion(parsers.MinionOptionParser): # pylint: disable=no-init
'''
Create a proxy minion server
'''
def prepare(self, proxydetails):
def prepare(self):
'''
Run the preparation sequence required to start a salt minion.
@ -344,14 +348,23 @@ class ProxyMinion(parsers.MinionOptionParser): # pylint: disable=no-init
confd = os.path.join(
os.path.dirname(self.config['conf_file']), 'minion.d'
)
v_dirs = [
self.config['pki_dir'],
self.config['cachedir'],
self.config['sock_dir'],
self.config['extension_modules'],
confd,
]
if self.config.get('transport') == 'raet':
v_dirs.append(os.path.join(self.config['pki_dir'], 'accepted'))
v_dirs.append(os.path.join(self.config['pki_dir'], 'pending'))
v_dirs.append(os.path.join(self.config['pki_dir'], 'rejected'))
v_dirs.append(os.path.join(self.config['cachedir'], 'raet'))
verify_env(
[
self.config['pki_dir'],
self.config['cachedir'],
self.config['sock_dir'],
self.config['extension_modules'],
confd,
],
v_dirs,
self.config['user'],
permissive=self.config['permissive_pki_access'],
pki_dir=self.config['pki_dir'],
@ -359,24 +372,30 @@ class ProxyMinion(parsers.MinionOptionParser): # pylint: disable=no-init
if 'proxy_log' in proxydetails:
logfile = proxydetails['proxy_log']
else:
logfile = None
logfile = self.config['log_file']
if logfile is not None and not logfile.startswith(('tcp://',
'udp://',
'file://')):
# Logfile is not using Syslog, verify
current_umask = os.umask(0o027)
verify_files([logfile], self.config['user'])
os.umask(current_umask)
except OSError as err:
logger.exception('Failed to prepare salt environment')
sys.exit(err.errno)
self.config['proxy'] = proxydetails
self.setup_logfile_logger()
logger.info(
'Setting up a Salt Proxy Minion "{0}"'.format(
self.config['id']
)
self.config['proxy'] = proxydetails
self.setup_logfile_logger()
logger.info(
'Setting up a Salt Proxy Minion "{0}"'.format(
self.config['id']
)
migrations.migrate_paths(self.config)
)
migrations.migrate_paths(self.config)
# TODO: AIO core is separate from transport
if self.config['transport'].lower() in ('zeromq', 'tcp'):
# Late import so logging works correctly
import salt.minion
# If the minion key has not been accepted, then Salt enters a loop
@ -385,12 +404,17 @@ class ProxyMinion(parsers.MinionOptionParser): # pylint: disable=no-init
# This is the latest safe place to daemonize
self.daemonize_if_required()
self.set_pidfile()
if isinstance(self.config.get('master'), list):
self.minion = salt.minion.MultiMinion(self.config)
else:
self.minion = salt.minion.ProxyMinion(self.config)
# TODO Proxy minions don't currently support failover
self.minion = salt.minion.ProxyMinion(self.config)
else:
# For proxy minions, this doesn't work yet.
import salt.daemons.flo
self.daemonize_if_required()
self.set_pidfile()
self.minion = salt.daemons.flo.IofloMinion(self.config)
def start(self, proxydetails):
def start(self):
'''
Start the actual minion.
@ -400,10 +424,11 @@ class ProxyMinion(parsers.MinionOptionParser): # pylint: disable=no-init
NOTE: Run any required code before calling `super()`.
'''
self.prepare(proxydetails)
try:
self.minion.tune_in()
logger.info('The proxy minion is starting up')
self.prepare(proxydetails)
if check_user(self.config['user']):
logger.info('The proxy minion is starting up')
self.minion.tune_in()
except (KeyboardInterrupt, SaltSystemExit) as exc:
logger.warn('Stopping the Salt Proxy Minion')
if isinstance(exc, KeyboardInterrupt):
@ -413,6 +438,7 @@ class ProxyMinion(parsers.MinionOptionParser): # pylint: disable=no-init
finally:
self.shutdown()
def shutdown(self):
'''
If sub-classed, run any shutdown operations on this method.

View file

@ -554,7 +554,6 @@ class Minion(MinionBase):
This class instantiates a minion, runs connections for a minion,
and loads all of the functions into the minion
'''
def __init__(self, opts, timeout=60, safe=True, loaded_base_name=None, io_loop=None): # pylint: disable=W0231
'''
Pass in the options dict
@ -642,6 +641,11 @@ class Minion(MinionBase):
self.beacons = salt.beacons.Beacon(self.opts, self.functions)
uid = salt.utils.get_uid(user=self.opts.get('user', None))
self.proc_dir = get_proc_dir(self.opts['cachedir'], uid=uid)
# For proxy minions
if 'proxymodule' in self.opts:
self.opts['proxymodule']['init'](self.opts)
self.schedule = salt.utils.schedule.Schedule(
self.opts,
self.functions,
@ -687,7 +691,7 @@ class Minion(MinionBase):
continue
else:
reinit_crypto()
proxyminion = salt.cli.daemons.ProxyMinion(self.opts)
proxyminion = salt.cli.daemons.ProxyMinion()
proxyminion.start(self.opts['pillar']['proxy'][p])
self.clean_die(signal.SIGTERM, None)
else:
@ -2483,14 +2487,23 @@ class ProxyMinion(Minion):
This class instantiates a 'proxy' minion--a minion that does not manipulate
the host it runs on, but instead manipulates a device that cannot run a minion.
'''
def __init__(self, opts, timeout=60, safe=True, loaded_base_name=None): # pylint: disable=W0231
def __init__(self, opts, timeout=60, safe=True, loaded_base_name=None, io_loop=None): # pylint: disable=W0231
'''
Pass in the options dict
'''
# this means that the parent class doesn't know *which* master we connect to
super(ProxyMinion, self).__init__(opts)
self.timeout = timeout
self.safe = safe
self._running = None
self.win_proc = []
self.loaded_base_name = loaded_base_name
self.io_loop = io_loop or zmq.eventloop.ioloop.ZMQIOLoop()
if not self.io_loop.initialized():
self.io_loop.install()
# Warn if ZMQ < 3.2
if HAS_ZMQ:
try:
@ -2508,11 +2521,8 @@ class ProxyMinion(Minion):
'may result in loss of contact with minions. Please '
'upgrade your ZMQ!'
)
# Late setup the of the opts grains, so we can log from the grains
# module
opts['master'] = self.eval_master(opts,
timeout,
safe)
self.opts = opts
fq_proxyname = opts['proxy']['proxytype']
# Need to match the function signature of the other loader fns
# which is def proxy(opts, functions, whitelist=None, loaded_base_name=None)
@ -2520,56 +2530,11 @@ class ProxyMinion(Minion):
# but since we are not needing to merge functions into another fn dictionary
# we will pass 'None' in
self.proxymodule = salt.loader.proxy(opts, None, loaded_base_name=fq_proxyname)
opts['proxymodule'] = self.proxymodule
opts['grains'] = salt.loader.grains(opts)
opts['id'] = opts['proxymodule'][fq_proxyname+'.id'](opts)
opts.update(resolve_dns(opts))
self.opts = opts
self.opts['pillar'] = salt.pillar.get_pillar(
opts,
opts['grains'],
opts['id'],
opts['environment'],
pillarenv=opts.get('pillarenv'),
).compile_pillar()
opts['proxymodule'][fq_proxyname+'.init'](opts)
self.functions, self.returners, self.function_errors = self._load_modules()
self.serial = salt.payload.Serial(self.opts)
self.mod_opts = self._prep_mod_opts()
self.matcher = Matcher(self.opts, self.functions)
uid = salt.utils.get_uid(user=opts.get('user', None))
self.proc_dir = get_proc_dir(opts['cachedir'], uid=uid)
self.schedule = salt.utils.schedule.Schedule(
self.opts,
self.functions,
self.returners)
self.opts['proxymodule'] = self.proxymodule
# Late setup the of the opts grains, so we can log from the grains
# module
self.opts['grains'] = salt.loader.grains(opts)
self.opts['id'] = self.opts['proxymodule'][fq_proxyname+'.id'](opts)
# add default scheduling jobs to the minions scheduler
if 'mine.update' in self.functions:
log.info('Added mine.update to scheduler')
self.schedule.add_job({
'__mine_interval':
{
'function': 'mine.update',
'minutes': opts['mine_interval'],
'jid_include': True,
'maxrunning': 2
}
})
self.grains_cache = self.opts['grains']
# self._running = True
def _prep_mod_opts(self):
'''
Returns a copy of the opts with key bits stripped out
'''
return super(ProxyMinion, self)._prep_mod_opts()
def _load_modules(self, force_refresh=False, notify=False):
'''
Return the functions and the returners loaded up from the loader
module
'''
return super(ProxyMinion, self)._load_modules(force_refresh=force_refresh, notify=notify)

View file

@ -154,6 +154,60 @@ def salt_minion():
logging.basicConfig()
def salt_proxy_minion():
'''
Start a proxy minion.
'''
import salt.cli.daemons
import multiprocessing
if '' in sys.path:
sys.path.remove('')
if salt.utils.is_windows():
minion = salt.cli.daemons.ProxyMinion()
minion.start()
return
if '--disable-keepalive' in sys.argv:
sys.argv.remove('--disable-keepalive')
minion = salt.cli.daemons.ProxyMinion()
minion.start()
return
# keep one minion subprocess running
while True:
try:
queue = multiprocessing.Queue()
except Exception:
# This breaks in containers
minion = salt.cli.daemons.ProxyMinion()
minion.start()
return
process = multiprocessing.Process(target=proxy_minion_process, args=(queue,))
process.start()
try:
process.join()
try:
restart_delay = queue.get(block=False)
except Exception:
if process.exitcode == 0:
# Minion process ended naturally, Ctrl+C or --version
break
restart_delay = 60
if restart_delay == 0:
# Minion process ended naturally, Ctrl+C, --version, etc.
break
# delay restart to reduce flooding and allow network resources to close
time.sleep(restart_delay)
except KeyboardInterrupt:
break
# need to reset logging because new minion objects
# cause extra log handlers to accumulate
rlogger = logging.getLogger()
for handler in rlogger.handlers:
rlogger.removeHandler(handler)
logging.basicConfig()
def salt_syndic():
'''
Start the salt syndic.

26
scripts/salt-proxy Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env python
'''
This script is used to kick off a salt proxy minion daemon
'''
from salt.scripts import salt_proxy_minion
from salt.utils import is_windows
from multiprocessing import freeze_support
if __name__ == '__main__':
if is_windows():
# Since this file does not have a '.py' extension, when running on
# Windows, spawning any addional processes will fail due to Python
# not being able to load this 'module' in the new process.
# Work around this by creating a '.pyc' file which will enable the
# spawned process to load this 'module' and proceed.
import os.path
import py_compile
cfile = os.path.splitext(__file__)[0] + '.pyc'
if not os.path.exists(cfile):
py_compile.compile(__file__, cfile)
# This handles the bootstrapping code that is included with frozen
# scripts. It is a no-op on unfrozen code.
freeze_support()
salt_proxy_minion()