Adding an iterator-like design pattern to the actor/orchestrator class hierarchy

community
Steve L. Nyemba 8 years ago
parent 43ba8fe1ac
commit 4d238e7a79

@ -16,56 +16,27 @@ import os
import subprocess import subprocess
from monitor import ProcessCounter from monitor import ProcessCounter
from utils.transport import QueueListener, QueueWriter from utils.transport import QueueListener, QueueWriter
class Actor(Thread): class Actor:
@staticmethod def __init__(self,config):
def instance(id,config): self.config = config
pass
def __init__(self,config):
Thread.__init__(self)
self.config = config
self.items = []
self.__id = config['id']
def getIdentifier(self): def getIdentifier(self):
return self.__id return self.__class__.__name__.lower()
def init(self,litems): def init(self,litems):
self.items = litems self.items = litems
def process(self,item): def process(self,item):
pass pass
def isValid(self,item):
return False
def execute(self,cmd): def execute(self,cmd):
stream = None stream = None
try: try:
print self.getIdentifier()
print cmd
handler = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE) handler = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
stream = handler.communicate()[0] stream = handler.communicate()[0]
except Exception,e: except Exception,e:
pass pass
return stream return stream
def callback(self,channel,method,header,stream):
print [self.getIdentifier(),stream]
message = json.loads(stream)
content = message['content']
sender = message['from']
if content.lower() == 'quit' :
channel.close()
print " *** ",self.getIdentifier()
elif content.lower() == 'ping':
self.post(to=sender,content="1")
else:
self.process(content)
self.post(to=sender,content=content)
#message = None
#try:
#message = json.loads(stream)
#except Exception, e:
#pass
#if message is not None:
#if 'id' in message :
#if 'payload' in message:
#self.execute(message['payload']
""" """
Sending a message to a queue with parameters to,from,content Sending a message to a queue with parameters to,from,content
""" """
@ -84,8 +55,8 @@ class Actor(Thread):
pass pass
class Kill(Actor): class Kill(Actor):
def __init__(self,config): def isValid(self,item):
Actor.__init__(self,config) return (item is not None) and (item in self.config)
def process(self,item): def process(self,item):
cmd = "".join(["ps -eo pid,command|grep ",item,'|grep -E "^ {0,1}[0-9]+" -o|xargs kill -9']) cmd = "".join(["ps -eo pid,command|grep ",item,'|grep -E "^ {0,1}[0-9]+" -o|xargs kill -9'])
self.execute(cmd) self.execute(cmd)
@ -95,40 +66,53 @@ class Kill(Actor):
class Start(Actor): class Start(Actor):
def __init__(self,config): def __init__(self,config):
Actor.__init__(self,config) Actor.__init__(self,config)
def process(self,item): def isValid(self,name):
return name in self.config:
def process(self,name):
item = self.config[name]
path = item['path'] path = item['path']
args = item['args'] if 'args' in item else '' args = item['args'] if 'args' in item else ''
cmd = " ".join([path,args]) cmd = " ".join([path,args])
self.execute(cmd) self.execute(cmd)
"""
The orchestrator class is designed to aggregate actions and communicate back to the caller
Mesage passing is structured as follows {from,to,content} The content is designed to be understood by the actor
class Orchestrator(Actor): The orchestrator is implemented using a simple iterator design-pattern
@TODO: action specifications should be provided remotely
"""
class Orchestrator(Actor,Thread):
def __init__(self,config): def __init__(self,config):
Thread.__init__(self)
Actor.__init__(self,config)
self.actors = {} self.actors = {}
for id in config : for id in config['actions'] :
_config_ = config[id] conf = config['actions'][id]
item = Actor.instance(id,config[id]) item = eval("".join([id,"(",json.dumps(conf),")"]))
self.actors[id] = item self.actors[id.lower()] = item
pass
def callback(self,channel,method,header,stream): def callback(self,channel,method,header,stream):
print [self.getIdentifier(),stream]
message = json.loads(stream) message = json.loads(stream)
content = message['content'] content = message['content']
sender = message['from'] sender = message['from']
if content.lower() == 'quit' : to = message['to']
if content.lower() == 'quit' or to == 'quit':
channel.close() channel.close()
print " *** ",self.getIdentifier() print " *** ",self.getIdentifier()
elif content.lower() == 'ping': elif content.lower() == 'ping' or to == 'ping':
self.post(to=sender,content="1") self.post(to=sender,content="1")
else: else:
self.process(content) id = to.lower()
self.post(to=sender,content=content) actor = self.actors[id]
if actor.isValid(content) :
actor.process(content)
else:
content = {"status":"invalid","content":content}
def process(self,item): self.post(to=sender,content=content)
id = item['cmd']
actor = self.actors[id]
actor.process(item) ;
def run(self): def run(self):
info = {} info = {}
@ -139,7 +123,7 @@ class Orchestrator(Actor):
qlistener = QueueListener(qid=qid,uid=uid,host=host) qlistener = QueueListener(qid=qid,uid=uid,host=host)
qlistener.callback = self.callback qlistener.callback = self.callback
qlistener.read() qlistener.read()
r = [self.process(item) for item in self.items] #r = [self.process(item) for item in self.items]
""" """
This class is designed to send a message to a given AMQP enpoint This class is designed to send a message to a given AMQP enpoint
@ -150,11 +134,20 @@ class Alert(Actor):
pass pass
config = {
"id":"demo-000",
"key":"[0v8]-247&7!v3","api":"localhost",
"actions":{
"Kill":["firefox"],
"Alert":[]
}
config = {"id":"demo","key":"[0v8]-247&7!v3","api":"localhost"} }
actor = Kill(config) thread = Orchestrator(config)
actor.start() thread.start()
#config = {"id":"demo","key":"[0v8]-247&7!v3","api":"localhost"}
#actor = Kill(config)
#actor.start()
config = {"id":"demo-100","key":"[0v8]-247&7!v3","api":"localhost"} #config = {"id":"demo-100","key":"[0v8]-247&7!v3","api":"localhost"}
actor_1 = Kill(config)
actor_1.start()

Loading…
Cancel
Save