%PDF- %PDF-
| Direktori : /proc/self/root/usr/lib/python2.7/site-packages/salt/daemons/flo/ |
| Current File : //proc/self/root/usr/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)