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:
Lisa Zangrando 2016-08-30 12:16:25 +02:00 committed by Vincent Llorens
parent 07c15e9c93
commit 3c33d51dd4
10 changed files with 316 additions and 342 deletions

View File

@ -15,3 +15,4 @@ eventlet
oslo.config>=2.4.0,<3.0.0 oslo.config>=2.4.0,<3.0.0
oslo.messaging>=2.5.0,<3.0.0 oslo.messaging>=2.5.0,<3.0.0
python-dateutil python-dateutil
tabulate>=0.7.2,<0.8.0

View File

@ -26,13 +26,10 @@ scripts =
[entry_points] [entry_points]
synergy.managers = synergy.managers =
timer = synergy.examples.timer_manager:TimerManager TimerManager = synergy.examples.timer_manager:TimerManager
synergy.commands = synergy.commands =
list = synergy.client.command:List manager = synergy.client.command:ManagerCommand
status = synergy.client.command:Status
start = synergy.client.command:Start
stop = synergy.client.command:Stop
[build_sphinx] [build_sphinx]
source-dir = doc/source source-dir = doc/source

View File

@ -1,6 +1,10 @@
import json import json
import requests import requests
from synergy.common import utils
from tabulate import tabulate
__author__ = "Lisa Zangrando" __author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it" __email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud __copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
@ -31,10 +35,21 @@ class HTTPCommand(object):
def configureParser(self, subparser): def configureParser(self, subparser):
raise NotImplementedError("not implemented!") raise NotImplementedError("not implemented!")
def log(self): def objectHookHandler(self, parsed_dict):
raise NotImplementedError("not implemented!") 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) request = requests.get(synergy_url, params=payload)
if request.status_code != requests.codes.ok: if request.status_code != requests.codes.ok:
@ -44,180 +59,98 @@ class HTTPCommand(object):
self.results = request.json() self.results = request.json()
return request try:
return json.loads(request.text, object_hook=self.objectHookHandler)
except Exception:
return request.json()
def getResults(self): def getResults(self):
return self.results return self.results
class List(HTTPCommand): class ManagerCommand(HTTPCommand):
def __init__(self): def __init__(self):
super(List, self).__init__("list") super(ManagerCommand, self).__init__("Manager")
def configureParser(self, subparser): 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): manager_parsers.add_parser(
super(List, self).sendRequest(synergy_url + "/synergy/list") "list", add_help=True, help="list the managers")
def log(self): status_parser = manager_parsers.add_parser(
results = self.getResults() "status", add_help=True, help="show the managers status")
max_project_id = max(len(max(results, key=len)), len("manager")) status_parser.add_argument(
separator_str = "-" * (max_project_id + 4) + "\n" "manager", nargs='*', help="the managers list")
format_str = "| {0:%ss} |\n" % (max_project_id)
msg = separator_str start_parser = manager_parsers.add_parser(
msg += format_str.format("manager") "start", add_help=True, help="start the manager")
msg += separator_str
for manager in results: start_parser.add_argument(
msg += format_str.format(manager) "manager", nargs='+', help="the managers list")
msg += separator_str stop_parser = manager_parsers.add_parser(
print(msg) "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): class ExecuteCommand(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):
def __init__(self, name): 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: if args is None:
args = {} args = {}
url = synergy_url + "/synergy/execute"
payload = {"manager": manager, payload = {"manager": manager,
"command": command, "command": command,
"args": json.dumps(args)} "args": json.dumps(args)}
super(Execute, self).sendRequest(synergy_url + "/synergy/execute", return super(ExecuteCommand, self).execute(url, payload)
payload)

View File

@ -175,8 +175,8 @@ def main():
if command_name not in commands: if command_name not in commands:
print("command %r not found!" % command_name) print("command %r not found!" % command_name)
commands[command_name].sendRequest(synergy_url, args) commands[command_name].execute(synergy_url, args)
commands[command_name].log() # commands[command_name].log()
except KeyboardInterrupt as e: except KeyboardInterrupt as e:
print("Shutting down synergyclient") print("Shutting down synergyclient")
sys.exit(1) sys.exit(1)

View File

@ -1,7 +1,9 @@
from serializer import SynergyObject
from threading import Condition from threading import Condition
from threading import Event from threading import Event
from threading import Thread from threading import Thread
__author__ = "Lisa Zangrando" __author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it" __email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud __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.""" 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__() super(Manager, self).__init__()
self.setDaemon(True)
self.stop_event = Event()
self.config_opts = []
self.condition = Condition() self.condition = Condition()
self.name = name self.stop_event = Event()
self.status = "CREATED" self.setDaemon(True)
self.autostart = False self.setName(name)
self.rate = -1 self.setStatus("CREATED")
self.setRate(-1)
self.config_opts = []
self.paused = True # start out paused self.paused = True # start out paused
self.managers = {} self.managers = {}
@ -61,24 +62,30 @@ class Manager(Thread):
if manager.getName() != manager_name: if manager.getName() != manager_name:
manager.doOnEvent(event_type, *args, **kargs) manager.doOnEvent(event_type, *args, **kargs)
def getName(self):
return self.name
def getOptions(self): def getOptions(self):
return self.config_opts 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): def isAutoStart(self):
return self.autostart return self.get("autostart")
def setAutoStart(self, autostart): def setAutoStart(self, autostart):
self.autostart = autostart self.set("autostart", autostart)
self.paused = not self.autostart self.paused = not autostart
def getRate(self): def getRate(self):
return self.rate return self.get("rate")
def setRate(self, rate): def setRate(self, rate):
self.rate = rate self.set("rate", rate)
def setup(self): def setup(self):
"""Manager initialization """Manager initialization
@ -93,15 +100,6 @@ class Manager(Thread):
def destroy(self): def destroy(self):
raise NotImplementedError raise NotImplementedError
def getStatus(self):
return self.status
def setStatus(self, status):
with self.condition:
self.status = status
self.condition.notifyAll()
def stop(self): def stop(self):
if self.isAlive(): if self.isAlive():
# set event to signal thread to terminate # set event to signal thread to terminate
@ -124,13 +122,13 @@ class Manager(Thread):
while not self.stop_event.isSet(): while not self.stop_event.isSet():
with self.condition: with self.condition:
if self.paused: if self.paused:
self.status = "ACTIVE" self.setStatus("ACTIVE")
self.condition.wait() self.condition.wait()
else: else:
self.status = "RUNNING" self.setStatus("RUNNING")
try: try:
self.task() self.task()
self.condition.wait(self.rate * 60) self.condition.wait(self.getRate() * 60)
except Exception as ex: except Exception as ex:
print("task %r: %s" % (self.name, ex)) print("task %r: %s" % (self.getName(), ex))

View File

@ -1,9 +1,5 @@
try: import datetime
import oslo_messaging from json import JSONEncoder
except ImportError:
import oslo.messaging as oslo_messaging
from synergy.common import context as ctx
from synergy.common import utils from synergy.common import utils
@ -35,128 +31,136 @@ class SynergyObject(object):
necessary "get" classmethod routines as well as "set" object methods necessary "get" classmethod routines as well as "set" object methods
as appropriate. as appropriate.
""" """
VERSION = "1.0" VERSION = "1.0"
def __init__(self, name=None): def __init__(self):
super(SynergyObject, self).__init__()
self.attributes = {} self.attributes = {}
if name: def getId(self):
self.attributes["name"] = name return self.get("id")
def setId(self, id):
self.set("id", id)
def getName(self): def getName(self):
return self.attributes["name"] return self.get("name")
def setName(self, 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) return self.attributes.get(field, None)
def set(self, field, value): def set(self, field, value):
self.attributes[field] = value if isinstance(value, unicode):
self.attributes[field] = str(value)
def setContext(self, context): else:
self.context = context self.attributes[field] = value
def setAttributes(self, attributes): def setAttributes(self, attributes):
if attributes: if attributes:
self.attributes = attributes self.attributes = attributes
@classmethod @classmethod
def deserialize(cls, context, entity): def deserialize(cls, entity):
if "synergy_object.namespace" not in entity: if "synergy_object" not in entity:
raise Exception("synergy_object.namespace nof defined!") raise Exception("it seems not a Synergy object!")
if "synergy_object.name" not in entity: synergy_object = entity["synergy_object"]
raise Exception("synergy_object.name nof defined!")
if "synergy_object.version" not in entity: if "namespace" not in synergy_object:
raise Exception("synergy_object.version nof defined!") 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" raise Exception("unsupported object objtype='%s.%s"
% (entity["synergy_object.namespace"], % (synergy_object["namespace"],
entity["synergy_object.name"])) synergy_object["name"]))
objName = entity['synergy_object.name'] objInstance = None
# objVer = entity['synergy_object.version']
objClass = utils.import_class(objName)
# 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) del entity["synergy_object"]
objInstance.setContext(context)
objInstance.setAttributes(entity) 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 return objInstance
def serialize(self): def serialize(self):
name = self.__class__.__module__ + "." + self.__class__.__name__ 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 result = {"synergy_object": {}}
""" result["synergy_object"]["name"] = name
def log(self): result["synergy_object"]["version"] = self.VERSION
result["synergy_object"]["namespace"] = "synergy"
for key, value in self.attributes.items(): 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): for item in value:
def __init__(self): if isinstance(item, SynergyObject):
super(SynergySerializer, self).__init__() result[key].append(item.serialize())
else:
def serialize_entity(self, context, entity): result[key].append(item)
if not entity: elif isinstance(value, datetime.datetime):
return entity result[key] = value.isoformat()
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)
else: else:
result = {} result[key] = value
for key, value in entity.items(): return result
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)
class RequestContextSerializer(oslo_messaging.Serializer): class SynergyEncoder(JSONEncoder):
def __init__(self): def default(self, obj):
pass if isinstance(obj, SynergyObject):
return obj.serialize()
def serialize_entity(self, context, entity): else:
return entity return JSONEncoder.default(self, obj)
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)

View File

@ -15,8 +15,11 @@ except ImportError:
from oslo.config import cfg from oslo.config import cfg
from synergy.common import config from synergy.common import config
from synergy.common import service from synergy.common.manager import Manager
from synergy.common import wsgi from synergy.common.serializer import SynergyEncoder
from synergy.common.service import Service
from synergy.common.wsgi import Server
__author__ = "Lisa Zangrando" __author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it" __email__ = "lisa.zangrando[AT]pd.infn.it"
@ -76,7 +79,7 @@ def setLogger(name):
logger.addHandler(handler) logger.addHandler(handler)
class Synergy(service.Service): class Synergy(Service):
"""Service object for binaries running on hosts. """Service object for binaries running on hosts.
A service takes a manager and enables rpc by listening to queues based 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_class = entry.load()
manager_obj = manager_class(*args, **kwargs) 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.setAutoStart(CONF.get(entry.name).autostart)
manager_obj.setRate(CONF.get(entry.name).rate) manager_obj.setRate(CONF.get(entry.name).rate)
@ -137,14 +139,18 @@ class Synergy(service.Service):
result = [] result = []
for name, manager in self.managers.items(): 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")]) 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): def getManagerStatus(self, environ, start_response):
manager_list = None manager_list = None
result = {} result = []
query = environ.get("QUERY_STRING", None) query = environ.get("QUERY_STRING", None)
@ -165,14 +171,20 @@ class Synergy(service.Service):
manager_name = escape(manager_name) manager_name = escape(manager_name)
if manager_name in self.managers: 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: if len(manager_list) == 1 and len(result) == 0:
start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) start_response("404 NOT FOUND", [("Content-Type", "text/plain")])
return ["manager %r not found!" % manager_list[0]] return ["manager %r not found!" % manager_list[0]]
start_response("200 OK", [("Content-Type", "text/html")]) 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): def executeCommand(self, environ, start_response):
manager_name = None manager_name = None
@ -215,16 +227,8 @@ class Synergy(service.Service):
try: try:
result = manager.execute(command=command, **manager_args) 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")]) start_response("200 OK", [("Content-Type", "text/html")])
return ["%s" % json.dumps(result)] return ["%s" % json.dumps(result, cls=SynergyEncoder)]
except Exception as ex: except Exception as ex:
LOG.debug("execute command: error=%s" % ex) LOG.debug("execute command: error=%s" % ex)
start_response("500 INTERNAL SERVER ERROR", start_response("500 INTERNAL SERVER ERROR",
@ -233,7 +237,7 @@ class Synergy(service.Service):
def startManager(self, environ, start_response): def startManager(self, environ, start_response):
manager_list = None manager_list = None
result = {} result = []
query = environ.get("QUERY_STRING", None) query = environ.get("QUERY_STRING", None)
@ -258,9 +262,11 @@ class Synergy(service.Service):
if manager_name not in self.managers: if manager_name not in self.managers:
continue continue
result[manager_name] = {}
manager = self.managers[manager_name] manager = self.managers[manager_name]
m = Manager(manager_name)
m.setRate(manager.getRate())
result.append(m)
if manager.getStatus() == "ACTIVE": if manager.getStatus() == "ACTIVE":
LOG.info("starting the %r manager" % (manager_name)) LOG.info("starting the %r manager" % (manager_name))
@ -270,25 +276,25 @@ class Synergy(service.Service):
LOG.info("%r manager started! (rate=%s min)" LOG.info("%r manager started! (rate=%s min)"
% (manager_name, manager.getRate())) % (manager_name, manager.getRate()))
result[manager_name]["status"] = "RUNNING" m.setStatus("RUNNING")
result[manager_name]["message"] = "started successfully" m.set("message", "started successfully")
elif manager.getStatus() == "RUNNING": elif manager.getStatus() == "RUNNING":
result[manager_name]["status"] = "RUNNING" m.setStatus("RUNNING")
result[manager_name]["message"] = "WARN: already started" m.set("message", "WARN: already started")
elif manager.getStatus() == "ERROR": elif manager.getStatus() == "ERROR":
result[manager_name]["status"] = "ERROR" m.setStatus("ERROR")
result[manager_name]["message"] = "wrong state" m.set("message", "wrong state")
if len(manager_list) == 1 and len(result) == 0: if len(manager_list) == 1 and len(result) == 0:
start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) start_response("404 NOT FOUND", [("Content-Type", "text/plain")])
return ["manager %r not found!" % manager_list[0]] return ["manager %r not found!" % manager_list[0]]
start_response("200 OK", [("Content-Type", "text/html")]) 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): def stopManager(self, environ, start_response):
manager_list = None manager_list = None
result = {} result = []
query = environ.get("QUERY_STRING", None) query = environ.get("QUERY_STRING", None)
@ -313,10 +319,13 @@ class Synergy(service.Service):
if manager_name not in self.managers: if manager_name not in self.managers:
continue continue
result[manager_name] = {}
manager = self.managers[manager_name] manager = self.managers[manager_name]
m = Manager(manager_name)
m.setRate(manager.getRate())
result.append(m)
if manager.getStatus() == "RUNNING": if manager.getStatus() == "RUNNING":
LOG.info("stopping the %r manager" % (manager_name)) LOG.info("stopping the %r manager" % (manager_name))
@ -324,21 +333,21 @@ class Synergy(service.Service):
LOG.info("%r manager stopped!" % (manager_name)) LOG.info("%r manager stopped!" % (manager_name))
result[manager_name]["status"] = "ACTIVE" m.setStatus("ACTIVE")
result[manager_name]["message"] = "stopped successfully" m.set("message", "stopped successfully")
elif manager.getStatus() == "ACTIVE": elif manager.getStatus() == "ACTIVE":
result[manager_name]["status"] = "ACTIVE" m.setStatus("ACTIVE")
result[manager_name]["message"] = "WARN: already stopped" m.set("message", "WARN: already stopped")
elif manager.getStatus() == "ERROR": elif manager.getStatus() == "ERROR":
result[manager_name]["status"] = "ERROR" m.setStatus("ERROR")
result[manager_name]["message"] = "wrong state" m.set("message", "wrong state")
if len(manager_list) == 1 and len(result) == 0: if len(manager_list) == 1 and len(result) == 0:
start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) start_response("404 NOT FOUND", [("Content-Type", "text/plain")])
return ["manager %r not found!" % manager_list[0]] return ["manager %r not found!" % manager_list[0]]
start_response("200 OK", [("Content-Type", "text/html")]) start_response("200 OK", [("Content-Type", "text/html")])
return ["%s" % json.dumps(result)] return ["%s" % json.dumps(result, cls=SynergyEncoder)]
def start(self): def start(self):
self.model_disconnected = False self.model_disconnected = False
@ -357,7 +366,7 @@ class Synergy(service.Service):
manager.setStatus("ERROR") manager.setStatus("ERROR")
raise ex raise ex
self.wsgi_server = wsgi.Server( self.wsgi_server = Server(
name="WSGI server", name="WSGI server",
host_name=CONF.WSGI.host, host_name=CONF.WSGI.host,
host_port=CONF.WSGI.port, host_port=CONF.WSGI.port,

View File

@ -23,6 +23,7 @@ import sys
import time import time
from mock import Mock from mock import Mock
from synergy.common import utils
from synergy.service import Synergy from synergy.service import Synergy
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
@ -47,6 +48,21 @@ def getLogger(name):
return logger 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): class SynergyTests(unittest.TestCase):
@mock.patch('synergy.service.LOG', LOG) @mock.patch('synergy.service.LOG', LOG)
@ -66,53 +82,66 @@ class SynergyTests(unittest.TestCase):
start_response = Mock() start_response = Mock()
result = self.synergy.listManagers(environ={}, result = self.synergy.listManagers(environ={},
start_response=start_response) 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) @mock.patch('synergy.service.LOG', LOG)
def test_getManagerStatus(self): def test_getManagerStatus(self):
start_response = Mock() start_response = Mock()
result = self.synergy.getManagerStatus(environ={}, result = self.synergy.getManagerStatus(environ={},
start_response=start_response) 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) @mock.patch('synergy.service.LOG', LOG)
def test_startManager(self): def test_startManager(self):
environ = {'QUERY_STRING': 'manager=TimerManager'}
start_response = Mock() start_response = Mock()
environ = {'QUERY_STRING': 'manager=NONE'}
result = self.synergy.startManager(environ, start_response) result = self.synergy.startManager(environ, start_response)
result = json.loads(result[0])
self.assertEqual(result, {'TimerManager': { self.assertEqual(result[0], "manager 'NONE' not found!")
'message': 'started successfully', 'status': 'RUNNING'}})
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) time.sleep(0.5)
result = self.synergy.startManager(environ, start_response) result = self.synergy.startManager(environ, start_response)
result = json.loads(result[0]) result = json.loads(result[0], object_hook=objectHookHandler)
self.assertEqual(result, {'TimerManager': { self.assertEqual(result[0].getStatus(), 'RUNNING')
'message': 'WARN: already started', 'status': 'RUNNING'}}) self.assertEqual(result[0].get("message"), 'WARN: already started')
@mock.patch('synergy.service.LOG', LOG) @mock.patch('synergy.service.LOG', LOG)
def test_stopManager(self): def test_stopManager(self):
environ = {'QUERY_STRING': 'manager=TimerManager'} stop_response = Mock()
start_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) 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[0].getStatus(), 'ACTIVE')
self.assertEqual(result, {'TimerManager': {
'message': 'stopped successfully', 'status': 'ACTIVE'}})
@mock.patch('synergy.service.LOG', LOG) @mock.patch('synergy.service.LOG', LOG)
def test_executeCommand(self): def test_executeCommand(self):

View File

@ -27,6 +27,7 @@ class TestManager(base.TestCase):
def setUp(self): def setUp(self):
super(TestManager, self).setUp() super(TestManager, self).setUp()
self.manager = Manager(name="dummy_manager") self.manager = Manager(name="dummy_manager")
self.manager.setAutoStart(False)
def test_get_name(self): def test_get_name(self):
self.assertEqual("dummy_manager", self.manager.getName()) self.assertEqual("dummy_manager", self.manager.getName())

View File

@ -13,3 +13,5 @@ testrepository>=0.0.18
testscenarios>=0.4 testscenarios>=0.4
testtools>=1.4.0 testtools>=1.4.0
mock==2.0.0 mock==2.0.0
tabulate>=0.7.2,<0.8.0