From 1eb35349d2bedacc75aff28b0883995794682395 Mon Sep 17 00:00:00 2001 From: lihuan Date: Wed, 6 Jul 2016 17:29:00 +0800 Subject: Creating Director and related codes. Add a new scenario type 'ScenarioGeneral' that support orchestrating general HA test scenarios. Director, ActionPlayer and RollbackPlayer are uesed to execute the test scenario (or test flow). JIRA: YARDSTICK-288 Change-Id: Ied2ccd4712f3c3efde6771bfa4538c1e9e137c11 Signed-off-by: lihuan --- .../benchmark/scenarios/availability/__init__.py | 1 - .../scenarios/availability/actionplayers.py | 54 +++++++++++ .../scenarios/availability/actionrollbackers.py | 45 +++++++++ .../benchmark/scenarios/availability/director.py | 106 +++++++++++++++++++++ .../scenarios/availability/scenario_general.py | 68 +++++++++++++ 5 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 yardstick/benchmark/scenarios/availability/actionplayers.py create mode 100644 yardstick/benchmark/scenarios/availability/actionrollbackers.py create mode 100644 yardstick/benchmark/scenarios/availability/director.py create mode 100644 yardstick/benchmark/scenarios/availability/scenario_general.py (limited to 'yardstick') diff --git a/yardstick/benchmark/scenarios/availability/__init__.py b/yardstick/benchmark/scenarios/availability/__init__.py index fdad0fe95..c3b3aae30 100755 --- a/yardstick/benchmark/scenarios/availability/__init__.py +++ b/yardstick/benchmark/scenarios/availability/__init__.py @@ -12,7 +12,6 @@ class ActionType: ATTACKER = "attacker" MONITOR = "monitor" RESULTCHECKER = "resultchecker" - RESULTCOMPARER = "comparer" OPERATION = "operation" diff --git a/yardstick/benchmark/scenarios/availability/actionplayers.py b/yardstick/benchmark/scenarios/availability/actionplayers.py new file mode 100644 index 000000000..420626413 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/actionplayers.py @@ -0,0 +1,54 @@ +############################################################################## +# Copyright (c) 2016 Juan Qiu and others +# juan_ qiu@tongji.edu.cn +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + + +class ActionPlayer(object): + """ + Abstract the action functions of attacker, + monitor, operation, resultchecker and mybe others in future + """ + + def action(self): + pass + + +class AttackerPlayer(ActionPlayer): + + def __init__(self, attacker): + self.underlyingAttacker = attacker + + def action(self): + self.underlyingAttacker.inject_fault() + + +class OperationPlayer(ActionPlayer): + + def __init__(self, operation): + self.underlyingOperation = operation + + def action(self): + self.underlyingOperation.run() + + +class MonitorPlayer(ActionPlayer): + + def __init__(self, monitor): + self.underlyingmonitor = monitor + + def action(self): + self.underlyingmonitor.start_monitor() + + +class ResultCheckerPlayer(ActionPlayer): + + def __init__(self, resultChecker): + self.underlyingresultChecker = resultChecker + + def action(self): + self.underlyingresultChecker.verify() diff --git a/yardstick/benchmark/scenarios/availability/actionrollbackers.py b/yardstick/benchmark/scenarios/availability/actionrollbackers.py new file mode 100644 index 000000000..4b732a10c --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/actionrollbackers.py @@ -0,0 +1,45 @@ +############################################################################## +# Copyright (c) 2016 Juan Qiu and others +# juan_ qiu@tongji.edu.cn +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import logging + +LOG = logging.getLogger(__name__) + + +class ActionRollbacker(object): + """ + Abstract the rollback functions of attacker, operation + and mybe others in future + """ + + def rollback(self): + pass + + +class AttackerRollbacker(ActionRollbacker): + + def __init__(self, attacker): + self.underlyingAttacker = attacker + + def rollback(self): + LOG.debug( + "\033[93m recovering attacker %s \033[0m" + % (self.underlyingAttacker.key)) + self.underlyingAttacker.recover() + + +class OperationRollbacker(ActionRollbacker): + + def __init__(self, operation): + self.underlyingOperation = operation + + def rollback(self): + LOG.debug( + "\033[93m rollback operation %s \033[0m" + % (self.underlyingOperation.key)) + self.underlyingOperation.rollback() diff --git a/yardstick/benchmark/scenarios/availability/director.py b/yardstick/benchmark/scenarios/availability/director.py new file mode 100644 index 000000000..267933dd0 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/director.py @@ -0,0 +1,106 @@ +############################################################################## +# Copyright (c) 2016 Juan Qiu and others +# juan_ qiu@tongji.edu.cn +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import logging + +from yardstick.benchmark.scenarios.availability.monitor import basemonitor +from yardstick.benchmark.scenarios.availability.attacker import baseattacker +from yardstick.benchmark.scenarios.availability.operation import baseoperation +from yardstick.benchmark.scenarios.availability.result_checker \ + import baseresultchecker +from yardstick.benchmark.scenarios.availability import ActionType +from yardstick.benchmark.scenarios.availability import actionplayers +from yardstick.benchmark.scenarios.availability import actionrollbackers + +LOG = logging.getLogger(__name__) + + +class Director(object): + """ + Director is used to direct a test scenaio + including the creation of action players, test result verification + and rollback of actions. + """ + + def __init__(self, scenario_cfg, context_cfg): + + # A stack store Rollbacker that will be called after + # all actionplayers finish. + self.executionSteps = [] + + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + nodes = self.context_cfg.get("nodes", None) + # setup attackers + if "attackers" in self.scenario_cfg["options"]: + LOG.debug("start init attackers...") + attacker_cfgs = self.scenario_cfg["options"]["attackers"] + self.attackerMgr = baseattacker.AttackerMgr() + self.attackerMgr.init_attackers(attacker_cfgs, nodes) + # setup monitors + if "monitors" in self.scenario_cfg["options"]: + LOG.debug("start init monitors...") + monitor_cfgs = self.scenario_cfg["options"]["monitors"] + self.monitorMgr = basemonitor.MonitorMgr() + self.monitorMgr.init_monitors(monitor_cfgs, nodes) + # setup operations + if "operations" in self.scenario_cfg["options"]: + LOG.debug("start init operations...") + operation_cfgs = self.scenario_cfg["options"]["operations"] + self.operationMgr = baseoperation.OperationMgr() + self.operationMgr.init_operations(operation_cfgs, nodes) + # setup result checker + if "resultCheckers" in self.scenario_cfg["options"]: + LOG.debug("start init resultCheckers...") + result_check_cfgs = self.scenario_cfg["options"]["resultCheckers"] + self.resultCheckerMgr = baseresultchecker.ResultCheckerMgr() + self.resultCheckerMgr.init_ResultChecker(result_check_cfgs, nodes) + + def createActionPlayer(self, type, key): + LOG.debug( + "the type of current action is %s, the key is %s" % (type, key)) + if type == ActionType.ATTACKER: + return actionplayers.AttackerPlayer(self.attackerMgr[key]) + if type == ActionType.MONITOR: + return actionplayers.MonitorPlayer(self.monitorMgr[key]) + if type == ActionType.RESULTCHECKER: + return actionplayers.ResultCheckerPlayer( + self.resultCheckerMgr[key]) + if type == ActionType.OPERATION: + return actionplayers.OperationPlayer(self.operationMgr[key]) + LOG.debug("something run when creatactionplayer") + + def createActionRollbacker(self, type, key): + LOG.debug( + "the type of current action is %s, the key is %s" % (type, key)) + if type == ActionType.ATTACKER: + return actionrollbackers.AttackerRollbacker(self.attackerMgr[key]) + if type == ActionType.OPERATION: + return actionrollbackers.OperationRollbacker( + self.operationMgr[key]) + LOG.debug("no rollbacker created for %s" % (key)) + + def verify(self): + result = True + if hasattr(self, 'monitorMgr'): + result &= self.monitorMgr.verify_SLA() + if hasattr(self, 'resultCheckerMgr'): + result &= self.resultCheckerMgr.verify() + if result: + LOG.debug("monitors are passed") + return result + + def stopMonitors(self): + if "monitors" in self.scenario_cfg["options"]: + self.monitorMgr.wait_monitors() + + def knockoff(self): + LOG.debug("knock off ....") + while self.executionSteps: + singleStep = self.executionSteps.pop() + singleStep.rollback() diff --git a/yardstick/benchmark/scenarios/availability/scenario_general.py b/yardstick/benchmark/scenarios/availability/scenario_general.py new file mode 100644 index 000000000..0a128aa09 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/scenario_general.py @@ -0,0 +1,68 @@ +############################################################################## +# Copyright (c) 2016 Juan Qiu and others +# juan_ qiu@tongji.edu.cn +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import logging +import traceback + +from yardstick.benchmark.scenarios import base +from yardstick.benchmark.scenarios.availability.director import Director + +LOG = logging.getLogger(__name__) + + +class ScenarioGeneral(base.Scenario): + """Support orchestrating general HA test scenarios.""" + + __scenario_type__ = "GeneralHA" + + def __init__(self, scenario_cfg, context_cfg): + LOG.debug( + "scenario_cfg:%s context_cfg:%s" % (scenario_cfg, context_cfg)) + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + + def setup(self): + self.director = Director(self.scenario_cfg, self.context_cfg) + + def run(self, args): + steps = self.scenario_cfg["options"]["steps"] + orderedSteps = sorted(steps, key=lambda x: x['index']) + for step in orderedSteps: + LOG.debug( + "\033[94m running step: {0} .... \033[0m" + .format(orderedSteps.index(step)+1)) + try: + actionPlayer = self.director.createActionPlayer( + step['actionType'], step['actionKey']) + actionPlayer.action() + actionRollbacker = self.director.createActionRollbacker( + step['actionType'], step['actionKey']) + if actionRollbacker: + self.director.executionSteps.append(actionRollbacker) + except Exception, e: + LOG.debug(e.message) + traceback.print_exc() + LOG.debug( + "\033[91m exception when running step: {0} .... \033[0m" + .format(orderedSteps.index(step))) + break + finally: + pass + + self.director.stopMonitors() + if self.director.verify(): + LOG.debug( + "\033[92m congratulations, " + "the test cases scenario is pass! \033[0m") + else: + LOG.debug( + "\033[91m aoh,the test cases scenario failed," + "please check the detail debug information! \033[0m") + + def teardown(self): + self.director.knockoff() -- cgit 1.2.3-korg