mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 17:50:20 +00:00
Begin modifying proxy to be called from command line.
This commit is contained in:
parent
c60452715b
commit
abdbbb6325
4 changed files with 153 additions and 82 deletions
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
26
scripts/salt-proxy
Executable 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()
|
Loading…
Add table
Reference in a new issue