From 4d065d2f4080e935b4e3bab4cbcf2b97f8a61ed3 Mon Sep 17 00:00:00 2001 From: JingLu5 Date: Thu, 10 Aug 2017 06:00:58 +0000 Subject: Add common openstack opertation scenarios: flavor & server JIRA: YARDSTICK-781 This patch adds some common openstack opertation scenarios Change-Id: I9e84a8894fe9b9c1754a45a0ddfdf93739164b9a Signed-off-by: JingLu5 --- .../benchmark/scenarios/lib/test_create_flavor.py | 37 ++++++++ .../benchmark/scenarios/lib/test_create_server.py | 42 +++++++++ .../benchmark/scenarios/lib/test_delete_flavor.py | 35 +++++++ .../benchmark/scenarios/lib/test_get_flavor.py | 33 +++++++ yardstick/benchmark/scenarios/lib/create_flavor.py | 65 +++++++++++++ yardstick/benchmark/scenarios/lib/create_server.py | 72 +++++++++++++++ yardstick/benchmark/scenarios/lib/delete_flavor.py | 56 ++++++++++++ yardstick/benchmark/scenarios/lib/get_flavor.py | 54 +++++++++++ yardstick/common/openstack_utils.py | 101 ++++++++------------- 9 files changed, 433 insertions(+), 62 deletions(-) create mode 100644 tests/unit/benchmark/scenarios/lib/test_create_flavor.py create mode 100644 tests/unit/benchmark/scenarios/lib/test_create_server.py create mode 100644 tests/unit/benchmark/scenarios/lib/test_delete_flavor.py create mode 100644 tests/unit/benchmark/scenarios/lib/test_get_flavor.py create mode 100644 yardstick/benchmark/scenarios/lib/create_flavor.py create mode 100644 yardstick/benchmark/scenarios/lib/create_server.py create mode 100644 yardstick/benchmark/scenarios/lib/delete_flavor.py create mode 100644 yardstick/benchmark/scenarios/lib/get_flavor.py diff --git a/tests/unit/benchmark/scenarios/lib/test_create_flavor.py b/tests/unit/benchmark/scenarios/lib/test_create_flavor.py new file mode 100644 index 000000000..036ae952d --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_create_flavor.py @@ -0,0 +1,37 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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 unittest +import mock + +from yardstick.benchmark.scenarios.lib.create_flavor import CreateFlavor + + +class CreateFlavorTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.create_flavor') + def test_create_flavor(self, mock_create_flavor): + options = { + 'flavor_name': 'yardstick_test_flavor', + 'vcpus': '2', + 'ram': '1024', + 'disk': '100', + 'is_public': 'True' + } + args = {"options": options} + obj = CreateFlavor(args, {}) + obj.run({}) + self.assertTrue(mock_create_flavor.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_create_server.py b/tests/unit/benchmark/scenarios/lib/test_create_server.py new file mode 100644 index 000000000..7c4193132 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_create_server.py @@ -0,0 +1,42 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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 unittest +import mock + +from yardstick.benchmark.scenarios.lib.create_server import CreateServer + + +class CreateServerTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.create_instance_and_wait_for_active') + @mock.patch('yardstick.common.openstack_utils.get_nova_client') + @mock.patch('yardstick.common.openstack_utils.get_glance_client') + @mock.patch('yardstick.common.openstack_utils.get_neutron_client') + def test_create_server(self, mock_get_nova_client, mock_get_neutron_client, + mock_get_glance_client, mock_create_instance_and_wait_for_active): + scenario_cfg = { + 'options' : { + 'openstack_paras': 'example' + }, + 'output': 'server' + } + obj = CreateServer(scenario_cfg, {}) + obj.run({}) + self.assertTrue(mock_get_nova_client.called) + self.assertTrue(mock_get_glance_client.called) + self.assertTrue(mock_get_neutron_client.called) + self.assertTrue(mock_create_instance_and_wait_for_active.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py b/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py new file mode 100644 index 000000000..4a91b8939 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py @@ -0,0 +1,35 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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 unittest +import mock + +from yardstick.benchmark.scenarios.lib.delete_flavor import DeleteFlavor + + +class DeleteFlavorTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.delete_flavor') + @mock.patch('yardstick.common.openstack_utils.get_nova_client') + def test_delete_flavor(self, mock_get_nova_client, mock_delete_flavor): + options = { + 'flavor_name': 'yardstick_test_flavor' + } + args = {"options": options} + obj = DeleteFlavor(args, {}) + obj.run({}) + self.assertTrue(mock_get_nova_client.called) + self.assertTrue(mock_delete_flavor.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_get_flavor.py b/tests/unit/benchmark/scenarios/lib/test_get_flavor.py new file mode 100644 index 000000000..bf12e0a32 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_get_flavor.py @@ -0,0 +1,33 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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 unittest +import mock + +from yardstick.benchmark.scenarios.lib.get_flavor import GetFlavor + + +class GetFlavorTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.get_flavor_by_name') + def test_get_flavor(self, mock_get_flavor_by_name): + options = { + 'flavor_name': 'yardstick_test_flavor' + } + args = {"options": options} + obj = GetFlavor(args, {}) + obj.run({}) + self.assertTrue(mock_get_flavor_by_name.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/yardstick/benchmark/scenarios/lib/create_flavor.py b/yardstick/benchmark/scenarios/lib/create_flavor.py new file mode 100644 index 000000000..05c7099cb --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/create_flavor.py @@ -0,0 +1,65 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class CreateFlavor(base.Scenario): + """Create an OpenStack flavor""" + + __scenario_type__ = "CreateFlavor" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.flavor_name = self.options.get("flavor_name", "TestFlavor") + self.vcpus = self.options.get("vcpus", 2) + self.ram = self.options.get("ram", 1024) + self.disk = self.options.get("disk", 100) + self.public = self.options.get("is_public", True) + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + LOG.info("Creating flavor %s with %s vcpus, %sMB ram and %sGB disk", + self.flavor_name, self.vcpus, self.ram, self.disk) + paras = {'is_public': self.public} + flavor = op_utils.create_flavor(self.flavor_name, + self.ram, self.vcpus, self.disk, + **paras) + + if flavor: + LOG.info("Create flavor successful!") + values = [flavor.id] + else: + LOG.info("Create flavor failed!") + values = [] + + keys = self.scenario_cfg.get('output', '').split() + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/create_server.py b/yardstick/benchmark/scenarios/lib/create_server.py new file mode 100644 index 000000000..45c0bfde9 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/create_server.py @@ -0,0 +1,72 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class CreateServer(base.Scenario): + """Create an OpenStack server""" + + __scenario_type__ = "CreateSever" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.image_name = self.options.get("image_name", None) + self.flavor_name = self.options.get("flavor_name", None) + self.openstack = self.options.get("openstack_paras", None) + + self.glance_client = op_utils.get_glance_client() + self.neutron_client = op_utils.get_neutron_client() + self.nova_client = op_utils.get_nova_client() + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + if self.image_name is not None: + self.openstack['image'] = op_utils.get_image_id(self.glance_client, + self.image_name) + if self.flavor_name is not None: + self.openstack['flavor'] = op_utils.get_flavor_id(self.nova_client, + self.flavor_name) + + vm = op_utils.create_instance_and_wait_for_active(self.openstack) + + if vm: + LOG.info("Create server successful!") + else: + LOG.error("Create server failed!") + + try: + keys = self.scenario_cfg.get('output', '').split() + except KeyError: + pass + else: + values = [vm.id] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/delete_flavor.py b/yardstick/benchmark/scenarios/lib/delete_flavor.py new file mode 100644 index 000000000..b30c37496 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/delete_flavor.py @@ -0,0 +1,56 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class DeleteFlavor(base.Scenario): + """Delete an OpenStack flavor by name""" + + __scenario_type__ = "DeleteFlavor" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.flavor_name = self.options.get("flavor_name", "TestFlavor") + self.flavor_id = None + + self.nova_client = op_utils.get_nova_client() + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + self.flavor_id = op_utils.get_flavor_id(self.nova_client, self.flavor_name) + LOG.info("Deleting flavor: %s", self.flavor_name) + status = op_utils.delete_flavor(self.flavor_id) + + if status: + LOG.info("Delete flavor successful!") + else: + LOG.info("Delete flavor failed!") diff --git a/yardstick/benchmark/scenarios/lib/get_flavor.py b/yardstick/benchmark/scenarios/lib/get_flavor.py new file mode 100644 index 000000000..d5e33947e --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/get_flavor.py @@ -0,0 +1,54 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class GetFlavor(base.Scenario): + """Get an OpenStack flavor by name""" + + __scenario_type__ = "GetFlavor" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + self.flavor_name = self.options.get("flavor_name", "TestFlavor") + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + LOG.info("Querying flavor: %s", self.flavor_name) + flavor = op_utils.get_flavor_by_name(self.flavor_name) + if flavor: + LOG.info("Get flavor successful!") + values = [self._change_obj_to_dict(flavor)] + else: + LOG.info("Get flavor: no flavor matched!") + values = [] + + keys = self.scenario_cfg.get('output', '').split() + return self._push_to_outputs(keys, values) diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py index f027b7922..51be6882a 100644 --- a/yardstick/common/openstack_utils.py +++ b/yardstick/common/openstack_utils.py @@ -264,81 +264,29 @@ def create_aggregate_with_host(nova_client, aggregate_name, av_zone, return True -def create_instance(flavor_name, - image_id, - network_id, - instance_name="instance-vm", - confdrive=True, - userdata=None, - av_zone='', - fixed_ip=None, - files=None): # pragma: no cover - nova_client = get_nova_client() +def create_instance(json_body): # pragma: no cover try: - flavor = nova_client.flavors.find(name=flavor_name) - except: - flavors = nova_client.flavors.list() - log.exception("Error: Flavor '%s' not found. Available flavors are: " - "\n%s", flavor_name, flavors) + return get_nova_client().servers.create(**json_body) + except Exception: + log.exception("Error create instance failed") return None - if fixed_ip is not None: - nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip} - else: - nics = {"net-id": network_id} - if userdata is None: - instance = nova_client.servers.create( - name=instance_name, - flavor=flavor, - image=image_id, - nics=[nics], - availability_zone=av_zone, - files=files - ) - else: - instance = nova_client.servers.create( - name=instance_name, - flavor=flavor, - image=image_id, - nics=[nics], - config_drive=confdrive, - userdata=userdata, - availability_zone=av_zone, - files=files - ) - return instance - - -def create_instance_and_wait_for_active(flavor_name, - image_id, - network_id, - instance_name="instance-vm", - config_drive=False, - userdata="", - av_zone='', - fixed_ip=None, - files=None): # pragma: no cover + + +def create_instance_and_wait_for_active(json_body): # pragma: no cover SLEEP = 3 VM_BOOT_TIMEOUT = 180 nova_client = get_nova_client() - instance = create_instance(flavor_name, - image_id, - network_id, - instance_name, - config_drive, - userdata, - av_zone=av_zone, - fixed_ip=fixed_ip, - files=files) + instance = create_instance(json_body) count = VM_BOOT_TIMEOUT / SLEEP for n in range(count, -1, -1): status = get_instance_status(nova_client, instance) if status.lower() == "active": return instance elif status.lower() == "error": - log.error("The instance %s went to ERROR status.", instance_name) + log.error("The instance went to ERROR status.") return None time.sleep(SLEEP) - log.error("Timeout booting the instance %s.", instance_name) + log.error("Timeout booting the instance.") return None @@ -395,6 +343,15 @@ def get_server_by_name(name): # pragma: no cover raise +def create_flavor(name, ram, vcpus, disk, **kwargs): # pragma: no cover + try: + return get_nova_client().flavors.create(name, ram, vcpus, disk, **kwargs) + except Exception: + log.exception("Error [create_flavor(nova_client, %s, %s, %s, %s, %s)]", + name, ram, disk, vcpus, kwargs['is_public']) + return None + + def get_image_by_name(name): # pragma: no cover images = get_nova_client().images.list() try: @@ -403,6 +360,16 @@ def get_image_by_name(name): # pragma: no cover log.exception('No image matched') +def get_flavor_id(nova_client, flavor_name): # pragma: no cover + flavors = nova_client.flavors.list(detailed=True) + flavor_id = '' + for f in flavors: + if f.name == flavor_name: + flavor_id = f.id + break + return flavor_id + + def get_flavor_by_name(name): # pragma: no cover flavors = get_nova_client().flavors.list() try: @@ -426,6 +393,16 @@ def check_status(status, name, iterations, interval): # pragma: no cover return False +def delete_flavor(flavor_id): # pragma: no cover + try: + get_nova_client().flavors.delete(flavor_id) + except Exception: + log.exception("Error [delete_flavor(nova_client, %s)]", flavor_id) + return False + else: + return True + + # ********************************************* # NEUTRON # ********************************************* -- cgit 1.2.3-korg