Synergy enhancements
- serializer.py: improved serialization - manager.py: Managers are now serializable - command.py, shell.py: improved command shell by using the 'tabulate' module - service.py: listManagers, startManager, stopManager and getManagerStatus methods now use the Managers serialization - requirements.txt, test-requirements.txt: 'tabulate' module dependence added - test_synergy.py, test_manager_abstract.py: updated unit tests - setup.cfg: changed entry points Change-Id: I657af749aa3fcb32c27b516c2b9f836c5ba0c690
This commit is contained in:
parent
07c15e9c93
commit
3c33d51dd4
@ -15,3 +15,4 @@ eventlet
|
||||
oslo.config>=2.4.0,<3.0.0
|
||||
oslo.messaging>=2.5.0,<3.0.0
|
||||
python-dateutil
|
||||
tabulate>=0.7.2,<0.8.0
|
||||
|
@ -26,13 +26,10 @@ scripts =
|
||||
|
||||
[entry_points]
|
||||
synergy.managers =
|
||||
timer = synergy.examples.timer_manager:TimerManager
|
||||
TimerManager = synergy.examples.timer_manager:TimerManager
|
||||
|
||||
synergy.commands =
|
||||
list = synergy.client.command:List
|
||||
status = synergy.client.command:Status
|
||||
start = synergy.client.command:Start
|
||||
stop = synergy.client.command:Stop
|
||||
manager = synergy.client.command:ManagerCommand
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
@ -1,6 +1,10 @@
|
||||
import json
|
||||
import requests
|
||||
|
||||
from synergy.common import utils
|
||||
from tabulate import tabulate
|
||||
|
||||
|
||||
__author__ = "Lisa Zangrando"
|
||||
__email__ = "lisa.zangrando[AT]pd.infn.it"
|
||||
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
|
||||
@ -31,10 +35,21 @@ class HTTPCommand(object):
|
||||
def configureParser(self, subparser):
|
||||
raise NotImplementedError("not implemented!")
|
||||
|
||||
def log(self):
|
||||
raise NotImplementedError("not implemented!")
|
||||
def objectHookHandler(self, parsed_dict):
|
||||
if "synergy_object" in parsed_dict:
|
||||
synergy_object = parsed_dict["synergy_object"]
|
||||
try:
|
||||
objClass = utils.import_class(synergy_object["name"])
|
||||
|
||||
def sendRequest(self, synergy_url, payload=None):
|
||||
objInstance = objClass()
|
||||
return objInstance.deserialize(parsed_dict)
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
raise ex
|
||||
else:
|
||||
return parsed_dict
|
||||
|
||||
def execute(self, synergy_url, payload=None):
|
||||
request = requests.get(synergy_url, params=payload)
|
||||
|
||||
if request.status_code != requests.codes.ok:
|
||||
@ -44,180 +59,98 @@ class HTTPCommand(object):
|
||||
|
||||
self.results = request.json()
|
||||
|
||||
return request
|
||||
try:
|
||||
return json.loads(request.text, object_hook=self.objectHookHandler)
|
||||
except Exception:
|
||||
return request.json()
|
||||
|
||||
def getResults(self):
|
||||
return self.results
|
||||
|
||||
|
||||
class List(HTTPCommand):
|
||||
class ManagerCommand(HTTPCommand):
|
||||
|
||||
def __init__(self):
|
||||
super(List, self).__init__("list")
|
||||
super(ManagerCommand, self).__init__("Manager")
|
||||
|
||||
def configureParser(self, subparser):
|
||||
subparser.add_parser("list", add_help=True, help="list the managers")
|
||||
manager_parser = subparser.add_parser('manager')
|
||||
manager_parsers = manager_parser.add_subparsers(dest="command")
|
||||
|
||||
def sendRequest(self, synergy_url, args=None):
|
||||
super(List, self).sendRequest(synergy_url + "/synergy/list")
|
||||
manager_parsers.add_parser(
|
||||
"list", add_help=True, help="list the managers")
|
||||
|
||||
def log(self):
|
||||
results = self.getResults()
|
||||
status_parser = manager_parsers.add_parser(
|
||||
"status", add_help=True, help="show the managers status")
|
||||
|
||||
max_project_id = max(len(max(results, key=len)), len("manager"))
|
||||
separator_str = "-" * (max_project_id + 4) + "\n"
|
||||
format_str = "| {0:%ss} |\n" % (max_project_id)
|
||||
status_parser.add_argument(
|
||||
"manager", nargs='*', help="the managers list")
|
||||
|
||||
msg = separator_str
|
||||
msg += format_str.format("manager")
|
||||
msg += separator_str
|
||||
start_parser = manager_parsers.add_parser(
|
||||
"start", add_help=True, help="start the manager")
|
||||
|
||||
for manager in results:
|
||||
msg += format_str.format(manager)
|
||||
start_parser.add_argument(
|
||||
"manager", nargs='+', help="the managers list")
|
||||
|
||||
msg += separator_str
|
||||
print(msg)
|
||||
stop_parser = manager_parsers.add_parser(
|
||||
"stop", add_help=True, help="stop the manager")
|
||||
|
||||
stop_parser.add_argument(
|
||||
"manager", nargs='+', help="the managers list")
|
||||
|
||||
def execute(self, synergy_url, args=None):
|
||||
table = []
|
||||
headers = []
|
||||
url = synergy_url
|
||||
|
||||
if args.command == "list":
|
||||
headers.append("manager")
|
||||
url += "/synergy/list"
|
||||
|
||||
managers = super(ManagerCommand, self).execute(url)
|
||||
|
||||
for manager in managers:
|
||||
table.append([manager.getName()])
|
||||
else:
|
||||
headers.append("manager")
|
||||
headers.append("status")
|
||||
headers.append("rate (min)")
|
||||
url += "/synergy/" + args.command
|
||||
|
||||
managers = super(ManagerCommand, self).execute(
|
||||
url, {"manager": args.manager})
|
||||
|
||||
if args.command == "status":
|
||||
for manager in managers:
|
||||
table.append([manager.getName(),
|
||||
manager.getStatus(),
|
||||
manager.getRate()])
|
||||
else:
|
||||
headers.append("details")
|
||||
|
||||
for manager in managers:
|
||||
msg = manager.get("message")
|
||||
|
||||
table.append([manager.getName(),
|
||||
manager.getStatus() + " (%s)" % msg,
|
||||
manager.getRate()])
|
||||
|
||||
print(tabulate(table, headers, tablefmt="fancy_grid"))
|
||||
|
||||
|
||||
class Start(HTTPCommand):
|
||||
|
||||
def __init__(self):
|
||||
super(Start, self).__init__("start")
|
||||
|
||||
def configureParser(self, subparser):
|
||||
parser = subparser.add_parser("start",
|
||||
add_help=True,
|
||||
help="start the managers")
|
||||
|
||||
parser.add_argument("manager", help="the manager to be started")
|
||||
|
||||
def sendRequest(self, synergy_url, args):
|
||||
super(Start, self).sendRequest(synergy_url + "/synergy/start",
|
||||
{"manager": args.manager})
|
||||
|
||||
def log(self):
|
||||
results = self.getResults()
|
||||
|
||||
max_manager = max(len(max(results.keys(), key=len)), len("manager"))
|
||||
|
||||
max_status = len("status")
|
||||
max_msg = len("message")
|
||||
|
||||
for result in results.values():
|
||||
max_status = max(len(str(result["status"])), max_status)
|
||||
max_msg = max(len(str(result["message"])), max_msg)
|
||||
|
||||
separator_str = "-" * (max_manager + max_status + max_msg + 10) + "\n"
|
||||
|
||||
format_str = "| {0:%ss} | {1:%ss} | {2:%ss} |\n" % (max_manager,
|
||||
max_status,
|
||||
max_msg)
|
||||
|
||||
msg = separator_str
|
||||
msg += format_str.format("manager", "status", "message")
|
||||
msg += separator_str
|
||||
|
||||
for manager, values in results.items():
|
||||
msg += format_str.format(manager,
|
||||
values["status"],
|
||||
values["message"])
|
||||
|
||||
msg += separator_str
|
||||
print(msg)
|
||||
|
||||
|
||||
class Stop(HTTPCommand):
|
||||
|
||||
def __init__(self):
|
||||
super(Stop, self).__init__("stop")
|
||||
|
||||
def configureParser(self, subparser):
|
||||
parser = subparser.add_parser("stop",
|
||||
add_help=True,
|
||||
help="stop the managers")
|
||||
|
||||
parser.add_argument("manager", help="the manager to be stopped")
|
||||
|
||||
def sendRequest(self, synergy_url, args):
|
||||
super(Stop, self).sendRequest(synergy_url + "/synergy/stop",
|
||||
{"manager": args.manager})
|
||||
|
||||
def log(self):
|
||||
results = self.getResults()
|
||||
|
||||
max_manager = max(len(max(results.keys(), key=len)), len("manager"))
|
||||
max_status = len("status")
|
||||
max_msg = len("message")
|
||||
|
||||
for result in results.values():
|
||||
max_status = max(len(str(result["status"])), max_status)
|
||||
max_msg = max(len(str(result["message"])), max_msg)
|
||||
|
||||
separator_str = "-" * (max_manager + max_status + max_msg + 10) + "\n"
|
||||
format_str = "| {0:%ss} | {1:%ss} | {2:%ss} |\n" % (max_manager,
|
||||
max_status,
|
||||
max_msg)
|
||||
|
||||
msg = separator_str
|
||||
msg += format_str.format("manager", "status", "message")
|
||||
msg += separator_str
|
||||
|
||||
for manager, values in results.items():
|
||||
msg += format_str.format(manager,
|
||||
values["status"],
|
||||
values["message"])
|
||||
|
||||
msg += separator_str
|
||||
print(msg)
|
||||
|
||||
|
||||
class Status(HTTPCommand):
|
||||
|
||||
def __init__(self):
|
||||
super(Status, self).__init__("status")
|
||||
|
||||
def configureParser(self, subparser):
|
||||
parser = subparser.add_parser("status",
|
||||
add_help=True,
|
||||
help="retrieve the manager's status")
|
||||
|
||||
parser.add_argument("manager", nargs='*', help="the managers list")
|
||||
|
||||
def sendRequest(self, synergy_url, args):
|
||||
super(Status, self).sendRequest(synergy_url + "/synergy/status",
|
||||
{"manager": args.manager})
|
||||
|
||||
def log(self):
|
||||
results = self.getResults()
|
||||
|
||||
max_project_id = max(len(max(results.keys(), key=len)), len("manager"))
|
||||
max_value = max(len(max(results.values(), key=len)), len("status"))
|
||||
separator_str = "-" * (max_project_id + max_value + 7) + "\n"
|
||||
format_str = "| {0:%ss} | {1:%ss} |\n" % (max_project_id, max_value)
|
||||
|
||||
msg = separator_str
|
||||
msg += format_str.format("manager", "status")
|
||||
msg += separator_str
|
||||
|
||||
for manager, status in results.items():
|
||||
msg += format_str.format(manager, status)
|
||||
|
||||
msg += separator_str
|
||||
print(msg)
|
||||
|
||||
|
||||
class Execute(HTTPCommand):
|
||||
class ExecuteCommand(HTTPCommand):
|
||||
|
||||
def __init__(self, name):
|
||||
super(Execute, self).__init__(name)
|
||||
super(ExecuteCommand, self).__init__(name)
|
||||
|
||||
def sendRequest(self, synergy_url, manager, command, args=None):
|
||||
def execute(self, synergy_url, manager, command, args=None):
|
||||
if args is None:
|
||||
args = {}
|
||||
|
||||
url = synergy_url + "/synergy/execute"
|
||||
|
||||
payload = {"manager": manager,
|
||||
"command": command,
|
||||
"args": json.dumps(args)}
|
||||
|
||||
super(Execute, self).sendRequest(synergy_url + "/synergy/execute",
|
||||
payload)
|
||||
return super(ExecuteCommand, self).execute(url, payload)
|
||||
|
@ -175,8 +175,8 @@ def main():
|
||||
if command_name not in commands:
|
||||
print("command %r not found!" % command_name)
|
||||
|
||||
commands[command_name].sendRequest(synergy_url, args)
|
||||
commands[command_name].log()
|
||||
commands[command_name].execute(synergy_url, args)
|
||||
# commands[command_name].log()
|
||||
except KeyboardInterrupt as e:
|
||||
print("Shutting down synergyclient")
|
||||
sys.exit(1)
|
||||
|
@ -1,7 +1,9 @@
|
||||
from serializer import SynergyObject
|
||||
from threading import Condition
|
||||
from threading import Event
|
||||
from threading import Thread
|
||||
|
||||
|
||||
__author__ = "Lisa Zangrando"
|
||||
__email__ = "lisa.zangrando[AT]pd.infn.it"
|
||||
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
|
||||
@ -21,18 +23,17 @@ See the License for the specific language governing
|
||||
permissions and limitations under the License."""
|
||||
|
||||
|
||||
class Manager(Thread):
|
||||
class Manager(SynergyObject, Thread):
|
||||
|
||||
def __init__(self, name):
|
||||
def __init__(self, name=None):
|
||||
super(Manager, self).__init__()
|
||||
self.setDaemon(True)
|
||||
self.stop_event = Event()
|
||||
self.config_opts = []
|
||||
self.condition = Condition()
|
||||
self.name = name
|
||||
self.status = "CREATED"
|
||||
self.autostart = False
|
||||
self.rate = -1
|
||||
self.stop_event = Event()
|
||||
self.setDaemon(True)
|
||||
self.setName(name)
|
||||
self.setStatus("CREATED")
|
||||
self.setRate(-1)
|
||||
self.config_opts = []
|
||||
self.paused = True # start out paused
|
||||
self.managers = {}
|
||||
|
||||
@ -61,24 +62,30 @@ class Manager(Thread):
|
||||
if manager.getName() != manager_name:
|
||||
manager.doOnEvent(event_type, *args, **kargs)
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getOptions(self):
|
||||
return self.config_opts
|
||||
|
||||
def getStatus(self):
|
||||
return self.get("status")
|
||||
|
||||
def setStatus(self, status):
|
||||
with self.condition:
|
||||
self.set("status", status)
|
||||
|
||||
self.condition.notifyAll()
|
||||
|
||||
def isAutoStart(self):
|
||||
return self.autostart
|
||||
return self.get("autostart")
|
||||
|
||||
def setAutoStart(self, autostart):
|
||||
self.autostart = autostart
|
||||
self.paused = not self.autostart
|
||||
self.set("autostart", autostart)
|
||||
self.paused = not autostart
|
||||
|
||||
def getRate(self):
|
||||
return self.rate
|
||||
return self.get("rate")
|
||||
|
||||
def setRate(self, rate):
|
||||
self.rate = rate
|
||||
self.set("rate", rate)
|
||||
|
||||
def setup(self):
|
||||
"""Manager initialization
|
||||
@ -93,15 +100,6 @@ class Manager(Thread):
|
||||
def destroy(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def getStatus(self):
|
||||
return self.status
|
||||
|
||||
def setStatus(self, status):
|
||||
with self.condition:
|
||||
self.status = status
|
||||
|
||||
self.condition.notifyAll()
|
||||
|
||||
def stop(self):
|
||||
if self.isAlive():
|
||||
# set event to signal thread to terminate
|
||||
@ -124,13 +122,13 @@ class Manager(Thread):
|
||||
while not self.stop_event.isSet():
|
||||
with self.condition:
|
||||
if self.paused:
|
||||
self.status = "ACTIVE"
|
||||
self.setStatus("ACTIVE")
|
||||
self.condition.wait()
|
||||
else:
|
||||
self.status = "RUNNING"
|
||||
self.setStatus("RUNNING")
|
||||
|
||||
try:
|
||||
self.task()
|
||||
self.condition.wait(self.rate * 60)
|
||||
self.condition.wait(self.getRate() * 60)
|
||||
except Exception as ex:
|
||||
print("task %r: %s" % (self.name, ex))
|
||||
print("task %r: %s" % (self.getName(), ex))
|
||||
|
@ -1,9 +1,5 @@
|
||||
try:
|
||||
import oslo_messaging
|
||||
except ImportError:
|
||||
import oslo.messaging as oslo_messaging
|
||||
|
||||
from synergy.common import context as ctx
|
||||
import datetime
|
||||
from json import JSONEncoder
|
||||
from synergy.common import utils
|
||||
|
||||
|
||||
@ -35,128 +31,136 @@ class SynergyObject(object):
|
||||
necessary "get" classmethod routines as well as "set" object methods
|
||||
as appropriate.
|
||||
"""
|
||||
|
||||
VERSION = "1.0"
|
||||
|
||||
def __init__(self, name=None):
|
||||
def __init__(self):
|
||||
super(SynergyObject, self).__init__()
|
||||
|
||||
self.attributes = {}
|
||||
|
||||
if name:
|
||||
self.attributes["name"] = name
|
||||
def getId(self):
|
||||
return self.get("id")
|
||||
|
||||
def setId(self, id):
|
||||
self.set("id", id)
|
||||
|
||||
def getName(self):
|
||||
return self.attributes["name"]
|
||||
return self.get("name")
|
||||
|
||||
def setName(self, name):
|
||||
self.attributes["name"] = name
|
||||
self.set("name", name)
|
||||
|
||||
def get(self, field=None):
|
||||
def get(self, field):
|
||||
return self.attributes.get(field, None)
|
||||
|
||||
def set(self, field, value):
|
||||
self.attributes[field] = value
|
||||
|
||||
def setContext(self, context):
|
||||
self.context = context
|
||||
if isinstance(value, unicode):
|
||||
self.attributes[field] = str(value)
|
||||
else:
|
||||
self.attributes[field] = value
|
||||
|
||||
def setAttributes(self, attributes):
|
||||
if attributes:
|
||||
self.attributes = attributes
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, context, entity):
|
||||
if "synergy_object.namespace" not in entity:
|
||||
raise Exception("synergy_object.namespace nof defined!")
|
||||
def deserialize(cls, entity):
|
||||
if "synergy_object" not in entity:
|
||||
raise Exception("it seems not a Synergy object!")
|
||||
|
||||
if "synergy_object.name" not in entity:
|
||||
raise Exception("synergy_object.name nof defined!")
|
||||
synergy_object = entity["synergy_object"]
|
||||
|
||||
if "synergy_object.version" not in entity:
|
||||
raise Exception("synergy_object.version nof defined!")
|
||||
if "namespace" not in synergy_object:
|
||||
raise Exception("synergy_object.namespace not defined!")
|
||||
|
||||
if entity["synergy_object.namespace"] != 'synergy':
|
||||
if "name" not in synergy_object:
|
||||
raise Exception("synergy_object.name not defined!")
|
||||
|
||||
if "version" not in synergy_object:
|
||||
raise Exception("synergy_object.version mismatch!")
|
||||
|
||||
if synergy_object["version"] != cls.VERSION:
|
||||
raise Exception("synergy_object.version mis!")
|
||||
|
||||
if synergy_object["namespace"] != "synergy":
|
||||
raise Exception("unsupported object objtype='%s.%s"
|
||||
% (entity["synergy_object.namespace"],
|
||||
entity["synergy_object.name"]))
|
||||
% (synergy_object["namespace"],
|
||||
synergy_object["name"]))
|
||||
|
||||
objName = entity['synergy_object.name']
|
||||
# objVer = entity['synergy_object.version']
|
||||
objClass = utils.import_class(objName)
|
||||
objInstance = None
|
||||
|
||||
# objInstance = objClass(context=context, data=entity)
|
||||
try:
|
||||
objName = synergy_object["name"]
|
||||
# objVer = synergy_object['version']
|
||||
objClass = utils.import_class(objName)
|
||||
objInstance = objClass()
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
raise Exception("error on deserializing the object %r: %s"
|
||||
% (objName, ex))
|
||||
|
||||
objInstance = objClass(name=None)
|
||||
objInstance.setContext(context)
|
||||
objInstance.setAttributes(entity)
|
||||
del entity["synergy_object"]
|
||||
|
||||
for key, value in entity.items():
|
||||
if isinstance(value, dict):
|
||||
if "synergy_object" in value:
|
||||
objInstance.set(key, SynergyObject.deserialize(value))
|
||||
else:
|
||||
objInstance.set(key, value)
|
||||
elif isinstance(value, list):
|
||||
l = []
|
||||
|
||||
objInstance.set(key, l)
|
||||
|
||||
for item in value:
|
||||
if isinstance(item, dict) and "synergy_object" in item:
|
||||
l.append(SynergyObject.deserialize(item))
|
||||
else:
|
||||
l.append(item)
|
||||
else:
|
||||
objInstance.set(key, value)
|
||||
|
||||
return objInstance
|
||||
|
||||
def serialize(self):
|
||||
name = self.__class__.__module__ + "." + self.__class__.__name__
|
||||
self.attributes['synergy_object.name'] = name
|
||||
self.attributes['synergy_object.version'] = self.VERSION
|
||||
self.attributes['synergy_object.namespace'] = 'synergy'
|
||||
|
||||
return self.attributes
|
||||
"""
|
||||
def log(self):
|
||||
result = {"synergy_object": {}}
|
||||
result["synergy_object"]["name"] = name
|
||||
result["synergy_object"]["version"] = self.VERSION
|
||||
result["synergy_object"]["namespace"] = "synergy"
|
||||
|
||||
for key, value in self.attributes.items():
|
||||
LOG.info("%s = %s" % (key, value))
|
||||
"""
|
||||
if isinstance(value, SynergyObject):
|
||||
result[key] = value.serialize()
|
||||
elif isinstance(value, dict):
|
||||
result[key] = {}
|
||||
|
||||
for k, v in value.items():
|
||||
if isinstance(v, SynergyObject):
|
||||
result[key][k] = v.serialize()
|
||||
else:
|
||||
result[key][k] = v
|
||||
elif isinstance(value, list):
|
||||
result[key] = []
|
||||
|
||||
class SynergySerializer(oslo_messaging.Serializer):
|
||||
def __init__(self):
|
||||
super(SynergySerializer, self).__init__()
|
||||
|
||||
def serialize_entity(self, context, entity):
|
||||
if not entity:
|
||||
return entity
|
||||
|
||||
if isinstance(entity, SynergyObject):
|
||||
entity = entity.serialize()
|
||||
elif isinstance(entity, dict):
|
||||
result = {}
|
||||
|
||||
for key, value in entity.items():
|
||||
result[key] = self.serialize_entity(context, value)
|
||||
|
||||
entity = result
|
||||
|
||||
return entity
|
||||
|
||||
def deserialize_entity(self, context, entity):
|
||||
if isinstance(entity, dict):
|
||||
if 'synergy_object.name' in entity:
|
||||
entity = SynergyObject.deserialize(context, entity)
|
||||
for item in value:
|
||||
if isinstance(item, SynergyObject):
|
||||
result[key].append(item.serialize())
|
||||
else:
|
||||
result[key].append(item)
|
||||
elif isinstance(value, datetime.datetime):
|
||||
result[key] = value.isoformat()
|
||||
else:
|
||||
result = {}
|
||||
result[key] = value
|
||||
|
||||
for key, value in entity.items():
|
||||
result[key] = self.deserialize_entity(context, value)
|
||||
|
||||
entity = result
|
||||
|
||||
return entity
|
||||
|
||||
def serialize_context(self, context):
|
||||
return context.toDict()
|
||||
|
||||
def deserialize_context(self, context):
|
||||
return ctx.RequestContext.fromDict(context)
|
||||
return result
|
||||
|
||||
|
||||
class RequestContextSerializer(oslo_messaging.Serializer):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def serialize_entity(self, context, entity):
|
||||
return entity
|
||||
|
||||
def deserialize_entity(self, context, entity):
|
||||
return entity
|
||||
|
||||
def serialize_context(self, context):
|
||||
return context.toDict()
|
||||
|
||||
def deserialize_context(self, context):
|
||||
return ctx.RequestContext.fromDict(context)
|
||||
class SynergyEncoder(JSONEncoder):
|
||||
def default(self, obj):
|
||||
if isinstance(obj, SynergyObject):
|
||||
return obj.serialize()
|
||||
else:
|
||||
return JSONEncoder.default(self, obj)
|
||||
|
@ -15,8 +15,11 @@ except ImportError:
|
||||
from oslo.config import cfg
|
||||
|
||||
from synergy.common import config
|
||||
from synergy.common import service
|
||||
from synergy.common import wsgi
|
||||
from synergy.common.manager import Manager
|
||||
from synergy.common.serializer import SynergyEncoder
|
||||
from synergy.common.service import Service
|
||||
from synergy.common.wsgi import Server
|
||||
|
||||
|
||||
__author__ = "Lisa Zangrando"
|
||||
__email__ = "lisa.zangrando[AT]pd.infn.it"
|
||||
@ -76,7 +79,7 @@ def setLogger(name):
|
||||
logger.addHandler(handler)
|
||||
|
||||
|
||||
class Synergy(service.Service):
|
||||
class Synergy(Service):
|
||||
"""Service object for binaries running on hosts.
|
||||
|
||||
A service takes a manager and enables rpc by listening to queues based
|
||||
@ -98,8 +101,7 @@ class Synergy(service.Service):
|
||||
manager_class = entry.load()
|
||||
|
||||
manager_obj = manager_class(*args, **kwargs)
|
||||
LOG.info("manager instance %r created!", entry.name)
|
||||
|
||||
manager_obj.setName(entry.name)
|
||||
manager_obj.setAutoStart(CONF.get(entry.name).autostart)
|
||||
manager_obj.setRate(CONF.get(entry.name).rate)
|
||||
|
||||
@ -137,14 +139,18 @@ class Synergy(service.Service):
|
||||
result = []
|
||||
|
||||
for name, manager in self.managers.items():
|
||||
result.append(name)
|
||||
m = Manager(name)
|
||||
m.setStatus(manager.getStatus())
|
||||
m.setRate(manager.getRate())
|
||||
|
||||
result.append(m)
|
||||
|
||||
start_response("200 OK", [("Content-Type", "text/html")])
|
||||
return ["%s" % json.dumps(result)]
|
||||
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
|
||||
|
||||
def getManagerStatus(self, environ, start_response):
|
||||
manager_list = None
|
||||
result = {}
|
||||
result = []
|
||||
|
||||
query = environ.get("QUERY_STRING", None)
|
||||
|
||||
@ -165,14 +171,20 @@ class Synergy(service.Service):
|
||||
manager_name = escape(manager_name)
|
||||
|
||||
if manager_name in self.managers:
|
||||
result[manager_name] = self.managers[manager_name].getStatus()
|
||||
manager = self.managers[manager_name]
|
||||
|
||||
m = Manager(manager_name)
|
||||
m.setStatus(manager.getStatus())
|
||||
m.setRate(manager.getRate())
|
||||
|
||||
result.append(m)
|
||||
|
||||
if len(manager_list) == 1 and len(result) == 0:
|
||||
start_response("404 NOT FOUND", [("Content-Type", "text/plain")])
|
||||
return ["manager %r not found!" % manager_list[0]]
|
||||
|
||||
start_response("200 OK", [("Content-Type", "text/html")])
|
||||
return ["%s" % json.dumps(result)]
|
||||
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
|
||||
|
||||
def executeCommand(self, environ, start_response):
|
||||
manager_name = None
|
||||
@ -215,16 +227,8 @@ class Synergy(service.Service):
|
||||
try:
|
||||
result = manager.execute(command=command, **manager_args)
|
||||
|
||||
if not isinstance(result, dict):
|
||||
try:
|
||||
result = result.toDict()
|
||||
except Exception:
|
||||
result = result.__dict__
|
||||
|
||||
LOG.debug("execute command: result=%s" % result)
|
||||
|
||||
start_response("200 OK", [("Content-Type", "text/html")])
|
||||
return ["%s" % json.dumps(result)]
|
||||
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
|
||||
except Exception as ex:
|
||||
LOG.debug("execute command: error=%s" % ex)
|
||||
start_response("500 INTERNAL SERVER ERROR",
|
||||
@ -233,7 +237,7 @@ class Synergy(service.Service):
|
||||
|
||||
def startManager(self, environ, start_response):
|
||||
manager_list = None
|
||||
result = {}
|
||||
result = []
|
||||
|
||||
query = environ.get("QUERY_STRING", None)
|
||||
|
||||
@ -258,9 +262,11 @@ class Synergy(service.Service):
|
||||
if manager_name not in self.managers:
|
||||
continue
|
||||
|
||||
result[manager_name] = {}
|
||||
|
||||
manager = self.managers[manager_name]
|
||||
m = Manager(manager_name)
|
||||
m.setRate(manager.getRate())
|
||||
|
||||
result.append(m)
|
||||
|
||||
if manager.getStatus() == "ACTIVE":
|
||||
LOG.info("starting the %r manager" % (manager_name))
|
||||
@ -270,25 +276,25 @@ class Synergy(service.Service):
|
||||
LOG.info("%r manager started! (rate=%s min)"
|
||||
% (manager_name, manager.getRate()))
|
||||
|
||||
result[manager_name]["status"] = "RUNNING"
|
||||
result[manager_name]["message"] = "started successfully"
|
||||
m.setStatus("RUNNING")
|
||||
m.set("message", "started successfully")
|
||||
elif manager.getStatus() == "RUNNING":
|
||||
result[manager_name]["status"] = "RUNNING"
|
||||
result[manager_name]["message"] = "WARN: already started"
|
||||
m.setStatus("RUNNING")
|
||||
m.set("message", "WARN: already started")
|
||||
elif manager.getStatus() == "ERROR":
|
||||
result[manager_name]["status"] = "ERROR"
|
||||
result[manager_name]["message"] = "wrong state"
|
||||
m.setStatus("ERROR")
|
||||
m.set("message", "wrong state")
|
||||
|
||||
if len(manager_list) == 1 and len(result) == 0:
|
||||
start_response("404 NOT FOUND", [("Content-Type", "text/plain")])
|
||||
return ["manager %r not found!" % manager_list[0]]
|
||||
|
||||
start_response("200 OK", [("Content-Type", "text/html")])
|
||||
return ["%s" % json.dumps(result)]
|
||||
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
|
||||
|
||||
def stopManager(self, environ, start_response):
|
||||
manager_list = None
|
||||
result = {}
|
||||
result = []
|
||||
|
||||
query = environ.get("QUERY_STRING", None)
|
||||
|
||||
@ -313,10 +319,13 @@ class Synergy(service.Service):
|
||||
if manager_name not in self.managers:
|
||||
continue
|
||||
|
||||
result[manager_name] = {}
|
||||
|
||||
manager = self.managers[manager_name]
|
||||
|
||||
m = Manager(manager_name)
|
||||
m.setRate(manager.getRate())
|
||||
|
||||
result.append(m)
|
||||
|
||||
if manager.getStatus() == "RUNNING":
|
||||
LOG.info("stopping the %r manager" % (manager_name))
|
||||
|
||||
@ -324,21 +333,21 @@ class Synergy(service.Service):
|
||||
|
||||
LOG.info("%r manager stopped!" % (manager_name))
|
||||
|
||||
result[manager_name]["status"] = "ACTIVE"
|
||||
result[manager_name]["message"] = "stopped successfully"
|
||||
m.setStatus("ACTIVE")
|
||||
m.set("message", "stopped successfully")
|
||||
elif manager.getStatus() == "ACTIVE":
|
||||
result[manager_name]["status"] = "ACTIVE"
|
||||
result[manager_name]["message"] = "WARN: already stopped"
|
||||
m.setStatus("ACTIVE")
|
||||
m.set("message", "WARN: already stopped")
|
||||
elif manager.getStatus() == "ERROR":
|
||||
result[manager_name]["status"] = "ERROR"
|
||||
result[manager_name]["message"] = "wrong state"
|
||||
m.setStatus("ERROR")
|
||||
m.set("message", "wrong state")
|
||||
|
||||
if len(manager_list) == 1 and len(result) == 0:
|
||||
start_response("404 NOT FOUND", [("Content-Type", "text/plain")])
|
||||
return ["manager %r not found!" % manager_list[0]]
|
||||
|
||||
start_response("200 OK", [("Content-Type", "text/html")])
|
||||
return ["%s" % json.dumps(result)]
|
||||
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
|
||||
|
||||
def start(self):
|
||||
self.model_disconnected = False
|
||||
@ -357,7 +366,7 @@ class Synergy(service.Service):
|
||||
manager.setStatus("ERROR")
|
||||
raise ex
|
||||
|
||||
self.wsgi_server = wsgi.Server(
|
||||
self.wsgi_server = Server(
|
||||
name="WSGI server",
|
||||
host_name=CONF.WSGI.host,
|
||||
host_port=CONF.WSGI.port,
|
||||
|
@ -23,6 +23,7 @@ import sys
|
||||
import time
|
||||
|
||||
from mock import Mock
|
||||
from synergy.common import utils
|
||||
from synergy.service import Synergy
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
@ -47,6 +48,21 @@ def getLogger(name):
|
||||
return logger
|
||||
|
||||
|
||||
def objectHookHandler(parsed_dict):
|
||||
if "synergy_object" in parsed_dict:
|
||||
synergy_object = parsed_dict["synergy_object"]
|
||||
try:
|
||||
objClass = utils.import_class(synergy_object["name"])
|
||||
|
||||
objInstance = objClass()
|
||||
return objInstance.deserialize(parsed_dict)
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
raise ex
|
||||
else:
|
||||
return parsed_dict
|
||||
|
||||
|
||||
class SynergyTests(unittest.TestCase):
|
||||
|
||||
@mock.patch('synergy.service.LOG', LOG)
|
||||
@ -66,53 +82,66 @@ class SynergyTests(unittest.TestCase):
|
||||
start_response = Mock()
|
||||
result = self.synergy.listManagers(environ={},
|
||||
start_response=start_response)
|
||||
result = json.loads(result[0])
|
||||
|
||||
self.assertEqual(result, ["TimerManager"])
|
||||
result = json.loads(result[0], object_hook=objectHookHandler)
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assertEqual(result[0].getName(), "TimerManager")
|
||||
|
||||
@mock.patch('synergy.service.LOG', LOG)
|
||||
def test_getManagerStatus(self):
|
||||
start_response = Mock()
|
||||
result = self.synergy.getManagerStatus(environ={},
|
||||
start_response=start_response)
|
||||
result = json.loads(result[0])
|
||||
|
||||
self.assertEqual(result, {'TimerManager': 'ACTIVE'})
|
||||
result = json.loads(result[0], object_hook=objectHookHandler)
|
||||
|
||||
self.assertEqual(result[0].getStatus(), 'ACTIVE')
|
||||
|
||||
@mock.patch('synergy.service.LOG', LOG)
|
||||
def test_startManager(self):
|
||||
environ = {'QUERY_STRING': 'manager=TimerManager'}
|
||||
start_response = Mock()
|
||||
environ = {'QUERY_STRING': 'manager=NONE'}
|
||||
|
||||
result = self.synergy.startManager(environ, start_response)
|
||||
result = json.loads(result[0])
|
||||
|
||||
self.assertEqual(result, {'TimerManager': {
|
||||
'message': 'started successfully', 'status': 'RUNNING'}})
|
||||
self.assertEqual(result[0], "manager 'NONE' not found!")
|
||||
|
||||
environ = {'QUERY_STRING': 'manager=TimerManager'}
|
||||
|
||||
result = self.synergy.startManager(environ, start_response)
|
||||
result = json.loads(result[0], object_hook=objectHookHandler)
|
||||
|
||||
self.assertEqual(result[0].getStatus(), 'RUNNING')
|
||||
self.assertEqual(result[0].get("message"), 'started successfully')
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
result = self.synergy.startManager(environ, start_response)
|
||||
result = json.loads(result[0])
|
||||
result = json.loads(result[0], object_hook=objectHookHandler)
|
||||
|
||||
self.assertEqual(result, {'TimerManager': {
|
||||
'message': 'WARN: already started', 'status': 'RUNNING'}})
|
||||
self.assertEqual(result[0].getStatus(), 'RUNNING')
|
||||
self.assertEqual(result[0].get("message"), 'WARN: already started')
|
||||
|
||||
@mock.patch('synergy.service.LOG', LOG)
|
||||
def test_stopManager(self):
|
||||
environ = {'QUERY_STRING': 'manager=TimerManager'}
|
||||
start_response = Mock()
|
||||
stop_response = Mock()
|
||||
environ = {'QUERY_STRING': 'manager=NONE'}
|
||||
|
||||
result = self.synergy.startManager(environ, start_response)
|
||||
result = self.synergy.startManager(environ, stop_response)
|
||||
|
||||
self.assertEqual(result[0], "manager 'NONE' not found!")
|
||||
|
||||
environ = {'QUERY_STRING': 'manager=TimerManager'}
|
||||
|
||||
result = self.synergy.startManager(environ, stop_response)
|
||||
result = json.loads(result[0], object_hook=objectHookHandler)
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
result = self.synergy.stopManager(environ, start_response)
|
||||
result = self.synergy.stopManager(environ, stop_response)
|
||||
result = json.loads(result[0], object_hook=objectHookHandler)
|
||||
|
||||
result = json.loads(result[0])
|
||||
|
||||
self.assertEqual(result, {'TimerManager': {
|
||||
'message': 'stopped successfully', 'status': 'ACTIVE'}})
|
||||
self.assertEqual(result[0].getStatus(), 'ACTIVE')
|
||||
|
||||
@mock.patch('synergy.service.LOG', LOG)
|
||||
def test_executeCommand(self):
|
||||
|
@ -27,6 +27,7 @@ class TestManager(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestManager, self).setUp()
|
||||
self.manager = Manager(name="dummy_manager")
|
||||
self.manager.setAutoStart(False)
|
||||
|
||||
def test_get_name(self):
|
||||
self.assertEqual("dummy_manager", self.manager.getName())
|
||||
|
@ -13,3 +13,5 @@ testrepository>=0.0.18
|
||||
testscenarios>=0.4
|
||||
testtools>=1.4.0
|
||||
mock==2.0.0
|
||||
tabulate>=0.7.2,<0.8.0
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user