Creating a generic opertion 69/16369/2
authorlihuan <lihuansse@tongji.edu.cn>
Tue, 5 Jul 2016 12:07:12 +0000 (20:07 +0800)
committerlihuan <lihuansse@tongji.edu.cn>
Tue, 5 Jul 2016 12:31:16 +0000 (20:31 +0800)
Operation class is used to do some work on the target system such as creating a VM instance.

JIRA: YARDSTICK-275

Change-Id: Ib62846824b74dcdae51f143bc59fba385cc7d84c
Signed-off-by: lihuan <lihuansse@tongji.edu.cn>
tests/unit/benchmark/scenarios/availability/test_baseoperation.py [new file with mode: 0644]
tests/unit/benchmark/scenarios/availability/test_operation_general.py [new file with mode: 0644]
yardstick/benchmark/scenarios/availability/operation/__init__.py [new file with mode: 0644]
yardstick/benchmark/scenarios/availability/operation/baseoperation.py [new file with mode: 0644]
yardstick/benchmark/scenarios/availability/operation/operation_general.py [new file with mode: 0644]
yardstick/benchmark/scenarios/availability/operation_conf.yaml [new file with mode: 0644]

diff --git a/tests/unit/benchmark/scenarios/availability/test_baseoperation.py b/tests/unit/benchmark/scenarios/availability/test_baseoperation.py
new file mode 100644 (file)
index 0000000..8c34191
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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.operation.baseoperation
+
+import mock
+import unittest
+
+from yardstick.benchmark.scenarios.availability.operation import  baseoperation
+
+@mock.patch('yardstick.benchmark.scenarios.availability.operation.baseoperation.BaseOperation')
+class OperationMgrTestCase(unittest.TestCase):
+
+    def setUp(self):
+        config = {
+            'operation_type': 'general-operation',
+            'key' : 'service_status'
+        }
+
+        self.operation_configs = []
+        self.operation_configs.append(config)
+
+    def  test_all_successful(self, mock_operation):
+        mgr_ins = baseoperation.OperationMgr()
+        mgr_ins.init_operations(self.operation_configs, None)
+        operation_ins = mgr_ins["service_status"]
+        mgr_ins.rollback()
+
+    def test_getitem_fail(self, mock_operation):
+        mgr_ins = baseoperation.OperationMgr()
+        mgr_ins.init_operations(self.operation_configs, None)
+        with self.assertRaises(KeyError):
+            operation_ins = mgr_ins["operation-not-exist"]
+
+
+class TestOperation(baseoperation.BaseOperation):
+    __operation__type__ = "test-operation"
+
+    def setup(self):
+        pass
+
+    def run(self):
+        pass
+
+    def rollback(self):
+        pass
+
+
+class BaseOperationTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.config = {
+            'operation_type': 'general-operation',
+            'key' : 'service_status'
+        }
+
+    def test_all_successful(self):
+        base_ins = baseoperation.BaseOperation(self.config, None)
+        base_ins.setup()
+        base_ins.run()
+        base_ins.rollback()
+
+    def test_get_script_fullpath(self):
+        base_ins = baseoperation.BaseOperation(self.config, None)
+        base_ins.get_script_fullpath("ha_tools/test.bash");
+
+    def test_get_operation_cls_successful(self):
+        base_ins = baseoperation.BaseOperation(self.config, None)
+        operation_ins = base_ins.get_operation_cls("test-operation")
+
+    def test_get_operation_cls_fail(self):
+        base_ins = baseoperation.BaseOperation(self.config, None)
+        with self.assertRaises(RuntimeError):
+            operation_ins = base_ins.get_operation_cls("operation-not-exist")
diff --git a/tests/unit/benchmark/scenarios/availability/test_operation_general.py b/tests/unit/benchmark/scenarios/availability/test_operation_general.py
new file mode 100644 (file)
index 0000000..6713733
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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.operation
+# .operation_general
+
+import mock
+import unittest
+from yardstick.benchmark.scenarios.availability.operation import operation_general
+
+@mock.patch('yardstick.benchmark.scenarios.availability.operation.'
+            'operation_general.ssh')
+@mock.patch('yardstick.benchmark.scenarios.availability.operation.'
+            'operation_general.open')
+class GeneralOperaionTestCase(unittest.TestCase):
+
+    def setUp(self):
+        host = {
+            "ip": "10.20.0.5",
+            "user": "root",
+            "key_filename": "/root/.ssh/id_rsa"
+        }
+        self.context = {"node1": host}
+        self.operation_cfg = {
+            'operation_type': 'general-operation',
+            'action_parameter': {'ins_cup': 2},
+            'rollback_parameter': {'ins_id': 'id123456'},
+            'key': 'nova-create-instance',
+            'host': 'node1',
+        }
+        self.operation_cfg_noparam = {
+            'operation_type': 'general-operation',
+            'key': 'nova-create-instance',
+            'host': 'node1',
+        }
+
+    def test__operation_successful(self, mock_open, mock_ssh):
+        ins = operation_general.GeneralOperaion(self.operation_cfg,
+            self.context);
+        mock_ssh.SSH().execute.return_value = (0, "success", '')
+        ins.setup()
+        ins.run()
+        ins.rollback()
+
+    def test__operation_successful_noparam(self, mock_open, mock_ssh):
+        ins = operation_general.GeneralOperaion(self.operation_cfg_noparam,
+            self.context);
+        mock_ssh.SSH().execute.return_value = (0, "success", '')
+        ins.setup()
+        ins.run()
+        ins.rollback()
+
+    def test__operation_fail(self, mock_open, mock_ssh):
+        ins = operation_general.GeneralOperaion(self.operation_cfg,
+            self.context);
+        mock_ssh.SSH().execute.return_value = (1, "failed", '')
+        ins.setup()
+        ins.run()
+        ins.rollback()
diff --git a/yardstick/benchmark/scenarios/availability/operation/__init__.py b/yardstick/benchmark/scenarios/availability/operation/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/yardstick/benchmark/scenarios/availability/operation/baseoperation.py b/yardstick/benchmark/scenarios/availability/operation/baseoperation.py
new file mode 100644 (file)
index 0000000..e776e87
--- /dev/null
@@ -0,0 +1,81 @@
+##############################################################################
+# 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 pkg_resources
+import yaml
+import logging
+import os
+
+import yardstick.common.utils as utils
+
+LOG = logging.getLogger(__name__)
+
+operation_conf_path = pkg_resources.resource_filename(
+    "yardstick.benchmark.scenarios.availability",
+    "operation_conf.yaml")
+
+
+class OperationMgr(object):
+
+    def __init__(self):
+        self._operation_list = []
+
+    def init_operations(self, operation_cfgs, context):
+        LOG.debug("operationMgr confg: %s" % operation_cfgs)
+        for cfg in operation_cfgs:
+            operation_type = cfg['operation_type']
+            operation_cls = BaseOperation.get_operation_cls(operation_type)
+            operation_ins = operation_cls(cfg, context)
+            operation_ins.key = cfg['key']
+            operation_ins.setup()
+            self._operation_list.append(operation_ins)
+
+    def __getitem__(self, item):
+        for obj in self._operation_list:
+            if(obj.key == item):
+                return obj
+        raise KeyError("No such operation instance of key - %s" % item)
+
+    def rollback(self):
+        for _instance in self._operation_list:
+            _instance.rollback()
+
+
+class BaseOperation(object):
+
+    operation_cfgs = {}
+
+    def __init__(self, config, context):
+        if not BaseOperation.operation_cfgs:
+            with open(operation_conf_path) as stream:
+                BaseOperation.operation_cfgs = yaml.load(stream)
+        self.key = ''
+        self._config = config
+        self._context = context
+
+    @staticmethod
+    def get_operation_cls(type):
+        '''return operation instance of specified type'''
+        operation_type = type
+        for operation_cls in utils.itersubclasses(BaseOperation):
+            if operation_type == operation_cls.__operation__type__:
+                return operation_cls
+        raise RuntimeError("No such runner_type %s" % operation_type)
+
+    def get_script_fullpath(self, path):
+        base_path = os.path.dirname(operation_conf_path)
+        return os.path.join(base_path, path)
+
+    def setup(self):
+        pass
+
+    def run(self):
+        pass
+
+    def rollback(self):
+        pass
diff --git a/yardstick/benchmark/scenarios/availability/operation/operation_general.py b/yardstick/benchmark/scenarios/availability/operation/operation_general.py
new file mode 100644 (file)
index 0000000..d413716
--- /dev/null
@@ -0,0 +1,77 @@
+##############################################################################
+# 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 baseoperation import BaseOperation
+import yardstick.ssh as ssh
+from yardstick.benchmark.scenarios.availability.util import buildshellparams
+
+LOG = logging.getLogger(__name__)
+
+
+class GeneralOperaion(BaseOperation):
+
+    __operation__type__ = "general-operation"
+
+    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 = buildshellparams(actionParameter)
+            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 = buildshellparams(rollbackParameter)
+            l = list(item for item in rollbackParameter.values())
+            self.rollback_param = str.format(*l)
+
+        self.operation_cfgs = BaseOperation.operation_cfgs.get(self.key)
+        self.action_script = self.get_script_fullpath(
+            self.operation_cfgs['action_script'])
+        self.rollback_script = self.get_script_fullpath(
+            self.operation_cfgs['rollback_script'])
+
+    def run(self):
+        if "action_parameter" in self._config:
+            exit_status, stdout, stderr = self.connection.execute(
+                self.action_param,
+                stdin=open(self.action_script, "r"))
+        else:
+            exit_status, stdout, stderr = self.connection.execute(
+                "/bin/sh -s ",
+                stdin=open(self.action_script, "r"))
+
+        if exit_status == 0:
+            LOG.debug("success,the operation's output is: {0}".format(stdout))
+        else:
+            LOG.error(
+                "the operation's error, stdout:%s, stderr:%s" %
+                (stdout, stderr))
+
+    def rollback(self):
+        if "rollback_parameter" in self._config:
+            exit_status, stdout, stderr = self.connection.execute(
+                self.rollback_param,
+                stdin=open(self.rollback_script, "r"))
+        else:
+            exit_status, stdout, stderr = self.connection.execute(
+                "/bin/sh -s ",
+                stdin=open(self.rollback_script, "r"))
diff --git a/yardstick/benchmark/scenarios/availability/operation_conf.yaml b/yardstick/benchmark/scenarios/availability/operation_conf.yaml
new file mode 100644 (file)
index 0000000..78c996d
--- /dev/null
@@ -0,0 +1,16 @@
+---
+# sample config file for ha test
+#
+schema: "yardstick:task:0.1"
+
+nova-create-instance:
+  action_script: ha_tools/nova/create_instance_from_image.bash
+  rollback_script: ha_tools/nova/delete_instance.bash
+
+swift_upload_file:
+  action_script: ha_tools/swift/upload.bash
+  rollback_script: ha_tools/swift/delete.bash
+
+swift_download_file:
+  action_script: ha_tools/swift/download.bash
+  rollback_script: ha_tools/file/remove_file.bash
\ No newline at end of file