From 297fff010a189d7bb2cdfa2838050d9dc99e2be6 Mon Sep 17 00:00:00 2001 From: Piyush Raman Srivastava Date: Fri, 1 Apr 2016 14:57:50 +0530 Subject: [PATCH] Add create-flavor and flavor-access-list scenario Benchmark create-flavor and flavor-access-list Nova API. blueprint extend-api-benchmark-in-nova-scenarios Change-Id: I870405aaaec727cfb3a0b460dcf60c6a7ca4b6d1 --- rally-jobs/nova.yaml | 28 +++++++++++++++ rally/plugins/openstack/cleanup/resources.py | 8 +++++ .../openstack/scenarios/nova/flavors.py | 36 +++++++++++++++++++ .../plugins/openstack/scenarios/nova/utils.py | 21 +++++++++++ .../nova/create-and-list-flavor-access.json | 16 +++++++++ .../nova/create-and-list-flavor-access.yaml | 11 ++++++ .../tasks/scenarios/nova/create-flavor.json | 16 +++++++++ .../tasks/scenarios/nova/create-flavor.yaml | 11 ++++++ .../openstack/cleanup/test_resources.py | 17 +++++++++ .../openstack/scenarios/nova/test_flavors.py | 28 +++++++++++++++ .../openstack/scenarios/nova/test_utils.py | 26 ++++++++++++++ 11 files changed, 218 insertions(+) create mode 100644 samples/tasks/scenarios/nova/create-and-list-flavor-access.json create mode 100644 samples/tasks/scenarios/nova/create-and-list-flavor-access.yaml create mode 100644 samples/tasks/scenarios/nova/create-flavor.json create mode 100644 samples/tasks/scenarios/nova/create-flavor.yaml diff --git a/rally-jobs/nova.yaml b/rally-jobs/nova.yaml index ef50057f..c09906b5 100644 --- a/rally-jobs/nova.yaml +++ b/rally-jobs/nova.yaml @@ -984,3 +984,31 @@ sla: failure_rate: max: 0 + + NovaFlavors.create_flavor: + - + args: + ram: 500 + vcpus: 1 + disk: 1 + runner: + type: "constant" + times: 5 + concurrency: 2 + sla: + failure_rate: + max: 0 + + NovaFlavors.create_and_list_flavor_access: + - + args: + ram: 500 + vcpus: 1 + disk: 1 + runner: + type: "constant" + times: 5 + concurrency: 2 + sla: + failure_rate: + max: 0 diff --git a/rally/plugins/openstack/cleanup/resources.py b/rally/plugins/openstack/cleanup/resources.py index e3146779..835724d6 100644 --- a/rally/plugins/openstack/cleanup/resources.py +++ b/rally/plugins/openstack/cleanup/resources.py @@ -137,6 +137,14 @@ class NovaQuotas(QuotaMixin, base.ResourceManager): pass +@base.resource("nova", "flavors", order=next(_nova_order), + admin_required=True, perform_for_admin_only=True) +class NovaFlavors(base.ResourceManager): + def list(self): + return [r for r in self._manager().list() + if utils.name_matches_object(r.name, nova_utils.NovaScenario)] + + @base.resource("nova", "floating_ips_bulk", order=next(_nova_order), admin_required=True) class NovaFloatingIpsBulk(SynchronizedDeletion, base.ResourceManager): diff --git a/rally/plugins/openstack/scenarios/nova/flavors.py b/rally/plugins/openstack/scenarios/nova/flavors.py index e7ee921b..13d29ed5 100644 --- a/rally/plugins/openstack/scenarios/nova/flavors.py +++ b/rally/plugins/openstack/scenarios/nova/flavors.py @@ -13,11 +13,14 @@ # License for the specific language governing permissions and limitations # under the License. +from rally.common import logging from rally import consts from rally.plugins.openstack import scenario from rally.plugins.openstack.scenarios.nova import utils from rally.task import validation +LOG = logging.getLogger(__name__) + class NovaFlavors(utils.NovaScenario): """Benchmark scenarios for Nova flavors.""" @@ -36,3 +39,36 @@ class NovaFlavors(utils.NovaScenario): :param kwargs: Optional additional arguments for flavor listing """ self._list_flavors(detailed, **kwargs) + + @validation.required_services(consts.Service.NOVA) + @validation.required_openstack(admin=True) + @scenario.configure(context={"admin_cleanup": ["nova"]}) + def create_and_list_flavor_access(self, ram, vcpus, disk, **kwargs): + """Create a non-public flavor and list its access rules + + :param ram: Memory in MB for the flavor + :param vcpus: Number of VCPUs for the flavor + :param disk: Size of local disk in GB + :param kwargs: Optional additional arguments for flavor creation + """ + # NOTE(pirsriva): access rules can be listed + # only for non-public flavors + if kwargs.get("is_public", False): + LOG.warn("is_public cannot be set to True for listing flavor " + "access rules. Setting is_public to False") + kwargs["is_public"] = False + flavor = self._create_flavor(ram, vcpus, disk, **kwargs) + self._list_flavor_access(flavor.id) + + @validation.required_services(consts.Service.NOVA) + @validation.required_openstack(admin=True) + @scenario.configure(context={"admin_cleanup": ["nova"]}) + def create_flavor(self, ram, vcpus, disk, **kwargs): + """Create a flavor. + + :param ram: Memory in MB for the flavor + :param vcpus: Number of VCPUs for the flavor + :param disk: Size of local disk in GB + :param kwargs: Optional additional arguments for flavor creation + """ + self._create_flavor(ram, vcpus, disk, **kwargs) diff --git a/rally/plugins/openstack/scenarios/nova/utils.py b/rally/plugins/openstack/scenarios/nova/utils.py index a1b1a1ed..507e6f4f 100644 --- a/rally/plugins/openstack/scenarios/nova/utils.py +++ b/rally/plugins/openstack/scenarios/nova/utils.py @@ -948,3 +948,24 @@ class NovaScenario(scenario.OpenStackScenario): :param binary: List all nova services matching given binary """ return self.admin_clients("nova").services.list(host, binary) + + @atomic.action_timer("nova.create_flavor") + def _create_flavor(self, ram, vcpus, disk, **kwargs): + """Create a flavor + + :param ram: Memory in MB for the flavor + :param vcpus: Number of VCPUs for the flavor + :param disk: Size of local disk in GB + :param kwargs: Optional additional arguments for flavor creation + """ + name = self.generate_random_name() + return self.admin_clients("nova").flavors.create(name, ram, vcpus, + disk, **kwargs) + + @atomic.action_timer("nova.list_flavor_access") + def _list_flavor_access(self, flavor): + """List access-rules for non-public flavor. + + :param flavor: List access rules for flavor instance or flavor ID + """ + return self.admin_clients("nova").flavor_access.list(flavor=flavor) diff --git a/samples/tasks/scenarios/nova/create-and-list-flavor-access.json b/samples/tasks/scenarios/nova/create-and-list-flavor-access.json new file mode 100644 index 00000000..680be246 --- /dev/null +++ b/samples/tasks/scenarios/nova/create-and-list-flavor-access.json @@ -0,0 +1,16 @@ +{ + "NovaFlavors.create_and_list_flavor_access": [ + { + "runner": { + "type": "constant", + "concurrency": 2, + "times": 10 + }, + "args": { + "ram": 500, + "vcpus" : 1, + "disk": 1 + } + } + ] +} diff --git a/samples/tasks/scenarios/nova/create-and-list-flavor-access.yaml b/samples/tasks/scenarios/nova/create-and-list-flavor-access.yaml new file mode 100644 index 00000000..b16bbd50 --- /dev/null +++ b/samples/tasks/scenarios/nova/create-and-list-flavor-access.yaml @@ -0,0 +1,11 @@ +--- + NovaFlavors.create_and_list_flavor_access: + - + args: + ram: 500 + vcpus: 1 + disk: 1 + runner: + type: "constant" + times: 10 + concurrency: 2 diff --git a/samples/tasks/scenarios/nova/create-flavor.json b/samples/tasks/scenarios/nova/create-flavor.json new file mode 100644 index 00000000..ec65d493 --- /dev/null +++ b/samples/tasks/scenarios/nova/create-flavor.json @@ -0,0 +1,16 @@ +{ + "NovaFlavors.create_flavor": [ + { + "runner": { + "type": "constant", + "concurrency": 2, + "times": 10 + }, + "args": { + "ram": 500, + "vcpus" : 1, + "disk": 1 + } + } + ] +} diff --git a/samples/tasks/scenarios/nova/create-flavor.yaml b/samples/tasks/scenarios/nova/create-flavor.yaml new file mode 100644 index 00000000..988f3a41 --- /dev/null +++ b/samples/tasks/scenarios/nova/create-flavor.yaml @@ -0,0 +1,11 @@ +--- + NovaFlavors.create_flavor: + - + args: + ram: 500 + vcpus: 1 + disk: 1 + runner: + type: "constant" + times: 10 + concurrency: 2 diff --git a/tests/unit/plugins/openstack/cleanup/test_resources.py b/tests/unit/plugins/openstack/cleanup/test_resources.py index 270a9f7d..878e5622 100644 --- a/tests/unit/plugins/openstack/cleanup/test_resources.py +++ b/tests/unit/plugins/openstack/cleanup/test_resources.py @@ -21,6 +21,7 @@ from neutronclient.common import exceptions as neutron_exceptions from rally.common import utils from rally.plugins.openstack.cleanup import resources from rally.plugins.openstack.scenarios.keystone import utils as kutils +from rally.plugins.openstack.scenarios.nova import utils as nutils from tests.unit import test BASE = "rally.plugins.openstack.cleanup.resources" @@ -116,6 +117,22 @@ class NovaFloatingIPsTestCase(test.TestCase): self.assertIsNone(fips.name()) +class NovaFlavorsTestCase(test.TestCase): + + @mock.patch("%s.base.ResourceManager._manager" % BASE) + @mock.patch("rally.common.utils.name_matches_object") + def test_list(self, mock_name_matches_object, + mock_resource_manager__manager): + flavors = [mock.MagicMock(name="rally_foo1"), + mock.MagicMock(name="rally_foo2"), + mock.MagicMock(name="foo3")] + mock_name_matches_object.side_effect = [False, True, True] + mock_resource_manager__manager().list.return_value = flavors + self.assertEqual(flavors[1:], resources.NovaFlavors().list()) + mock_name_matches_object.assert_has_calls( + [mock.call(r.name, nutils.NovaScenario) for r in flavors]) + + class NovaSecurityGroupTestCase(test.TestCase): @mock.patch("%s.base.ResourceManager._manager" % BASE) diff --git a/tests/unit/plugins/openstack/scenarios/nova/test_flavors.py b/tests/unit/plugins/openstack/scenarios/nova/test_flavors.py index aa3284d5..5367508d 100644 --- a/tests/unit/plugins/openstack/scenarios/nova/test_flavors.py +++ b/tests/unit/plugins/openstack/scenarios/nova/test_flavors.py @@ -13,12 +13,14 @@ # License for the specific language governing permissions and limitations # under the License. +import ddt import mock from rally.plugins.openstack.scenarios.nova import flavors from tests.unit import test +@ddt.ddt class NovaFlavorsTestCase(test.TestCase): def test_list_flavors(self): @@ -26,3 +28,29 @@ class NovaFlavorsTestCase(test.TestCase): scenario._list_flavors = mock.Mock() scenario.list_flavors(detailed=True, fakearg="fakearg") scenario._list_flavors.assert_called_once_with(True, fakearg="fakearg") + + @ddt.data({}, + {"is_public": True}, + {"is_public": False}, + {"fakeargs": "fakeargs"}, + {"is_public": False, "fakeargs": "fakeargs"}) + @ddt.unpack + def test_create_and_list_flavor_access(self, **kwargs): + scenario = flavors.NovaFlavors() + scenario._create_flavor = mock.Mock() + scenario._list_flavor_access = mock.Mock() + scenario.create_and_list_flavor_access(ram=100, vcpus=1, disk=1, + **kwargs) + kwargs.pop("is_public", None) + scenario._create_flavor.assert_called_once_with(100, 1, 1, + is_public=False, + **kwargs) + scenario._list_flavor_access.assert_called_once_with( + scenario._create_flavor.return_value.id) + + def test_create_flavor(self): + scenario = flavors.NovaFlavors() + scenario._create_flavor = mock.MagicMock() + scenario.create_flavor(ram=100, vcpus=1, disk=1, fakeargs="fakeargs") + scenario._create_flavor.assert_called_once_with(100, 1, 1, + fakeargs="fakeargs") diff --git a/tests/unit/plugins/openstack/scenarios/nova/test_utils.py b/tests/unit/plugins/openstack/scenarios/nova/test_utils.py index e8630804..f2148591 100644 --- a/tests/unit/plugins/openstack/scenarios/nova/test_utils.py +++ b/tests/unit/plugins/openstack/scenarios/nova/test_utils.py @@ -943,3 +943,29 @@ class NovaScenarioTestCase(test.ScenarioTestCase): host, binary) self._test_atomic_action_timer(nova_scenario.atomic_actions(), "nova.list_services") + + def test__list_flavor_access(self): + nova_scenario = utils.NovaScenario() + result = nova_scenario._list_flavor_access("foo_id") + self.assertEqual( + self.admin_clients("nova").flavor_access.list.return_value, + result) + self.admin_clients("nova").flavor_access.list.assert_called_once_with( + flavor="foo_id") + self._test_atomic_action_timer(nova_scenario.atomic_actions(), + "nova.list_flavor_access") + + def test__create_flavor(self): + nova_scenario = utils.NovaScenario() + random_name = "random_name" + nova_scenario.generate_random_name = mock.Mock( + return_value=random_name) + result = nova_scenario._create_flavor(500, 1, 1, + fakearg="fakearg") + self.assertEqual( + self.admin_clients("nova").flavors.create.return_value, + result) + self.admin_clients("nova").flavors.create.assert_called_once_with( + random_name, 500, 1, 1, fakearg="fakearg") + self._test_atomic_action_timer(nova_scenario.atomic_actions(), + "nova.create_flavor")