%PDF- %PDF-
Direktori : /lib/python2.7/site-packages/salt/daemons/flo/ |
Current File : //lib/python2.7/site-packages/salt/daemons/flo/core.py |
# -*- coding: utf-8 -*- ''' The core behaviors used by minion and master ''' # pylint: disable=W0232 # pylint: disable=3rd-party-module-not-gated # Import python libs from __future__ import absolute_import, print_function, unicode_literals import os import time import random import logging import itertools from collections import deque from _socket import gaierror # Import salt libs import salt.daemons.masterapi import salt.utils.args import salt.utils.kinds as kinds import salt.utils.process import salt.utils.stringutils import salt.transport import salt.engines # pylint: disable=import-error from raet import raeting from raet.road.stacking import RoadStack from raet.road.estating import RemoteEstate from raet.lane.stacking import LaneStack # pylint: enable=import-error from salt import daemons from salt.daemons import salting from salt.exceptions import SaltException from salt.utils.platform import is_windows from salt.utils.event import tagify # Import ioflo libs # pylint: disable=import-error from ioflo.aid.odicting import odict # pylint: disable=E0611,F0401 import ioflo.base.deeding from ioflo.base.consoling import getConsole # pylint: enable=import-error console = getConsole() # Import Third Party Libs # pylint: disable=import-error HAS_PSUTIL = False try: import salt.utils.psutil_compat as psutil HAS_PSUTIL = True except ImportError: pass HAS_RESOURCE = False try: import resource HAS_RESOURCE = True except ImportError: pass # pylint: disable=no-name-in-module,redefined-builtin from salt.ext import six from salt.ext.six.moves import range # pylint: enable=import-error,no-name-in-module,redefined-builtin log = logging.getLogger(__name__) class SaltRaetCleanup(ioflo.base.deeding.Deed): ''' Cleanup stray lane keep directories not reaped FloScript: do salt raet cleanup at enter ''' Ioinits = { 'opts': salt.utils.stringutils.to_str('.salt.opts'), } def action(self): ''' Should only run once to cleanup stale lane uxd files. ''' if not is_windows() and self.opts.value.get('sock_dir'): sockdirpath = os.path.abspath(self.opts.value['sock_dir']) console.concise("Cleaning up uxd files in {0}\n".format(sockdirpath)) protecteds = self.opts.value.get('raet_cleanup_protecteds', []) for name in os.listdir(sockdirpath): path = os.path.join(sockdirpath, name) if os.path.isdir(path): continue root, ext = os.path.splitext(name) if ext != '.uxd': continue if not all(root.partition('.')): continue if path in protecteds: continue try: os.unlink(path) console.concise("Removed {0}\n".format(path)) except OSError: console.concise("Failed removing {0}\n".format(path)) raise class SaltRaetRoadClustered(ioflo.base.deeding.Deed): ''' Updates value of share .salt.road.manor.cluster.clustered Twith opts['cluster_mode'] FloScript: do salt raet road clustered go next if .salt.road.manor.cluster.clustered ''' Ioinits = odict(inode=salt.utils.stringutils.to_str('.salt.road.manor.'), clustered=odict(ipath=salt.utils.stringutils.to_str('cluster.clustered'), ival=False), opts=salt.utils.stringutils.to_str('.salt.opts'),) def action(self, **kwa): ''' Update .cluster.clustered share from opts ''' self.clustered.update(value=self.opts.value.get('cluster_mode', False)) class SaltRaetProcessManagerSetup(ioflo.base.deeding.Deed): ''' Set up the process manager object ''' Ioinits = {'proc_mgr': salt.utils.stringutils.to_str('.salt.usr.proc_mgr')} def action(self): ''' Create the process manager ''' self.proc_mgr.value = salt.utils.process.ProcessManager() class SaltRaetRoadUsherMinionSetup(ioflo.base.deeding.Deed): ''' Set up .ushers which is initial list of masters to bootstrap into road FloScript: do salt raet road usher minion setup at enter ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), ushers=salt.utils.stringutils.to_str('ushers'), opts=salt.utils.stringutils.to_str('.salt.opts')) def action(self): ''' Assign .ushers by parsing opts ''' masters = 'master' port = None if self.opts.value.get('cluster_mode', False): masters = 'cluster_masters' self.ushers.value = daemons.extract_masters(self.opts.value, masters=masters, port=port) class SaltRaetRoadUsherMasterSetup(ioflo.base.deeding.Deed): ''' Set up .ushers which is initial list of masters to bootstrap into road FloScript: do salt raet road usher master setup at enter ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), ushers=salt.utils.stringutils.to_str('ushers'), opts=salt.utils.stringutils.to_str('.salt.opts')) def action(self): ''' Assign .ushers by parsing opts ''' masters = 'cluster_masters' port = 'raet_port' self.ushers.value = daemons.extract_masters(self.opts.value, masters=masters, port=port, raise_if_empty=False) class SaltRaetRoadClusterLoadSetup(ioflo.base.deeding.Deed): ''' Sets up cluster.masters for load balancing FloScript: do salt raet road cluster load setup at enter ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), masters={'ipath': salt.utils.stringutils.to_str('cluster.masters'), 'ival': odict()}, stack=salt.utils.stringutils.to_str('stack'), opts=salt.utils.stringutils.to_str('.salt.opts'),) def action(self, **kwa): ''' Populate loads from masters in stack.remotes ''' if self.opts.value.get('cluster_mode'): for remote in list(self.stack.value.remotes.values()): if remote.kind == kinds.applKinds.master: self.masters.value[remote.name] = odict(load=0.0, expire=self.store.stamp) class SaltRaetRoadStackSetup(ioflo.base.deeding.Deed): ''' Initialize and run raet udp stack for Salt FloScript: do salt raet road stack setup at enter ''' Ioinits = { 'inode': salt.utils.stringutils.to_str('salt.road.manor.'), 'stack': salt.utils.stringutils.to_str('stack'), 'opts': salt.utils.stringutils.to_str('.salt.opts'), 'txmsgs': {'ipath': salt.utils.stringutils.to_str('txmsgs'), 'ival': deque()}, 'rxmsgs': {'ipath': salt.utils.stringutils.to_str('rxmsgs'), 'ival': deque()}, 'local': {'ipath': salt.utils.stringutils.to_str('local'), 'ival': {'main': False, 'mutable': False, 'uid': None, 'role': 'master', 'sighex': None, 'prihex': None, 'bufcnt': 2}}, } def _prepare(self): ''' Assign class defaults ''' RoadStack.Bk = raeting.BodyKind.msgpack.value RoadStack.JoinentTimeout = 0.0 def action(self): ''' enter action should only run once to setup road stack. moved from _prepare so can do clean up before stack is initialized do salt raet road stack setup at enter ''' kind = self.opts.value['__role'] # application kind if kind not in kinds.APPL_KINDS: emsg = ("Invalid application kind = '{0}'.".format(kind)) log.error(emsg + '\n') raise ValueError(emsg) role = self.opts.value.get('id', '') if not role: emsg = ("Missing role required to setup RoadStack.") log.error(emsg + "\n") raise ValueError(emsg) name = "{0}_{1}".format(role, kind) main = self.opts.value.get('raet_main', self.local.data.main) mutable = self.opts.value.get('raet_mutable', self.local.data.mutable) always = self.opts.value.get('open_mode', False) mutable = mutable or always # open_made when True takes precedence uid = self.local.data.uid if kind == kinds.APPL_KIND_NAMES[kinds.applKinds.caller]: ha = (self.opts.value['interface'], self.opts.value['raet_alt_port']) else: ha = (self.opts.value['interface'], self.opts.value['raet_port']) basedirpath = os.path.abspath(os.path.join(self.opts.value['cachedir'], 'raet')) txMsgs = self.txmsgs.value rxMsgs = self.rxmsgs.value keep = salting.SaltKeep(opts=self.opts.value, basedirpath=basedirpath, stackname=name) roledata = keep.loadLocalRoleData() sighex = roledata['sighex'] or self.local.data.sighex prihex = roledata['prihex'] or self.local.data.prihex bufcnt = self.opts.value.get('raet_road_bufcnt', self.local.data.bufcnt) self.stack.value = RoadStack(store=self.store, keep=keep, name=name, uid=uid, ha=ha, role=role, sigkey=sighex, prikey=prihex, main=main, kind=kinds.APPL_KINDS[kind], mutable=mutable, txMsgs=txMsgs, rxMsgs=rxMsgs, period=3.0, offset=0.5, bufcnt=bufcnt) if self.opts.value.get('raet_clear_remotes'): for remote in list(self.stack.value.remotes.values()): self.stack.value.removeRemote(remote, clear=True) self.stack.puid = self.stack.value.Uid # reset puid class SaltRaetRoadStackCloser(ioflo.base.deeding.Deed): ''' Closes stack server socket connection FloScript: do salt raet road stack closer at exit ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), stack=salt.utils.stringutils.to_str('stack'), ) def action(self, **kwa): ''' Close udp socket ''' if self.stack.value and isinstance(self.stack.value, RoadStack): self.stack.value.server.close() class SaltRaetRoadStackJoiner(ioflo.base.deeding.Deed): ''' Initiates join transaction with master(s) FloScript: do salt raet road stack joiner at enter assumes that prior the following has been run to setup .masters do salt raet road usher minion setup ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), stack=salt.utils.stringutils.to_str('stack'), ushers=salt.utils.stringutils.to_str('ushers'), opts=salt.utils.stringutils.to_str('.salt.opts')) def action(self, **kwa): ''' Join with all masters ''' stack = self.stack.value if stack and isinstance(stack, RoadStack): refresh_masters = (self.opts.value.get('raet_clear_remote_masters', True) or not stack.remotes) refresh_all = (self.opts.value.get('raet_clear_remotes', True) or not stack.remotes) if refresh_masters: # clear all remote masters for remote in list(stack.remotes.values()): if remote.kind == kinds.applKinds.master: stack.removeRemote(remote, clear=True) if refresh_all: # clear all remotes for remote in list(stack.remotes.values()): stack.removeRemote(remote, clear=True) if refresh_all or refresh_masters: stack.puid = stack.Uid # reset puid so reuse same uid each time ex = SaltException('Unable to connect to any master') for master in self.ushers.value: try: mha = master['external'] stack.addRemote(RemoteEstate(stack=stack, fuid=0, # vacuous join sid=0, # always 0 for join ha=mha, kind=kinds.applKinds.master)) except gaierror as ex: log.warning("Unable to connect to master %s: %s", mha, ex) if self.opts.value.get('master_type') not in ('failover', 'distributed'): raise ex if not stack.remotes: raise ex for remote in list(stack.remotes.values()): if remote.kind == kinds.applKinds.master: stack.join(uid=remote.uid, timeout=0.0) class SaltRaetRoadStackJoined(ioflo.base.deeding.Deed): ''' Updates status with .joined of zeroth remote estate (master) FloScript: do salt raet road stack joined go next if joined in .salt.road.manor.status ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), stack=salt.utils.stringutils.to_str('stack'), status=odict(ipath=salt.utils.stringutils.to_str('status'), ival=odict(joined=False, allowed=False, alived=False, rejected=False, idle=False, ))) def action(self, **kwa): ''' Update .status share ''' stack = self.stack.value joined = False if stack and isinstance(stack, RoadStack): if stack.remotes: joined = any([remote.joined for remote in list(stack.remotes.values()) if remote.kind == kinds.applKinds.master]) self.status.update(joined=joined) class SaltRaetRoadStackRejected(ioflo.base.deeding.Deed): ''' Updates status with rejected of .acceptance of zeroth remote estate (master) FloScript: do salt raet road stack rejected go next if rejected in .salt.road.manor.status ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), stack=salt.utils.stringutils.to_str('stack'), status=odict(ipath=salt.utils.stringutils.to_str('status'), ival=odict(joined=False, allowed=False, alived=False, rejected=False, idle=False, ))) def action(self, **kwa): ''' Update .status share ''' stack = self.stack.value rejected = False if stack and isinstance(stack, RoadStack): if stack.remotes: rejected = all([remote.acceptance == raeting.Acceptance.rejected.value for remote in stack.remotes.values() if remote.kind == kinds.applKinds.master]) else: # no remotes so assume rejected rejected = True self.status.update(rejected=rejected) class SaltRaetRoadStackAllower(ioflo.base.deeding.Deed): ''' Initiates allow (CurveCP handshake) transaction with master FloScript: do salt raet road stack allower at enter ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), stack=salt.utils.stringutils.to_str('stack'), ) def action(self, **kwa): ''' Receive any udp packets on server socket and put in rxes Send any packets in txes ''' stack = self.stack.value if stack and isinstance(stack, RoadStack): for remote in stack.remotes.values(): if remote.kind == kinds.applKinds.master: stack.allow(uid=remote.uid, timeout=0.0) class SaltRaetRoadStackAllowed(ioflo.base.deeding.Deed): ''' Updates status with .allowed of zeroth remote estate (master) FloScript: do salt raet road stack allowed go next if allowed in .salt.road.manor.status ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), stack=salt.utils.stringutils.to_str('stack'), status=odict(ipath=salt.utils.stringutils.to_str('status'), ival=odict(joined=False, allowed=False, alived=False, rejected=False, idle=False, ))) def action(self, **kwa): ''' Update .status share ''' stack = self.stack.value allowed = False if stack and isinstance(stack, RoadStack): if stack.remotes: allowed = any([remote.allowed for remote in list(stack.remotes.values()) if remote.kind == kinds.applKinds.master]) self.status.update(allowed=allowed) class SaltRaetRoadStackManager(ioflo.base.deeding.Deed): ''' Runs the manage method of RoadStack FloScript: do salt raet road stack manager ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), stack=salt.utils.stringutils.to_str('stack'), alloweds={'ipath': salt.utils.stringutils.to_str('.salt.var.presence.alloweds'), 'ival': odict()}, aliveds={'ipath': salt.utils.stringutils.to_str('.salt.var.presence.aliveds'), 'ival': odict()}, reapeds={'ipath': salt.utils.stringutils.to_str('.salt.var.presence.reapeds'), 'ival': odict()}, availables={'ipath': salt.utils.stringutils.to_str('.salt.var.presence.availables'), 'ival': set()}, changeds={'ipath': salt.utils.stringutils.to_str('.salt.var.presence.changeds'), 'ival': odict(plus=set(), minus=set())}, event=salt.utils.stringutils.to_str('.salt.event.events'),) def _fire_events(self): stack = self.stack.value if self.changeds.data.plus or self.changeds.data.minus: # fire presence change event data = {'new': list(self.changeds.data.plus), 'lost': list(self.changeds.data.minus)} tag = tagify('change', 'presence') route = {'dst': (None, None, 'event_fire'), 'src': (None, stack.local.name, None)} msg = {'route': route, 'tag': tag, 'data': data} self.event.value.append(msg) # fire presence present event data = {'present': list(self.aliveds.value)} tag = tagify('present', 'presence') route = {'dst': (None, None, 'event_fire'), 'src': (None, stack.local.name, None)} msg = {'route': route, 'tag': tag, 'data': data} self.event.value.append(msg) def action(self, **kwa): ''' Manage the presence of any remotes availables is set of names of alive remotes which are also allowed changeds is is share with two fields: plus is set of names of newly available remotes minus is set of names of newly unavailable remotes alloweds is dict of allowed remotes keyed by name aliveds is dict of alived remotes keyed by name reapeds is dict of reaped remotes keyed by name ''' stack = self.stack.value if stack and isinstance(stack, RoadStack): stack.manage(cascade=True) # make copies self.availables.value = set(self.stack.value.availables) self.changeds.update(plus=set(self.stack.value.changeds['plus'])) self.changeds.update(minus=set(self.stack.value.changeds['minus'])) self.alloweds.value = odict(self.stack.value.alloweds) self.aliveds.value = odict(self.stack.value.aliveds) self.reapeds.value = odict(self.stack.value.reapeds) console.concise(" Manage {0}.\nAvailables: {1}\nChangeds:\nPlus: {2}\n" "Minus: {3}\nAlloweds: {4}\nAliveds: {5}\nReapeds: {6}\n".format( stack.name, self.availables.value, self.changeds.data.plus, self.changeds.data.minus, self.alloweds.value, self.aliveds.value, self.reapeds.value)) self._fire_events() class SaltRaetRoadStackPrinter(ioflo.base.deeding.Deed): ''' Prints out messages on rxMsgs queue for associated stack FloScript: do raet road stack printer ''' Ioinits = odict( inode=salt.utils.stringutils.to_str('.salt.road.manor.'), rxmsgs=odict(ipath=salt.utils.stringutils.to_str('rxmsgs'), ival=deque()),) def action(self, **kwa): ''' Queue up message ''' rxMsgs = self.rxmsgs.value while rxMsgs: msg, name = rxMsgs.popleft() console.terse("\nReceived....\n{0}\n".format(msg)) class SaltLoadModules(ioflo.base.deeding.Deed): ''' Reload the minion modules FloScript: do salt load modules at enter ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'grains': salt.utils.stringutils.to_str('.salt.grains'), 'utils': salt.utils.stringutils.to_str('.salt.loader.utils'), 'modules': salt.utils.stringutils.to_str('.salt.loader.modules'), 'grain_time': salt.utils.stringutils.to_str('.salt.var.grain_time'), 'module_refresh': salt.utils.stringutils.to_str('.salt.var.module_refresh'), 'returners': salt.utils.stringutils.to_str('.salt.loader.returners'), 'module_executors': salt.utils.stringutils.to_str('.salt.loader.executors')} def _prepare(self): self._load_modules() def action(self): self._load_modules() def _load_modules(self): ''' Return the functions and the returners loaded up from the loader module ''' if self.grain_time.value is None: self.grain_time.value = 0.0 # if this is a *nix system AND modules_max_memory is set, lets enforce # a memory limit on module imports # this feature ONLY works on *nix like OSs (resource module doesn't work on windows) modules_max_memory = False if self.opts.value.get('modules_max_memory', -1) > 0 and HAS_PSUTIL and HAS_RESOURCE: log.debug('modules_max_memory set, enforcing a maximum of %s', self.opts.value['modules_max_memory']) modules_max_memory = True old_mem_limit = resource.getrlimit(resource.RLIMIT_AS) rss, vms = psutil.Process(os.getpid()).memory_info()[:2] mem_limit = rss + vms + self.opts.value['modules_max_memory'] resource.setrlimit(resource.RLIMIT_AS, (mem_limit, mem_limit)) elif self.opts.value.get('modules_max_memory', -1) > 0: if not HAS_PSUTIL: log.error('Unable to enforce modules_max_memory because psutil is missing') if not HAS_RESOURCE: log.error('Unable to enforce modules_max_memory because resource is missing') if time.time() - self.grain_time.value > 300.0 or self.module_refresh.value: self.opts.value['grains'] = salt.loader.grains(self.opts.value) self.grain_time.value = time.time() self.grains.value = self.opts.value['grains'] self.utils.value = salt.loader.utils(self.opts.value) self.modules.value = salt.loader.minion_mods(self.opts.value, utils=self.utils.value) self.returners.value = salt.loader.returners(self.opts.value, self.modules.value) self.module_executors.value = salt.loader.executors(self.opts.value, self.modules.value) self.utils.value.clear() self.modules.value.clear() self.returners.value.clear() self.module_executors.value.clear() # we're done, reset the limits! if modules_max_memory is True: resource.setrlimit(resource.RLIMIT_AS, old_mem_limit) self.module_refresh.value = False class SaltLoadPillar(ioflo.base.deeding.Deed): ''' Load up the initial pillar for the minion do salt load pillar ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'pillar': salt.utils.stringutils.to_str('.salt.pillar'), 'grains': salt.utils.stringutils.to_str('.salt.grains'), 'modules': salt.utils.stringutils.to_str('.salt.loader.modules'), 'pillar_refresh': salt.utils.stringutils.to_str('.salt.var.pillar_refresh'), 'road_stack': salt.utils.stringutils.to_str('.salt.road.manor.stack'), 'master_estate_name': salt.utils.stringutils.to_str('.salt.track.master_estate_name') } def action(self): ''' Initial pillar ''' # default master is the first remote that is allowed available_masters = [remote for remote in list(self.road_stack.value.remotes.values()) if remote.allowed] while not available_masters: available_masters = [remote for remote in self.road_stack.value.remotes.values() if remote.allowed] time.sleep(0.1) random_master = self.opts.value.get('random_master') if random_master: master = available_masters[random.randint(0, len(available_masters) - 1)] else: master = available_masters[0] self.master_estate_name.value = master.name route = {'src': (self.road_stack.value.local.name, None, None), 'dst': (master.name, None, 'remote_cmd')} load = {'id': self.opts.value['id'], 'grains': self.grains.value, 'saltenv': self.opts.value['saltenv'], 'ver': '2', 'cmd': '_pillar'} self.road_stack.value.transmit({'route': route, 'load': load}, uid=master.uid) self.road_stack.value.serviceAll() while True: time.sleep(0.1) while self.road_stack.value.rxMsgs: msg, sender = self.road_stack.value.rxMsgs.popleft() self.pillar.value = msg.get('return', {}) if self.pillar.value is None: continue self.opts.value['pillar'] = self.pillar.value self.pillar_refresh.value = False return self.road_stack.value.serviceAll() class SaltSchedule(ioflo.base.deeding.Deed): ''' Evaluates the schedule FloScript: do salt schedule ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'grains': salt.utils.stringutils.to_str('.salt.grains'), 'utils': salt.utils.stringutils.to_str('.salt.loader.utils'), 'modules': salt.utils.stringutils.to_str('.salt.loader.modules'), 'returners': salt.utils.stringutils.to_str('.salt.loader.returners')} def _prepare(self): ''' Map opts and make the schedule object ''' self.utils.value = salt.loader.utils(self.opts.value) self.modules.value = salt.loader.minion_mods(self.opts.value, utils=self.utils.value) self.returners.value = salt.loader.returners(self.opts.value, self.modules.value) self.schedule = salt.utils.schedule.Schedule( self.opts.value, self.modules.value, self.returners.value) def action(self): ''' Eval the schedule ''' self.schedule.eval() class SaltRaetManorLaneSetup(ioflo.base.deeding.Deed): ''' Only intended to be called once at the top of the manor house Sets up the LaneStack for the main yard FloScript: do salt raet manor lane setup at enter ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'event_yards': salt.utils.stringutils.to_str('.salt.event.yards'), 'local_cmd': salt.utils.stringutils.to_str('.salt.var.local_cmd'), 'remote_cmd': salt.utils.stringutils.to_str('.salt.var.remote_cmd'), 'publish': salt.utils.stringutils.to_str('.salt.var.publish'), 'fun': salt.utils.stringutils.to_str('.salt.var.fun'), 'worker_verify': salt.utils.stringutils.to_str('.salt.var.worker_verify'), 'event': salt.utils.stringutils.to_str('.salt.event.events'), 'event_req': salt.utils.stringutils.to_str('.salt.event.event_req'), 'presence_req': salt.utils.stringutils.to_str('.salt.presence.event_req'), 'stats_req': salt.utils.stringutils.to_str('.salt.stats.event_req'), 'workers': salt.utils.stringutils.to_str('.salt.track.workers'), 'inode': salt.utils.stringutils.to_str('.salt.lane.manor.'), 'stack': salt.utils.stringutils.to_str('stack'), 'local': {'ipath': salt.utils.stringutils.to_str('local'), 'ival': {'lanename': 'master', 'bufcnt': 100}}, } def _prepare(self): ''' Set up required objects and queues ''' pass def action(self): ''' Run once at enter ''' kind = self.opts.value['__role'] if kind not in kinds.APPL_KINDS: emsg = ("Invalid application kind = '{0}' for manor lane.".format(kind)) log.error(emsg + "\n") raise ValueError(emsg) if kind in [kinds.APPL_KIND_NAMES[kinds.applKinds.master], kinds.APPL_KIND_NAMES[kinds.applKinds.syndic]]: lanename = 'master' elif kind in [kinds.APPL_KIND_NAMES[kinds.applKinds.minion], kinds.APPL_KIND_NAMES[kinds.applKinds.caller], ]: role = self.opts.value.get('id', '') if not role: emsg = ("Missing role required to setup manor Lane.") log.error(emsg + "\n") raise ValueError(emsg) lanename = "{0}_{1}".format(role, kind) else: emsg = ("Unsupported application kind = '{0}' for manor Lane.".format(kind)) log.error(emsg + '\n') raise ValueError(emsg) bufcnt = self.opts.value.get('raet_lane_bufcnt', self.local.data.bufcnt) name = 'manor' self.stack.value = LaneStack( name=name, lanename=lanename, sockdirpath=self.opts.value['sock_dir'], bufcnt=bufcnt) self.stack.value.Pk = raeting.PackKind.pack.value self.event_yards.value = set() self.local_cmd.value = deque() self.remote_cmd.value = deque() self.fun.value = deque() self.event.value = deque() self.event_req.value = deque() self.presence_req.value = deque() self.stats_req.value = deque() self.publish.value = deque() self.worker_verify.value = salt.utils.stringutils.random() if self.opts.value.get('worker_threads'): worker_seed = [] for index in range(self.opts.value['worker_threads']): worker_seed.append('worker{0}'.format(index + 1)) self.workers.value = itertools.cycle(worker_seed) class SaltRaetLaneStackCloser(ioflo.base.deeding.Deed): # pylint: disable=W0232 ''' Closes lane stack server socket connection FloScript: do raet lane stack closer at exit ''' Ioinits = odict( inode='.salt.lane.manor', stack='stack',) def action(self, **kwa): ''' Close uxd socket ''' if self.stack.value and isinstance(self.stack.value, LaneStack): self.stack.value.server.close() class SaltRaetRoadStackService(ioflo.base.deeding.Deed): ''' Process the udp traffic FloScript: do rx ''' Ioinits = { 'road_stack': salt.utils.stringutils.to_str('.salt.road.manor.stack'), } def action(self): ''' Process inboud queues ''' self.road_stack.value.serviceAll() class SaltRaetRoadStackServiceRx(ioflo.base.deeding.Deed): ''' Process the inbound Road traffic FloScript: do salt raet road stack service rx ''' Ioinits = { 'road_stack': salt.utils.stringutils.to_str('.salt.road.manor.stack'), } def action(self): ''' Process inboud queues ''' self.road_stack.value.serviceAllRx() class SaltRaetRoadStackServiceTx(ioflo.base.deeding.Deed): ''' Process the outbound Road traffic FloScript: do salt raet road stack service tx ''' # Yes, this class is identical to RX, this is because we still need to # separate out rx and tx in raet itself Ioinits = { 'road_stack': salt.utils.stringutils.to_str('.salt.road.manor.stack'), } def action(self): ''' Process inbound queues ''' self.road_stack.value.serviceAllTx() class SaltRaetLaneStackServiceRx(ioflo.base.deeding.Deed): ''' Process the inbound Lane traffic FloScript: do salt raet lane stack service rx ''' Ioinits = { 'lane_stack': salt.utils.stringutils.to_str('.salt.lane.manor.stack'), } def action(self): ''' Process inboud queues ''' self.lane_stack.value.serviceAllRx() class SaltRaetLaneStackServiceTx(ioflo.base.deeding.Deed): ''' Process the outbound Lane traffic FloScript: do salt raet lane stack service tx ''' # Yes, this class is identical to RX, this is because we still need to # separate out rx and tx in raet itself Ioinits = { 'lane_stack': salt.utils.stringutils.to_str('.salt.lane.manor.stack'), } def action(self): ''' Process outbound queues ''' self.lane_stack.value.serviceAllTx() class SaltRaetRouter(ioflo.base.deeding.Deed): ''' Routes the communication in and out of Road and Lane connections This is a base class ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'local_cmd': salt.utils.stringutils.to_str('.salt.var.local_cmd'), 'remote_cmd': salt.utils.stringutils.to_str('.salt.var.remote_cmd'), 'publish': salt.utils.stringutils.to_str('.salt.var.publish'), 'fun': salt.utils.stringutils.to_str('.salt.var.fun'), 'event': salt.utils.stringutils.to_str('.salt.event.events'), 'event_req': salt.utils.stringutils.to_str('.salt.event.event_req'), # deque 'presence_req': salt.utils.stringutils.to_str('.salt.presence.event_req'), # deque 'stats_req': salt.utils.stringutils.to_str('.salt.stats.event_req'), # deque 'availables': salt.utils.stringutils.to_str('.salt.var.presence.availables'), # set() 'workers': salt.utils.stringutils.to_str('.salt.track.workers'), 'worker_verify': salt.utils.stringutils.to_str('.salt.var.worker_verify'), 'lane_stack': salt.utils.stringutils.to_str('.salt.lane.manor.stack'), 'road_stack': salt.utils.stringutils.to_str('.salt.road.manor.stack'), 'master_estate_name': salt.utils.stringutils.to_str('.salt.track.master_estate_name'), # requeuing when not yet routable 'laters': {'ipath': salt.utils.stringutils.to_str('.salt.lane.manor.laters'), 'ival': deque()}} def _process_road_rxmsg(self, msg, sender): ''' Send to the right queue msg is the message body dict sender is the unique name of the remote estate that sent the message ''' pass def _process_lane_rxmsg(self, msg, sender): ''' Send uxd messages tot he right queue or forward them to the correct yard etc. msg is message body dict sender is unique name of remote that sent the message ''' pass def _get_master_estate_name(self, clustered=False): ''' Assign and return the name of the estate for the default master or empty if none If the default master is no longer available then selects one of the available masters If clustered is True then use load balancing algorithm to select master ''' opts = self.opts.value master = self.road_stack.value.nameRemotes.get(self.master_estate_name.value) if not master or not master.alived: # select a different master available_masters = [remote for remote in six.Iterator(self.road_stack.value.remotes) if remote.alived] if available_masters: random_master = opts.get('random_master') if random_master: master = available_masters[random.randint(0, len(available_masters) - 1)] else: master = available_masters[0] else: master = None self.master_estate_name.value = master.name if master else '' return self.master_estate_name.value def _availablize(self, minions): ''' Return set that is intersection of associated minion estates for roles in minions and the set of available minion estates. ''' suffix = '_{0}'.format(kinds.APPL_KIND_NAMES[kinds.applKinds.minion]) return list(set(minions) & set((name.rstrip(suffix) for name in self.availables.value))) def action(self): ''' Process the messages! ''' while self.road_stack.value.rxMsgs: msg, sender = self.road_stack.value.rxMsgs.popleft() self._process_road_rxmsg(msg=msg, sender=sender) while self.laters.value: # process requeued LaneMsgs msg, sender = self.laters.value.popleft() self.lane_stack.value.rxMsgs.append((msg, sender)) while self.lane_stack.value.rxMsgs: msg, sender = self.lane_stack.value.rxMsgs.popleft() self._process_lane_rxmsg(msg=msg, sender=sender) class SaltRaetRouterMaster(SaltRaetRouter): ''' Routes the communication in and out of Road and Lane connections Specific to Master do salt raet router master ''' def _process_road_rxmsg(self, msg, sender): ''' Send to the right queue msg is the message body dict sender is the unique name of the remote estate that sent the message ''' try: s_estate, s_yard, s_share = msg['route']['src'] d_estate, d_yard, d_share = msg['route']['dst'] except (ValueError, IndexError): log.error('Received invalid message: %s', msg) return if s_estate is None: # drop return log.debug( '**** Road Router rxMsg **** id=%s estate=%s yard=%s\nmsg=%s', self.opts.value['id'], self.road_stack.value.local.name, self.lane_stack.value.local.name, msg ) if d_estate is not None and d_estate != self.road_stack.value.local.name: log.error('Road Router Received message for wrong estate: %s', d_estate) return if d_yard is not None: # Meant for another yard, send it off! if d_yard in self.lane_stack.value.nameRemotes: self.lane_stack.value.transmit(msg, self.lane_stack.value.nameRemotes[d_yard].uid) return if d_share is None: # No queue destination! log.error('Received message without share: %s', msg) return elif d_share == 'event_fire': # rebroadcast events from other masters self.event.value.append(msg) #log.debug("\n**** Event Fire \n %s\n", msg) return elif d_share == 'local_cmd': # Refuse local commands over the wire log.error('Received local command remotely! Ignoring: %s', msg) return elif d_share == 'remote_cmd': # Send it to a remote worker if 'load' in msg: role = self.road_stack.value.nameRemotes[sender].role msg['load']['id'] = role # sender # should this be role XXXX self.lane_stack.value.transmit(msg, self.lane_stack.value.fetchUidByName(next(self.workers.value))) def _process_lane_rxmsg(self, msg, sender): ''' Send uxd messages tot he right queue or forward them to the correct yard etc. msg is message body dict sender is unique name of remote that sent the message ''' try: s_estate, s_yard, s_share = msg['route']['src'] d_estate, d_yard, d_share = msg['route']['dst'] except (ValueError, IndexError): log.error('Lane Router Received invalid message: %s', msg) return if s_yard is None: return # drop message if s_estate is None: # substitute local estate s_estate = self.road_stack.value.local.name msg['route']['src'] = (s_estate, s_yard, s_share) log.debug( '**** Lane Router rxMsg **** id=%s estate=%s yard=%s\nmsg=%s', self.opts.value['id'], self.road_stack.value.local.name, self.lane_stack.value.local.name, msg ) if d_estate is None: pass elif d_estate != self.road_stack.value.local.name: # Forward to the correct estate if d_estate in self.road_stack.value.nameRemotes: self.road_stack.value.message(msg, self.road_stack.value.nameRemotes[d_estate].uid) return if d_share == 'pub_ret': # only publish to available minions msg['return']['ret']['minions'] = self._availablize(msg['return']['ret']['minions']) if msg.get('__worker_verify') == self.worker_verify.value: self.publish.value.append(msg) if d_yard is None: pass elif d_yard != self.lane_stack.value.local.name: # Meant for another yard, send it off! if d_yard in self.lane_stack.value.nameRemotes: self.lane_stack.value.transmit(msg, self.lane_stack.value.nameRemotes[d_yard].uid) return if d_share is None: # No queue destination! log.error('Lane Router Received message without share: %s', msg) return elif d_share == 'local_cmd': self.lane_stack.value.transmit(msg, self.lane_stack.value.fetchUidByName(next(self.workers.value))) elif d_share == 'event_req': self.event_req.value.append(msg) #log.debug("\n**** Event Subscribe \n %s\n", msg) elif d_share == 'event_fire': self.event.value.append(msg) #log.debug("\n**** Event Fire \n %s\n", msg) elif d_share == 'presence_req': self.presence_req.value.append(msg) #log.debug("\n**** Presence Request \n %s\n", msg) elif d_share == 'stats_req': self.stats_req.value.append(msg) #log.debug("\n**** Stats Request \n %s\n", msg) class SaltRaetRouterMinion(SaltRaetRouter): ''' Routes the communication in and out of Road and Lane connections Specific to Minions do salt raet router minion ''' def _process_road_rxmsg(self, msg, sender): ''' Send to the right queue msg is the message body dict sender is the unique name of the remote estate that sent the message ''' try: s_estate, s_yard, s_share = msg['route']['src'] d_estate, d_yard, d_share = msg['route']['dst'] except (ValueError, IndexError): log.error('Received invalid message: %s', msg) return if s_estate is None: # drop return log.debug( '**** Road Router rxMsg **** id=%s estate=%s yard=%s\nmsg=%s', self.opts.value['id'], self.road_stack.value.local.name, self.lane_stack.value.local.name, msg ) if d_estate is not None and d_estate != self.road_stack.value.local.name: log.error('Road Router Received message for wrong estate: %s', d_estate) return if d_yard is not None: # Meant for another yard, send it off! if d_yard in self.lane_stack.value.nameRemotes: self.lane_stack.value.transmit(msg, self.lane_stack.value.nameRemotes[d_yard].uid) return return if d_share is None: # No queue destination! log.error('Received message without share: %s', msg) return elif d_share == 'fun': if self.road_stack.value.kind == kinds.applKinds.minion: self.fun.value.append(msg) elif d_share == 'stats_req': self.stats_req.value.append(msg) #log.debug("\n**** Stats Request \n %s\n", msg) def _process_lane_rxmsg(self, msg, sender): ''' Send uxd messages tot he right queue or forward them to the correct yard etc. msg is message body dict sender is unique name of remote that sent the message ''' try: s_estate, s_yard, s_share = msg['route']['src'] d_estate, d_yard, d_share = msg['route']['dst'] except (ValueError, IndexError): log.error('Lane Router Received invalid message: %s', msg) return if s_yard is None: return # drop message if s_estate is None: # substitute local estate s_estate = self.road_stack.value.local.name msg['route']['src'] = (s_estate, s_yard, s_share) log.debug( '**** Lane Router rxMsg **** id=%s estate=%s yard=%s\nmsg=%s', self.opts.value['id'], self.road_stack.value.local.name, self.lane_stack.value.local.name, msg ) if d_estate is None: pass elif d_estate != self.road_stack.value.local.name: # Forward to the correct estate if d_estate in self.road_stack.value.nameRemotes: self.road_stack.value.message(msg, self.road_stack.value.nameRemotes[d_estate].uid) return if d_yard is None: pass elif d_yard != self.lane_stack.value.local.name: # Meant for another yard, send it off! if d_yard in self.lane_stack.value.nameRemotes: self.lane_stack.value.transmit(msg, self.lane_stack.value.nameRemotes[d_yard].uid) return return if d_share is None: # No queue destination! log.error('Lane Router Received message without share: %s', msg) return elif d_share == 'event_req': self.event_req.value.append(msg) #log.debug("\n**** Event Subscribe \n %s\n", msg) elif d_share == 'event_fire': self.event.value.append(msg) #log.debug("\n**** Event Fire \n %s\n", msg) elif d_share == 'remote_cmd': # assume minion to master or salt-call if not self.road_stack.value.remotes: log.error("**** Lane Router: Missing joined master. Unable to route " "remote_cmd. Requeuing") self.laters.value.append((msg, sender)) return d_estate = self._get_master_estate_name(clustered=self.opts.get('cluster_mode', False)) if not d_estate: log.error("**** Lane Router: No available destination estate for 'remote_cmd'." "Unable to route. Requeuing") self.laters.value.append((msg, sender)) return msg['route']['dst'] = (d_estate, d_yard, d_share) log.debug("**** Lane Router: Missing destination estate for 'remote_cmd'. " "Using default route=%s.", msg['route']['dst']) self.road_stack.value.message(msg, self.road_stack.value.nameRemotes[d_estate].uid) def _get_master_estate_name(self, clustered=False): ''' Assign and return the name of the estate for the default master or empty if none If the default master is no longer available then selects one of the available masters ''' opts = self.opts.value master = self.road_stack.value.nameRemotes.get(self.master_estate_name.value) if not master or not master.alived: # select a different master available_masters = [remote for remote in list(self.road_stack.value.remotes.values()) if remote.alived] if available_masters: random_master = opts.get('random_master') if random_master: master = available_masters[random.randint(0, len(available_masters) - 1)] else: master = available_masters[0] else: master = None self.master_estate_name.value = master.name if master else '' return self.master_estate_name.value def _availablize(self, minions): ''' Return set that is intersection of associated minion estates for roles in minions and the set of available minion estates. ''' suffix = '_{0}'.format(kinds.APPL_KIND_NAMES[kinds.applKinds.minion]) return list(set(minions) & set((name.rstrip(suffix) for name in self.availables.value))) class SaltRaetEventer(ioflo.base.deeding.Deed): ''' Fire events! FloScript: do salt raet eventer ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'event_yards': salt.utils.stringutils.to_str('.salt.event.yards'), 'event': salt.utils.stringutils.to_str('.salt.event.events'), 'event_req': salt.utils.stringutils.to_str('.salt.event.event_req'), 'module_refresh': salt.utils.stringutils.to_str('.salt.var.module_refresh'), 'pillar_refresh': salt.utils.stringutils.to_str('.salt.var.pillar_refresh'), 'lane_stack': salt.utils.stringutils.to_str('.salt.lane.manor.stack'), 'road_stack': salt.utils.stringutils.to_str('.salt.road.manor.stack'), 'availables': salt.utils.stringutils.to_str('.salt.var.presence.availables'), } def _register_event_yard(self, msg): ''' register an incoming event request with the requesting yard id ''' self.event_yards.value.add(msg['route']['src'][1]) def _forward_event(self, msg): ''' Forward an event message to all subscribed yards Event message has a route ''' rm_ = [] if msg.get('tag') == 'pillar_refresh': self.pillar_refresh.value = True if msg.get('tag') == 'module_refresh': self.module_refresh.value = True for y_name in self.event_yards.value: if y_name not in self.lane_stack.value.nameRemotes: # subscriber not a remote rm_.append(y_name) continue # drop msg don't publish self.lane_stack.value.transmit(msg, self.lane_stack.value.fetchUidByName(y_name)) self.lane_stack.value.serviceAll() for y_name in rm_: # remove missing subscribers self.event_yards.value.remove(y_name) def action(self): ''' Register event requests Iterate over the registered event yards and fire! ''' while self.event_req.value: # event subscription requests are msg with routes self._register_event_yard( self.event_req.value.popleft() ) while self.event.value: # events are msgs with routes self._forward_event( self.event.value.popleft() ) class SaltRaetEventerMaster(SaltRaetEventer): ''' Fire events! FloScript: do salt raet eventer master ''' def _forward_event(self, msg): ''' Forward an event message to all subscribed yards Event message has a route Also rebroadcast to all masters in cluster ''' super(SaltRaetEventerMaster, self)._forward_event(msg) if self.opts.value.get('cluster_mode'): if msg.get('origin') is None: masters = (self.availables.value & set((remote.name for remote in list(self.road_stack.value.remotes.values()) if remote.kind == kinds.applKinds.master))) for name in masters: remote = self.road_stack.value.nameRemotes[name] msg['origin'] = self.road_stack.value.name s_estate, s_yard, s_share = msg['route']['src'] msg['route']['src'] = (self.road_stack.value.name, s_yard, s_share) msg['route']['dst'] = (remote.name, None, 'event_fire') self.road_stack.value.message(msg, remote.uid) class SaltRaetPresenter(ioflo.base.deeding.Deed): ''' Fire presence events! FloScript: do salt raet presenter ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'presence_req': salt.utils.stringutils.to_str('.salt.presence.event_req'), 'lane_stack': salt.utils.stringutils.to_str('.salt.lane.manor.stack'), 'alloweds': salt.utils.stringutils.to_str('.salt.var.presence.alloweds'), # odict 'aliveds': salt.utils.stringutils.to_str('.salt.var.presence.aliveds'), # odict 'reapeds': salt.utils.stringutils.to_str('.salt.var.presence.reapeds'), # odict 'availables': salt.utils.stringutils.to_str('.salt.var.presence.availables'), # set } def _send_presence(self, msg): ''' Forward an presence message to all subscribed yards Presence message has a route ''' y_name = msg['route']['src'][1] if y_name not in self.lane_stack.value.nameRemotes: # subscriber not a remote pass # drop msg don't answer else: if 'data' in msg and 'state' in msg['data']: state = msg['data']['state'] else: state = None # create answer message if state in [None, 'available', 'present']: present = odict() for name in self.availables.value: minion = self.aliveds.value.get(name, None) present[name] = minion.ha[0] if minion else None data = {'present': present} else: # TODO: update to really return joineds states = {'joined': self.alloweds, 'allowed': self.alloweds, 'alived': self.aliveds, 'reaped': self.reapeds} try: minions = states[state].value except KeyError: # error: wrong/unknown state requested log.error('Lane Router Received invalid message: %s', msg) return result = odict() for name in minions: result[name] = minions[name].ha[0] data = {state: result} tag = tagify('present', 'presence') route = {'dst': (None, None, 'event_fire'), 'src': (None, self.lane_stack.value.local.name, None)} msg = {'route': route, 'tag': tag, 'data': data} self.lane_stack.value.transmit(msg, self.lane_stack.value.fetchUidByName(y_name)) self.lane_stack.value.serviceAll() def action(self): ''' Register presence requests Iterate over the registered presence yards and fire! ''' while self.presence_req.value: # presence are msgs with routes self._send_presence( self.presence_req.value.popleft() ) class SaltRaetStatsEventer(ioflo.base.deeding.Deed): ''' Fire stats events FloScript: do salt raet state eventer ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'stats_req': salt.utils.stringutils.to_str('.salt.stats.event_req'), 'lane_stack': salt.utils.stringutils.to_str('.salt.lane.manor.stack'), 'road_stack': salt.utils.stringutils.to_str('.salt.road.manor.stack'), } def _send_stats(self, msg): ''' Forward a stats message to all subscribed yards Stats message has a route ''' pass def _get_stats(self, tag): if tag == tagify('road', 'stats'): return self.road_stack.value.stats elif tag == tagify('lane', 'stats'): return self.lane_stack.value.stats else: log.error('Missing or invalid tag: %s', tag) return None def action(self): ''' Iterate over the registered stats requests and fire! ''' while self.stats_req.value: # stats are msgs with routes self._send_stats( self.stats_req.value.popleft() ) class SaltRaetStatsEventerMaster(SaltRaetStatsEventer): def _send_stats(self, msg): ''' Forward a stats message to all subscribed yards Stats message has a route ''' y_name = msg['route']['src'][1] if y_name not in self.lane_stack.value.nameRemotes: # subscriber not a remote return # drop msg don't answer stats = self._get_stats(msg.get('tag')) if stats is None: return route = {'dst': (None, None, 'event_fire'), 'src': (None, self.lane_stack.value.local.name, None)} repl = {'route': route, 'tag': msg.get('tag'), 'data': stats} self.lane_stack.value.transmit(repl, self.lane_stack.value.fetchUidByName(y_name)) self.lane_stack.value.serviceAll() class SaltRaetStatsEventerMinion(SaltRaetStatsEventer): def _send_stats(self, msg): ''' Forward a stats message to all subscribed yards Stats message has a route ''' s_estate, s_yard, s_share = msg['route']['src'] if s_estate not in self.road_stack.value.nameRemotes: # subscriber not a remote return # drop msg don't answer stats = self._get_stats(msg.get('tag')) if stats is None: return route = {'dst': (s_estate, s_yard, 'event_fire'), 'src': (self.road_stack.value.name, self.lane_stack.value.name, None)} repl = {'route': route, 'tag': msg.get('tag'), 'data': stats} self.road_stack.value.transmit(repl, self.road_stack.value.fetchUidByName(s_estate)) self.road_stack.value.serviceAll() class SaltRaetPublisher(ioflo.base.deeding.Deed): ''' Publish to the minions FloScript: do salt raet publisher ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'publish': salt.utils.stringutils.to_str('.salt.var.publish'), 'stack': salt.utils.stringutils.to_str('.salt.road.manor.stack'), 'availables': salt.utils.stringutils.to_str('.salt.var.presence.availables'), } def _publish(self, pub_msg): ''' Publish the message out to the targeted minions ''' stack = self.stack.value pub_data = pub_msg['return'] # only publish to available minions by intersecting sets minions = (self.availables.value & set((remote.name for remote in list(stack.remotes.values()) if remote.kind in [kinds.applKinds.minion, kinds.applKinds.syndic]))) for minion in minions: uid = self.stack.value.fetchUidByName(minion) if uid: route = { 'dst': (minion, None, 'fun'), 'src': (self.stack.value.local.name, None, None)} msg = {'route': route, 'pub': pub_data['pub']} self.stack.value.message(msg, uid) def action(self): ''' Pop the publish queue and publish the requests! ''' while self.publish.value: self._publish( self.publish.value.popleft() ) class SaltRaetSetupEngines(ioflo.base.deeding.Deed): ''' Start the engines! ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'proc_mgr': salt.utils.stringutils.to_str('.salt.usr.proc_mgr')} def action(self): ''' Only call once, this will start the engine processes ''' salt.engines.start_engines(self.opts.value, self.proc_mgr.value) class SaltRaetSetupBeacon(ioflo.base.deeding.Deed): ''' Create the Beacon subsystem ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'beacon': salt.utils.stringutils.to_str('.salt.beacon'), 'modules': salt.utils.stringutils.to_str('.salt.loader.modules')} def action(self): ''' Run the beacons ''' self.beacon.value = salt.beacons.Beacon( self.opts.value, self.modules.value) class SaltRaetBeacon(ioflo.base.deeding.Deed): ''' Run the beacons ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'modules': salt.utils.stringutils.to_str('.salt.loader.modules'), 'master_events': salt.utils.stringutils.to_str('.salt.var.master_events'), 'event': salt.utils.stringutils.to_str('.salt.event.events'), 'beacon': salt.utils.stringutils.to_str('.salt.beacon')} def action(self): ''' Run the beacons ''' if 'config.merge' in self.modules.value: b_conf = self.modules.value['config.merge']('beacons') if b_conf: try: events = self.beacon.value.process(b_conf) self.master_events.value.extend(events) self.event.value.extend(events) except Exception: log.error('Error in the beacon system: ', exc_info=True) return [] class SaltRaetMasterEvents(ioflo.base.deeding.Deed): ''' Take the events off the master event que and send them to the master to be fired ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'road_stack': salt.utils.stringutils.to_str('.salt.road.manor.stack'), 'master_events': salt.utils.stringutils.to_str('.salt.var.master_events')} def _prepare(self): self.master_events.value = deque() def action(self): if not self.master_events.value: return events = [] for master in self.road_stack.value.remotes: master_uid = master while self.master_events.value: events.append(self.master_events.value.popleft()) route = {'src': (self.road_stack.value.local.name, None, None), 'dst': (next(list(self.road_stack.value.remotes.values())).name, None, 'remote_cmd')} load = {'id': self.opts.value['id'], 'events': events, 'cmd': '_minion_event'} self.road_stack.value.transmit({'route': route, 'load': load}, uid=master_uid) class SaltRaetSetupMatcher(ioflo.base.deeding.Deed): ''' Make the matcher object ''' Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'), 'modules': salt.utils.stringutils.to_str('.salt.loader.modules'), 'matcher': salt.utils.stringutils.to_str('.salt.matcher')} def action(self): self.matcher.value = salt.minion.Matcher( self.opts.value, self.modules.value)