summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/unit/benchmark/scenarios/availability/test_director.py103
-rw-r--r--tests/unit/benchmark/scenarios/availability/test_scenario_general.py65
-rwxr-xr-xyardstick/benchmark/scenarios/availability/__init__.py1
-rw-r--r--yardstick/benchmark/scenarios/availability/actionplayers.py54
-rw-r--r--yardstick/benchmark/scenarios/availability/actionrollbackers.py45
-rw-r--r--yardstick/benchmark/scenarios/availability/director.py106
-rw-r--r--yardstick/benchmark/scenarios/availability/scenario_general.py68
7 files changed, 441 insertions, 1 deletions
diff --git a/tests/unit/benchmark/scenarios/availability/test_director.py b/tests/unit/benchmark/scenarios/availability/test_director.py
new file mode 100644
index 000000000..887ddd631
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/availability/test_director.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+
+##############################################################################
+# Copyright (c) 2016 Huan Li and others
+# lihuansse@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
+##############################################################################
+
+# Unittest for yardstick.benchmark.scenarios.availability.director
+
+import mock
+import unittest
+
+from yardstick.benchmark.scenarios.availability.director import Director
+from yardstick.benchmark.scenarios.availability import actionplayers
+
+
+@mock.patch('yardstick.benchmark.scenarios.availability.director.basemonitor')
+@mock.patch('yardstick.benchmark.scenarios.availability.director.baseattacker')
+@mock.patch('yardstick.benchmark.scenarios.availability.director.baseoperation')
+@mock.patch('yardstick.benchmark.scenarios.availability.director.baseresultchecker')
+class DirectorTestCase(unittest.TestCase):
+
+ def setUp(self):
+ self.scenario_cfg = {
+ 'type': "general_scenario",
+ 'options': {
+ 'attackers':[{
+ 'fault_type': "general-attacker",
+ 'key': "kill-process"}],
+ 'monitors': [{
+ 'monitor_type': "general-monitor",
+ 'key': "service_status"}],
+ 'operations': [{
+ 'operation_type': 'general-operation',
+ 'key' : 'service_status'}],
+ 'resultCheckers': [{
+ 'checker_type': 'general-result-checker',
+ 'key' : 'process-checker',}],
+ 'steps':[
+ {
+ 'actionKey': "service_status",
+ 'actionType': "operation",
+ 'index': 1},
+ {
+ 'actionKey': "kill-process",
+ 'actionType': "attacker",
+ 'index': 2},
+ {
+ 'actionKey': "process-checker",
+ 'actionType': "resultchecker",
+ 'index': 3},
+ {
+ 'actionKey': "service_status",
+ 'actionType': "monitor",
+ 'index': 4},
+ ]
+ }
+ }
+ host = {
+ "ip": "10.20.0.5",
+ "user": "root",
+ "key_filename": "/root/.ssh/id_rsa"
+ }
+ self.ctx = {"nodes": {"node1": host}}
+
+ def test_director_all_successful(self, mock_checer, mock_opertion, mock_attacker, mock_monitor):
+ ins = Director(self.scenario_cfg, self.ctx)
+ opertion_action = ins.createActionPlayer("operation", "service_status")
+ attacker_action = ins.createActionPlayer("attacker", "kill-process")
+ checker_action = ins.createActionPlayer("resultchecker", "process-checker")
+ monitor_action = ins.createActionPlayer("monitor", "service_status")
+
+ opertion_rollback = ins.createActionRollbacker("operation", "service_status")
+ attacker_rollback = ins.createActionRollbacker("attacker", "kill-process")
+ ins.executionSteps.append(opertion_rollback)
+ ins.executionSteps.append(attacker_rollback)
+
+ opertion_action.action()
+ attacker_action.action()
+ checker_action.action()
+ monitor_action.action()
+
+ attacker_rollback.rollback()
+ opertion_rollback.rollback()
+
+ ins.stopMonitors()
+ ins.verify()
+ ins.knockoff()
+
+ def test_director_get_wrong_item(self, mock_checer, mock_opertion, mock_attacker, mock_monitor):
+ ins = Director(self.scenario_cfg, self.ctx)
+ ins.createActionPlayer("wrong_type", "wrong_key")
+ ins.createActionRollbacker("wrong_type", "wrong_key")
+
+
+
+
+
+
diff --git a/tests/unit/benchmark/scenarios/availability/test_scenario_general.py b/tests/unit/benchmark/scenarios/availability/test_scenario_general.py
new file mode 100644
index 000000000..c17edea45
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/availability/test_scenario_general.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+##############################################################################
+# Copyright (c) 2016 Huan Li and others
+# lihuansse@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
+##############################################################################
+
+# Unittest for yardstick.benchmark.scenarios.availability.scenario_general
+
+import mock
+import unittest
+
+from yardstick.benchmark.scenarios.availability.scenario_general import ScenarioGeneral
+
+
+@mock.patch('yardstick.benchmark.scenarios.availability.scenario_general.Director')
+class ScenarioGeneralTestCase(unittest.TestCase):
+
+ def setUp(self):
+ self.scenario_cfg = {
+ 'type': "general_scenario",
+ 'options': {
+ 'attackers':[{
+ 'fault_type': "general-attacker",
+ 'key': "kill-process"}],
+ 'monitors': [{
+ 'monitor_type': "general-monitor",
+ 'key': "service_status"}],
+ 'steps':[
+ {
+ 'actionKey': "kill-process",
+ 'actionType': "attacker",
+ 'index': 1},
+ {
+ 'actionKey': "service_status",
+ 'actionType': "monitor",
+ 'index': 2}]
+ }
+ }
+
+ def test_scenario_general_all_successful(self, mock_director):
+ ins = ScenarioGeneral(self.scenario_cfg, None)
+ ins.setup()
+ ins.run(None)
+ ins.teardown()
+
+ def test_scenario_general_exception(self, mock_director):
+ ins = ScenarioGeneral(self.scenario_cfg, None)
+ mock_obj = mock.Mock()
+ mock_obj.createActionPlayer.side_effect = KeyError('Wrong')
+ ins.director = mock_obj
+ ins.run(None)
+ ins.teardown()
+
+ def test_scenario_general_case_fail(self, mock_director):
+ ins = ScenarioGeneral(self.scenario_cfg, None)
+ mock_obj = mock.Mock()
+ mock_obj.verify.return_value = False
+ ins.director = mock_obj
+ ins.run(None)
+ ins.teardown() \ No newline at end of file
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()