From 8a4f8df64b8897bf38e77399099099f92266048b Mon Sep 17 00:00:00 2001 From: qiujuan Date: Mon, 30 May 2016 21:15:53 +0800 Subject: Creating a generic attacker JIRA: YARDSTICK-273 Change-Id: Id81b554b559d14ced440a1fa004d14d791fd2306 Signed-off-by: qiujuan --- .../availability/test_attacker_general.py | 55 +++++++++++++ .../availability/attacker/attacker_general.py | 91 ++++++++++++++++++++++ .../availability/attacker/baseattacker.py | 28 +++++++ .../scenarios/availability/attacker_conf.yaml | 4 + yardstick/benchmark/scenarios/availability/util.py | 19 +++++ 5 files changed, 197 insertions(+) create mode 100644 tests/unit/benchmark/scenarios/availability/test_attacker_general.py create mode 100644 yardstick/benchmark/scenarios/availability/attacker/attacker_general.py create mode 100644 yardstick/benchmark/scenarios/availability/util.py diff --git a/tests/unit/benchmark/scenarios/availability/test_attacker_general.py b/tests/unit/benchmark/scenarios/availability/test_attacker_general.py new file mode 100644 index 000000000..d6488a9a7 --- /dev/null +++ b/tests/unit/benchmark/scenarios/availability/test_attacker_general.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +############################################################################## +# 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 +############################################################################## + +# Unittest for yardstick.benchmark.scenarios.availability.attacker +# .attacker_general + +import mock +import unittest + +from yardstick.benchmark.scenarios.availability.attacker import baseattacker + +@mock.patch('yardstick.benchmark.scenarios.availability.attacker.' + 'attacker_general.ssh') +class GeneralAttackerServiceTestCase(unittest.TestCase): + + def setUp(self): + host = { + "ip": "10.20.0.5", + "user": "root", + "key_filename": "/root/.ssh/id_rsa" + } + self.context = {"node1": host} + self.attacker_cfg = { + 'fault_type': 'general-attacker', + 'action_parameter':{'process_name':'nova_api'}, + 'rollback_parameter':{'process_name':'nova_api'}, + 'key':'stop_service', + 'host': 'node1', + } + + def test__attacker_service_all_successful(self, mock_ssh): + + cls = baseattacker.BaseAttacker.get_attacker_cls(self.attacker_cfg) + ins = cls(self.attacker_cfg, self.context) + + mock_ssh.SSH().execute.return_value = (0, "running", '') + ins.setup() + ins.inject_fault() + ins.recover() + + def test__attacker_service_check_failuer(self, mock_ssh): + + cls = baseattacker.BaseAttacker.get_attacker_cls(self.attacker_cfg) + ins = cls(self.attacker_cfg, self.context) + + mock_ssh.SSH().execute.return_value = (0, "error check", '') + ins.setup() diff --git a/yardstick/benchmark/scenarios/availability/attacker/attacker_general.py b/yardstick/benchmark/scenarios/availability/attacker/attacker_general.py new file mode 100644 index 000000000..018362a15 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/attacker/attacker_general.py @@ -0,0 +1,91 @@ +############################################################################## +# 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 baseattacker import BaseAttacker +import yardstick.ssh as ssh +from yardstick.benchmark.scenarios.availability import util + +LOG = logging.getLogger(__name__) + + +class GeneralAttacker(BaseAttacker): + + __attacker_type__ = 'general-attacker' + + def setup(self): + LOG.debug("config:%s context:%s" % (self._config, self._context)) + host = self._context.get(self._config['host'], None) + ip = host.get("ip", None) + user = host.get("user", "root") + key_filename = host.get("key_filename", "~/.ssh/id_rsa") + + self.connection = ssh.SSH(user, ip, key_filename=key_filename) + self.connection.wait(timeout=600) + LOG.debug("ssh host success!") + + self.key = self._config['key'] + + if "action_parameter" in self._config: + actionParameter = self._config['action_parameter'] + str = util.buildshellparams(actionParameter) + LOG.debug("inject parameter is: {0}".format(actionParameter)) + LOG.debug("inject parameter values are: {0}" + .format(actionParameter.values())) + l = list(item for item in actionParameter.values()) + self.action_param = str.format(*l) + + if "rollback_parameter" in self._config: + rollbackParameter = self._config['rollback_parameter'] + str = util.buildshellparams(rollbackParameter) + LOG.debug("recover parameter is: {0}".format(rollbackParameter)) + LOG.debug("recover parameter values are: {0}". + format(rollbackParameter.values())) + l = list(item for item in rollbackParameter.values()) + self.rollback_param = str.format(*l) + + self.fault_cfg = BaseAttacker.attacker_cfgs.get(self.key) + self.inject_script = self.get_script_fullpath( + self.fault_cfg['inject_script']) + self.recovery_script = self.get_script_fullpath( + self.fault_cfg['recovery_script']) + + def inject_fault(self): + LOG.debug("{0} starting inject!".format(self.key)) + LOG.debug("the inject_script path:{0}".format(self.inject_script)) + + if "action_parameter" in self._config: + LOG.debug("the shell command is: {0}".format(self.action_param)) + exit_status, stdout, stderr = self.connection.execute( + self.action_param, + stdin=open(self.inject_script, "r")) + else: + exit_status, stdout, stderr = self.connection.execute( + "/bin/bash -s ", + stdin=open(self.inject_script, "r")) + + LOG.debug("the inject_fault's exit status is: {0}".format(exit_status)) + if exit_status == 0: + LOG.debug("success,the inject_fault's output is: {0}" + .format(stdout)) + else: + LOG.error( + "the inject_fault's error, stdout:%s, stderr:%s" % + (stdout, stderr)) + + def recover(self): + if "rollback_parameter" in self._config: + LOG.debug("the shell command is: {0}".format(self.rollback_param)) + exit_status, stdout, stderr = self.connection.execute( + self.rollback_param, + stdin=open(self.recovery_script, "r")) + else: + exit_status, stdout, stderr = self.connection.execute( + "/bin/bash -s ", + stdin=open(self.recovery_script, "r")) diff --git a/yardstick/benchmark/scenarios/availability/attacker/baseattacker.py b/yardstick/benchmark/scenarios/availability/attacker/baseattacker.py index a1c6999e5..78276efa2 100644 --- a/yardstick/benchmark/scenarios/availability/attacker/baseattacker.py +++ b/yardstick/benchmark/scenarios/availability/attacker/baseattacker.py @@ -20,6 +20,31 @@ attacker_conf_path = pkg_resources.resource_filename( "attacker_conf.yaml") +class AttackerMgr(object): + + def __init__(self): + self._attacker_list = [] + + def init_attackers(self, attacker_cfgs, context): + LOG.debug("attackerMgr confg: %s" % attacker_cfgs) + + for cfg in attacker_cfgs: + attacker_cls = BaseAttacker.get_attacker_cls(cfg) + attacker_ins = attacker_cls(cfg, context) + attacker_ins.key = cfg['key'] + attacker_ins.setup() + self._attacker_list.append(attacker_ins) + + def __getitem__(self, item): + for obj in self._attacker_list: + if(obj.key == item): + return obj + + def recover(self): + for _instance in self._attacker_list: + _instance.recover() + + class BaseAttacker(object): attacker_cfgs = {} @@ -45,3 +70,6 @@ class BaseAttacker(object): def get_script_fullpath(self, path): base_path = os.path.dirname(attacker_conf_path) return os.path.join(base_path, path) + + def recover(self): + pass diff --git a/yardstick/benchmark/scenarios/availability/attacker_conf.yaml b/yardstick/benchmark/scenarios/availability/attacker_conf.yaml index 3f6c2aa8f..16b3d735c 100644 --- a/yardstick/benchmark/scenarios/availability/attacker_conf.yaml +++ b/yardstick/benchmark/scenarios/availability/attacker_conf.yaml @@ -11,3 +11,7 @@ kill-process: bare-metal-down: check_script: ha_tools/check_host_ping.bash recovery_script: ha_tools/ipmi_power.bash + +stop_service: + inject_script: ha_tools/stop_service.bash + recovery_script: ha_tools/start_service.bash diff --git a/yardstick/benchmark/scenarios/availability/util.py b/yardstick/benchmark/scenarios/availability/util.py new file mode 100644 index 000000000..2addef8ef --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/util.py @@ -0,0 +1,19 @@ +############################################################################## +# Copyright (c) 2016 Juan Qiu +# 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 +############################################################################## + + +def buildshellparams(param): + i = 0 + values = [] + result = '/bin/bash -s' + for key in param.keys(): + values.append(param[key]) + result += " {%d}" % i + i = i + 1 + return result -- cgit 1.2.3-korg