Enhancement in handling the parameters defined in the user request

The Synergy's methods startManager() stopManager() getManagerStatus() and
executeCommand() require the parsing of the parameters included into the
user request and make some checks for the mandatory parameters.
This commit enhances this parsing and checking steps by using the Python
decorators. Moreover it simplifies the execution of the methods startManager()
stopManager() and getManagerStatus() by handling requests for only one manager
at a time.

Change-Id: Ic295ad20f03459cf3e512e795529c35bd6969ed3
Sem-Ver: bugfix
This commit is contained in:
Lisa Zangrando 2017-05-24 10:39:26 +02:00
parent b99f2078a1
commit 3b568b70a0
5 changed files with 171 additions and 327 deletions

View File

@ -80,19 +80,18 @@ class ManagerCommand(HTTPCommand):
"status", add_help=True, help="show the managers status")
status_parser.add_argument(
"manager", nargs='*', help="one or more manager name")
"manager", nargs='?', default=None, help="at most one manager")
start_parser = manager_parsers.add_parser(
"start", add_help=True, help="start the manager")
start_parser.add_argument(
"manager", nargs='+', help="one or more manager name")
start_parser.add_argument("manager", help="the manager to start")
stop_parser = manager_parsers.add_parser(
"stop", add_help=True, help="stop the manager")
stop_parser.add_argument(
"manager", nargs='+', help="one or more manager name")
"manager", help="the manager to stop")
def execute(self, synergy_url, args=None):
table = []
@ -113,21 +112,19 @@ class ManagerCommand(HTTPCommand):
headers.append("rate (min)")
url += "/synergy/" + args.command
managers = super(ManagerCommand, self).execute(
result = super(ManagerCommand, self).execute(
url, {"manager": args.manager})
if args.command == "status":
for manager in managers:
for manager in result:
table.append([manager.getName(),
manager.getStatus(),
manager.getRate()])
else:
for manager in managers:
msg = manager.get("message")
table.append([manager.getName(),
manager.getStatus() + " (%s)" % msg,
manager.getRate()])
msg = result.get("message")
table.append([result.getName(),
result.getStatus() + " (%s)" % msg,
result.getRate()])
print(tabulate(table, headers, tablefmt="fancy_grid"))

View File

@ -1,10 +1,12 @@
import os
import os.path
import requests
import sys
from argparse import ArgumentParser
from pkg_resources import iter_entry_points
from requests.exceptions import ConnectionError
from requests.exceptions import HTTPError
from requests.exceptions import RequestException
from synergy.client import keystone_v3
__author__ = "Lisa Zangrando"
@ -167,14 +169,14 @@ def main():
commands[command_name].setToken(token)
commands[command_name].execute(synergy_url, args)
except KeyboardInterrupt as e:
except KeyboardInterrupt:
print("Shutting down synergyclient")
sys.exit(1)
except requests.exceptions.HTTPError as e:
print("HTTPError: %s" % e.response._content)
except (RequestException, ConnectionError, HTTPError) as ex:
print("connection to %s failed!" % synergy_url)
sys.exit(1)
except Exception as e:
print("ERROR: %s" % e)
except Exception as ex:
print(ex.message)
sys.exit(1)

View File

@ -153,15 +153,58 @@ class Synergy(Service):
self.saved_args, self.saved_kwargs = args, kwargs
def authorizationRequired(f):
def parseParameters(f):
def wrapper(self, *args, **kw):
context = args[0]
query = context.get("QUERY_STRING", None)
if query:
parameters = parse_qs(query)
for key in parameters:
value = escape(parameters[key][0])
value = value.replace("'", "\"")
try:
value = json.loads(value)
except ValueError:
pass
context[key] = value
return f(self, *args, **kw)
return wrapper
def checkParameters(paremeters):
def check(f):
def wrapper(self, *args, **kw):
context = args[0]
start_response = args[1]
for parameter in paremeters:
value = context.get(parameter, None)
if not value:
start_response("400 BAD REQUEST",
[("Content-Type", "text/plain")])
return "parameter %s not found!" % parameter
if parameter == "manager" and value not in self.managers:
start_response("404 NOT FOUND",
[("Content-Type", "text/plain")])
return "manager %s not found!" % value
return f(self, *args, **kw)
return wrapper
return check
def authorize(f):
def wrapper(self, *args, **kw):
if self.auth_plugin:
context = args[0]
context["managers"] = self.managers
query = context.get("QUERY_STRING", None)
if query:
context.update(parse_qs(query))
try:
self.auth_plugin.authorize(context)
@ -174,7 +217,7 @@ class Synergy(Service):
return wrapper
@authorizationRequired
@authorize
def listManagers(self, environ, start_response):
result = []
@ -188,23 +231,21 @@ class Synergy(Service):
start_response("200 OK", [("Content-Type", "text/html")])
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
@authorizationRequired
@parseParameters
@authorize
def getManagerStatus(self, environ, start_response):
manager_name = environ.get("manager", None)
manager_list = None
result = []
query = environ.get("QUERY_STRING", None)
if manager_name:
if manager_name not in self.managers:
start_response("404 NOT FOUND",
[("Content-Type", "text/plain")])
return "manager %s not found!" % manager_name
if query:
parameters = parse_qs(query)
if "manager" in parameters:
if isinstance(parameters['manager'], (list, tuple)):
manager_list = parameters['manager']
else:
manager_list = [parameters['manager']]
else:
manager_list = self.managers.keys()
manager_list = [manager_name]
else:
manager_list = self.managers.keys()
@ -220,184 +261,94 @@ class Synergy(Service):
result.append(m)
if len(manager_list) == 1 and len(result) == 0:
start_response("404 NOT FOUND", [("Content-Type", "text/plain")])
return ["manager %s not found!" % manager_list[0]]
start_response("200 OK", [("Content-Type", "text/html")])
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
return [json.dumps(result, cls=SynergyEncoder)]
@authorizationRequired
@parseParameters
@checkParameters(["manager", "command", "args"])
@authorize
def executeCommand(self, environ, start_response):
manager_name = None
command = None
query = environ.get("QUERY_STRING", None)
if not query:
start_response("400 BAD REQUEST", [("Content-Type", "text/plain")])
return ["bad request"]
parameters = parse_qs(query)
LOG.debug("execute command: parameters=%s" % parameters)
if "manager" not in parameters:
start_response("400 BAD REQUEST", [("Content-Type", "text/plain")])
return ["manager not specified!"]
manager_name = escape(parameters['manager'][0])
if manager_name not in self.managers:
start_response("404 NOT FOUND", [("Content-Type", "text/plain")])
return ["manager %s not found!" % manager_name]
if "command" not in parameters:
start_response("400 BAD REQUEST", [("Content-Type", "text/plain")])
return ["bad request"]
command = escape(parameters['command'][0])
if "args" in parameters:
manager_args = escape(parameters['args'][0])
manager_args = manager_args.replace("'", "\"")
manager_args = json.loads(manager_args)
else:
manager_args = {}
manager_name = environ["manager"]
manager = self.managers[manager_name]
manager_args = environ["args"]
command = environ["command"]
try:
result = manager.execute(command=command, **manager_args)
start_response("200 OK", [("Content-Type", "text/html")])
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
return [json.dumps(result, cls=SynergyEncoder)]
except NotImplementedError:
message = "execute() not implemented!"
LOG.error(message)
start_response("500 INTERNAL SERVER ERROR",
[("Content-Type", "text/plain")])
return ["error: %s" % message]
return message
except SynergyError as ex:
LOG.debug("execute command: error=%s" % ex)
start_response("500 INTERNAL SERVER ERROR",
[("Content-Type", "text/plain")])
return ["error: %s" % ex]
return "%s" % ex
@authorizationRequired
@parseParameters
@checkParameters(["manager"])
@authorize
def startManager(self, environ, start_response):
manager_list = None
result = []
manager_name = environ["manager"]
manager = self.managers[manager_name]
result = Manager(manager_name)
result.setRate(manager.getRate())
query = environ.get("QUERY_STRING", None)
if manager.getStatus() == "ACTIVE":
LOG.info("starting the %s manager" % (manager_name))
if not query:
start_response("400 BAD REQUEST", [("Content-Type", "text/plain")])
return ["bad request"]
manager.resume()
parameters = parse_qs(query)
LOG.info("%s manager started! (rate=%s min)"
% (manager_name, manager.getRate()))
if "manager" not in parameters:
start_response("400 BAD REQUEST", [("Content-Type", "text/plain")])
return ["manager not specified!"]
if isinstance(parameters['manager'], (list, tuple)):
manager_list = parameters['manager']
else:
manager_list = [parameters['manager']]
for manager_name in manager_list:
manager_name = escape(manager_name)
if manager_name not in self.managers:
continue
manager = self.managers[manager_name]
m = Manager(manager_name)
m.setRate(manager.getRate())
result.append(m)
if manager.getStatus() == "ACTIVE":
LOG.info("starting the %s manager" % (manager_name))
manager.resume()
LOG.info("%s manager started! (rate=%s min)"
% (manager_name, manager.getRate()))
m.setStatus("RUNNING")
m.set("message", "started successfully")
elif manager.getStatus() == "RUNNING":
m.setStatus("RUNNING")
m.set("message", "WARN: already started")
elif manager.getStatus() == "ERROR":
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]]
result.setStatus("RUNNING")
result.set("message", "started successfully")
elif manager.getStatus() == "RUNNING":
result.setStatus("RUNNING")
result.set("message", "WARN: already started")
elif manager.getStatus() == "ERROR":
result.setStatus("ERROR")
result.set("message", "wrong state")
start_response("200 OK", [("Content-Type", "text/html")])
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
return json.dumps(result, cls=SynergyEncoder)
@authorizationRequired
@parseParameters
@checkParameters(["manager"])
@authorize
def stopManager(self, environ, start_response):
manager_list = None
result = []
query = environ.get("QUERY_STRING", None)
manager_name = environ["manager"]
manager = self.managers[manager_name]
result = Manager(manager_name)
result.setRate(manager.getRate())
if not query:
start_response("400 BAD REQUEST", [("Content-Type", "text/plain")])
return ["bad request"]
if manager.getStatus() == "RUNNING":
LOG.info("stopping the %s manager" % (manager_name))
parameters = parse_qs(query)
manager.pause()
if "manager" not in parameters:
start_response("400 BAD REQUEST", [("Content-Type", "text/plain")])
return ["manager not specified!"]
LOG.info("%s manager stopped!" % (manager_name))
if isinstance(parameters['manager'], (list, tuple)):
manager_list = parameters['manager']
else:
manager_list = [parameters['manager']]
for manager_name in manager_list:
manager_name = escape(manager_name)
if manager_name not in self.managers:
continue
manager = self.managers[manager_name]
m = Manager(manager_name)
m.setRate(manager.getRate())
result.append(m)
if manager.getStatus() == "RUNNING":
LOG.info("stopping the %s manager" % (manager_name))
manager.pause()
LOG.info("%s manager stopped!" % (manager_name))
m.setStatus("ACTIVE")
m.set("message", "stopped successfully")
elif manager.getStatus() == "ACTIVE":
m.setStatus("ACTIVE")
m.set("message", "WARN: already stopped")
elif manager.getStatus() == "ERROR":
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]]
result.setStatus("ACTIVE")
result.set("message", "stopped successfully")
elif manager.getStatus() == "ACTIVE":
result.setStatus("ACTIVE")
result.set("message", "WARN: already stopped")
elif manager.getStatus() == "ERROR":
result.setStatus("ERROR")
result.set("message", "wrong state")
start_response("200 OK", [("Content-Type", "text/html")])
return ["%s" % json.dumps(result, cls=SynergyEncoder)]
return json.dumps(result, cls=SynergyEncoder)
def start(self):
self.model_disconnected = False

View File

@ -75,7 +75,17 @@ class SynergyTests(unittest.TestCase):
@mock.patch('synergy.service.LOG', LOG)
def test_getManagerStatus(self):
start_response = Mock()
result = self.synergy.getManagerStatus(environ={},
environ = {}
result = self.synergy.getManagerStatus(environ,
start_response=start_response)
result = json.loads(result[0], object_hook=objectHookHandler)
self.assertEqual(result[0].getStatus(), 'ACTIVE')
environ = {'QUERY_STRING': 'manager=TimerManager'}
result = self.synergy.getManagerStatus(environ,
start_response=start_response)
result = json.loads(result[0], object_hook=objectHookHandler)
@ -89,23 +99,23 @@ class SynergyTests(unittest.TestCase):
result = self.synergy.startManager(environ, start_response)
self.assertEqual(result[0], "manager 'NONE' not found!")
self.assertEqual(result, "manager NONE not found!")
environ = {'QUERY_STRING': 'manager=TimerManager'}
result = self.synergy.startManager(environ, start_response)
result = json.loads(result[0], object_hook=objectHookHandler)
result = json.loads(result, object_hook=objectHookHandler)
self.assertEqual(result[0].getStatus(), 'RUNNING')
self.assertEqual(result[0].get("message"), 'started successfully')
self.assertEqual(result.getStatus(), 'RUNNING')
self.assertEqual(result.get("message"), 'started successfully')
time.sleep(0.5)
result = self.synergy.startManager(environ, start_response)
result = json.loads(result[0], object_hook=objectHookHandler)
result = json.loads(result, object_hook=objectHookHandler)
self.assertEqual(result[0].getStatus(), 'RUNNING')
self.assertEqual(result[0].get("message"), 'WARN: already started')
self.assertEqual(result.getStatus(), 'RUNNING')
self.assertEqual(result.get("message"), 'WARN: already started')
@mock.patch('synergy.service.LOG', LOG)
def test_stopManager(self):
@ -114,23 +124,25 @@ class SynergyTests(unittest.TestCase):
result = self.synergy.startManager(environ, stop_response)
self.assertEqual(result[0], "manager 'NONE' not found!")
self.assertEqual(result, "manager NONE not found!")
environ = {'QUERY_STRING': 'manager=TimerManager'}
result = self.synergy.startManager(environ, stop_response)
result = json.loads(result[0], object_hook=objectHookHandler)
result = json.loads(result, object_hook=objectHookHandler)
time.sleep(0.5)
result = self.synergy.stopManager(environ, stop_response)
result = json.loads(result[0], object_hook=objectHookHandler)
result = json.loads(result, object_hook=objectHookHandler)
self.assertEqual(result[0].getStatus(), 'ACTIVE')
self.assertEqual(result.getStatus(), 'ACTIVE')
@mock.patch('synergy.service.LOG', LOG)
def test_executeCommand(self):
environ = {'QUERY_STRING': 'manager=TimerManager&command=GET_TIME'}
environ = {'QUERY_STRING':
'manager=TimerManager&args=%7B%22id%22%3A'
'+null%2C+%22name%22%3A+%22prj_a%22%7D&command=GET_TIME'}
start_response = Mock()
result = self.synergy.executeCommand(environ, start_response)

View File

@ -49,22 +49,22 @@ class TestManagerCommand(base.TestCase):
# manager status
res = root_parser.parse_args(["manager", "status"])
ns = Namespace(command_name="manager", command="status", manager=[])
ns = Namespace(command_name="manager", command="status", manager=None)
self.assertEqual(ns, res)
res = root_parser.parse_args(["manager", "status", "TestManager"])
ns = Namespace(
command_name="manager",
command="status",
manager=["TestManager"])
manager="TestManager")
self.assertEqual(ns, res)
res = root_parser.parse_args(
["manager", "status", "Test1", "Test2", "Test3"])
["manager", "status", "Test1"])
ns = Namespace(
command_name="manager",
command="status",
manager=["Test1", "Test2", "Test3"])
manager="Test1")
self.assertEqual(ns, res)
# manager start
@ -77,15 +77,15 @@ class TestManagerCommand(base.TestCase):
ns = Namespace(
command_name="manager",
command="start",
manager=["TestManager"])
manager="TestManager")
self.assertEqual(ns, res)
res = root_parser.parse_args(
["manager", "start", "Test1", "Test2"])
["manager", "start", "Test1"])
ns = Namespace(
command_name="manager",
command="start",
manager=["Test1", "Test2"])
manager="Test1")
self.assertEqual(ns, res)
# manager stop
@ -98,15 +98,15 @@ class TestManagerCommand(base.TestCase):
ns = Namespace(
command_name="manager",
command="stop",
manager=["TestManager"])
manager="TestManager")
self.assertEqual(ns, res)
res = root_parser.parse_args(
["manager", "stop", "Test1", "Test2"])
["manager", "stop", "Test1"])
ns = Namespace(
command_name="manager",
command="stop",
manager=["Test1", "Test2"])
manager="Test1")
self.assertEqual(ns, res)
@mock.patch('synergy.client.command.tabulate')
@ -204,50 +204,12 @@ class TestManagerCommand(base.TestCase):
tablefmt="fancy_grid")
@mock.patch('synergy.client.command.tabulate')
def test_execute_status_two_managers(self, mock_tabulate):
"""Check the CLI output of "manager status ManagerA ManagerB"."""
# Mock the parser call
mock_parser = mock.Mock()
mock_parser.args.command = "status"
mock_parser.args.manager = ["ManagerA", "ManagerB"]
# Mock 2 managers and their statuses
manager_a = mock.Mock()
manager_a.getName.return_value = "ManagerA"
manager_a.getStatus.return_value = "UP"
manager_a.getRate.return_value = 5
manager_b = mock.Mock()
manager_b.getName.return_value = "ManagerB"
manager_b.getStatus.return_value = "DOWN"
manager_b.getRate.return_value = 10
mgrs = [manager_a, manager_b]
# Execute "manager status ManagerA ManagerB"
with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m:
self.manager_command.execute(synergy_url="", args=mock_parser.args)
# Check the executed call
m.assert_called_once_with(
"/synergy/status",
{"manager": ["ManagerA", "ManagerB"]})
# Check the data when we call tabulate
headers = ["manager", "status", "rate (min)"]
table = [
["ManagerA", "UP", 5],
["ManagerB", "DOWN", 10]]
mock_tabulate.assert_called_once_with(
table,
headers,
tablefmt="fancy_grid")
@mock.patch('synergy.client.command.tabulate')
def test_execute_start_one_manager(self, mock_tabulate):
def test_execute_start_manager(self, mock_tabulate):
"""Check the CLI output of "manager start ManagerA"."""
# Mock the parser call
mock_parser = mock.Mock()
mock_parser.args.command = "start"
mock_parser.args.manager = ["ManagerA"]
mock_parser.args.manager = "ManagerA"
# Mock a manager
manager_a = mock.Mock()
@ -255,7 +217,7 @@ class TestManagerCommand(base.TestCase):
manager_a.getStatus.return_value = "RUNNING"
manager_a.get.return_value = "started successfully"
manager_a.getRate.return_value = 1
mgrs = [manager_a]
mgrs = manager_a
# Execute "manager start ManagerA"
with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m:
@ -264,7 +226,7 @@ class TestManagerCommand(base.TestCase):
# Check the executed call to "manager start ManagerA"
m.assert_called_once_with(
"/synergy/start",
{"manager": ["ManagerA"]})
{"manager": "ManagerA"})
# Check the data when we call tabulate
headers = ["manager", "status", "rate (min)"]
@ -275,52 +237,12 @@ class TestManagerCommand(base.TestCase):
tablefmt="fancy_grid")
@mock.patch('synergy.client.command.tabulate')
def test_execute_start_two_managers(self, mock_tabulate):
"""Check the CLI output of "manager start ManagerA ManagerB"."""
# Mock the parser call
mock_parser = mock.Mock()
mock_parser.args.command = "start"
mock_parser.args.manager = ["ManagerA", "ManagerB"]
# Mock 2 managers
manager_a = mock.Mock()
manager_a.getName.return_value = "ManagerA"
manager_a.getStatus.return_value = "RUNNING"
manager_a.get.return_value = "started successfully"
manager_a.getRate.return_value = 1
manager_b = mock.Mock()
manager_b.getName.return_value = "ManagerB"
manager_b.getStatus.return_value = "RUNNING"
manager_b.get.return_value = "started successfully"
manager_b.getRate.return_value = 4
mgrs = [manager_a, manager_b]
# Execute "manager start ManagerA ManagerB"
with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m:
self.manager_command.execute(synergy_url='', args=mock_parser.args)
# Check the executed call to "manager start ManagerA ManagerB"
m.assert_called_once_with(
"/synergy/start",
{"manager": ["ManagerA", "ManagerB"]})
# Check the data when we call tabulate
headers = ["manager", "status", "rate (min)"]
table = [
["ManagerA", "RUNNING (started successfully)", 1],
["ManagerB", "RUNNING (started successfully)", 4]]
mock_tabulate.assert_called_once_with(
table,
headers,
tablefmt="fancy_grid")
@mock.patch('synergy.client.command.tabulate')
def test_execute_stop_one_manager(self, mock_tabulate):
def test_execute_stop_manager(self, mock_tabulate):
"""Check the CLI output of "manager stop ManagerA"."""
# Mock the parser call
mock_parser = mock.Mock()
mock_parser.args.command = "stop"
mock_parser.args.manager = ["ManagerA"]
mock_parser.args.manager = "ManagerA"
# Mock a manager
manager_a = mock.Mock()
@ -328,7 +250,7 @@ class TestManagerCommand(base.TestCase):
manager_a.getStatus.return_value = "ACTIVE"
manager_a.get.return_value = "stopped successfully"
manager_a.getRate.return_value = 1
mgrs = [manager_a]
mgrs = manager_a
# Execute "manager stop ManagerA"
with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m:
@ -337,7 +259,7 @@ class TestManagerCommand(base.TestCase):
# Check the executed call to "manager stop ManagerA"
m.assert_called_once_with(
"/synergy/stop",
{"manager": ["ManagerA"]})
{"manager": "ManagerA"})
# Check the data when we call tabulate
headers = ["manager", "status", "rate (min)"]
@ -346,43 +268,3 @@ class TestManagerCommand(base.TestCase):
table,
headers,
tablefmt="fancy_grid")
@mock.patch('synergy.client.command.tabulate')
def test_execute_stop_two_managers(self, mock_tabulate):
"""Check the CLI output of "manager stop ManagerA ManagerB"."""
# Mock the parser call
mock_parser = mock.Mock()
mock_parser.args.command = "stop"
mock_parser.args.manager = ["ManagerA", "ManagerB"]
# Mock 2 managers
manager_a = mock.Mock()
manager_a.getName.return_value = "ManagerA"
manager_a.getStatus.return_value = "ACTIVE"
manager_a.get.return_value = "stopped successfully"
manager_a.getRate.return_value = 1
manager_b = mock.Mock()
manager_b.getName.return_value = "ManagerB"
manager_b.getStatus.return_value = "ACTIVE"
manager_b.get.return_value = "stopped successfully"
manager_b.getRate.return_value = 4
mgrs = [manager_a, manager_b]
# Execute "manager stop ManagerA ManagerB"
with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m:
self.manager_command.execute(synergy_url='', args=mock_parser.args)
# Check the executed call to "manager start ManagerA ManagerB"
m.assert_called_once_with(
"/synergy/stop",
{"manager": ["ManagerA", "ManagerB"]})
# Check the data when we call tabulate
headers = ["manager", "status", "rate (min)"]
table = [
["ManagerA", "ACTIVE (stopped successfully)", 1],
["ManagerB", "ACTIVE (stopped successfully)", 4]]
mock_tabulate.assert_called_once_with(
table,
headers,
tablefmt="fancy_grid")