From cc00bd60ed0c5ea71e43cdda61dc9016194e22ed Mon Sep 17 00:00:00 2001 From: Winnie Tsang Date: Fri, 22 Apr 2016 18:19:17 +0000 Subject: [PATCH] [Magnum] Context and scenario for Magnum baymodel Context and scenario to create baymodel All Magnum scenarios will use some baymodels. This patch sets up the Rally context to create any baymodels needed by a scenario. All baymodels created will be cleaned up at the end of the job. A simple scenario is included to test a Magnum job in Rally. Currently the scenario only lists the baymodel created by the context, but later more user query type of actions can be added to similate a large user base interacting with Magnum. The job yaml file specifies the 3 bay types to be created by the context: Kubernetes, Swarm, Mesos. Partially-Implements: blueprint benchmark-scenarios-for-magnum Co-Authored-By: Ton Ngo Co-Authored-By: Spyros Trigazis Change-Id: I0979f2461c6e33c9163e19a6d7884fe1c7967e3f --- rally-jobs/rally-magnum.yaml | 49 +++++++++++++++ rally/plugins/openstack/cleanup/resources.py | 21 +++++++ .../openstack/context/magnum/__init__.py | 0 .../openstack/scenarios/magnum/__init__.py | 0 .../openstack/scenarios/magnum/utils.py | 50 ++++++++++++++++ tests/ci/osresources.py | 8 +++ tests/unit/fakes.py | 23 ++++++- .../openstack/cleanup/test_resources.py | 23 ++++++- .../openstack/context/magnum/__init__.py | 0 .../openstack/scenarios/magnum/__init__.py | 0 .../openstack/scenarios/magnum/test_utils.py | 60 +++++++++++++++++++ 11 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 rally-jobs/rally-magnum.yaml create mode 100644 rally/plugins/openstack/context/magnum/__init__.py create mode 100644 rally/plugins/openstack/scenarios/magnum/__init__.py create mode 100644 rally/plugins/openstack/scenarios/magnum/utils.py create mode 100644 tests/unit/plugins/openstack/context/magnum/__init__.py create mode 100644 tests/unit/plugins/openstack/scenarios/magnum/__init__.py create mode 100644 tests/unit/plugins/openstack/scenarios/magnum/test_utils.py diff --git a/rally-jobs/rally-magnum.yaml b/rally-jobs/rally-magnum.yaml new file mode 100644 index 00000000..77315e1c --- /dev/null +++ b/rally-jobs/rally-magnum.yaml @@ -0,0 +1,49 @@ +--- + MagnumBaymodels.list_baymodels: + - + runner: + type: "constant" + times: 40 + concurrency: 20 + context: + users: + tenants: 1 + users_per_tenant: 1 + baymodels: + image_id: "fedora-atomic-latest" + flavor_id: "m1.small" + master_flavor_id: "m1.small" + external_network_id: "public" + dns_nameserver: "8.8.8.8" + docker_volume_size: 5 + coe: "kubernetes" + network_driver: "flannel" + docker_storage_driver: "devicemapper" + master_lb_enabled: False + sla: + failure_rate: + max: 0 + + - + runner: + type: "constant" + times: 40 + concurrency: 20 + context: + users: + tenants: 1 + users_per_tenant: 1 + baymodels: + image_id: "fedora-atomic-latest" + flavor_id: "m1.small" + master_flavor_id: "m1.small" + external_network_id: "public" + dns_nameserver: "8.8.8.8" + docker_volume_size: 5 + coe: "swarm" + network_driver: "docker" + docker_storage_driver: "devicemapper" + master_lb_enabled: False + sla: + failure_rate: + max: 0 diff --git a/rally/plugins/openstack/cleanup/resources.py b/rally/plugins/openstack/cleanup/resources.py index fb43c33d..4234806a 100644 --- a/rally/plugins/openstack/cleanup/resources.py +++ b/rally/plugins/openstack/cleanup/resources.py @@ -66,6 +66,27 @@ class QuotaMixin(SynchronizedDeletion): return [self.tenant_uuid] if self.tenant_uuid else [] +# MAGNUM + +@base.resource("magnum", "baymodels", order=80, tenant_resource=True) +class MagnumBaymodel(base.ResourceManager): + + def id(self): + """Returns id of resource.""" + return self.raw_resource.uuid + + def list(self): + result = [] + marker = None + while True: + baymodels = self._manager().list(marker=marker) + if not baymodels: + break + result.extend(baymodels) + marker = baymodels[-1].uuid + return result + + # HEAT @base.resource("heat", "stacks", order=100, tenant_resource=True) diff --git a/rally/plugins/openstack/context/magnum/__init__.py b/rally/plugins/openstack/context/magnum/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rally/plugins/openstack/scenarios/magnum/__init__.py b/rally/plugins/openstack/scenarios/magnum/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rally/plugins/openstack/scenarios/magnum/utils.py b/rally/plugins/openstack/scenarios/magnum/utils.py new file mode 100644 index 00000000..d2f22ae9 --- /dev/null +++ b/rally/plugins/openstack/scenarios/magnum/utils.py @@ -0,0 +1,50 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from rally.plugins.openstack import scenario +from rally.task import atomic + + +class MagnumScenario(scenario.OpenStackScenario): + """Base class for Magnum scenarios with basic atomic actions.""" + + @atomic.action_timer("magnum.list_baymodels") + def _list_baymodels(self, **kwargs): + """Return list of baymodels. + + :param limit: (Optional) The maximum number of results to return + per request, if: + + 1) limit > 0, the maximum number of baymodels to return. + 2) limit param is NOT specified (None), the number of items + returned respect the maximum imposed by the Magnum API + (see Magnum's api.max_limit option). + :param kwargs: Optional additional arguments for baymodels listing + + :returns: baymodels list + """ + + return self.clients("magnum").baymodels.list(**kwargs) + + @atomic.action_timer("magnum.create_baymodel") + def _create_baymodel(self, **kwargs): + """Create a baymodel + + :param kwargs: optional additional arguments for baymodel creation + :returns: magnum baymodel + """ + + kwargs["name"] = self.generate_random_name() + + return self.clients("magnum").baymodels.create(**kwargs) diff --git a/tests/ci/osresources.py b/tests/ci/osresources.py index 73c5be92..a0981758 100755 --- a/tests/ci/osresources.py +++ b/tests/ci/osresources.py @@ -92,6 +92,14 @@ class Keystone(ResourceManager): return self.client.roles.list() +class Magnum(ResourceManager): + + REQUIRED_SERVICE = consts.Service.MAGNUM + + def list_baymodels(self): + return self.client.baymodels.list() + + class Nova(ResourceManager): REQUIRED_SERVICE = consts.Service.NOVA diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py index 0735bc23..4c195b6c 100644 --- a/tests/unit/fakes.py +++ b/tests/unit/fakes.py @@ -322,6 +322,10 @@ class FakeObject(FakeResource): pass +class FakeBaymodel(FakeResource): + pass + + class FakeManager(object): def __init__(self): @@ -514,6 +518,23 @@ class FakeKeypairManager(FakeManager): self.resources_order.remove(resource) +class FakeBaymodelManager(FakeManager): + + def create(self, name): + baymodel = FakeBaymodel(self) + baymodel.name = name or baymodel.name + return self._cache(baymodel) + + def delete(self, resource): + if not isinstance(resource, six.string_types): + resource = resource.id + + cached = self.get(resource) + if cached is not None: + del self.cache[resource] + self.resources_order.remove(resource) + + class FakeStackManager(FakeManager): def create(self, name): @@ -1512,7 +1533,7 @@ class FakeSenlinClient(object): class FakeMagnumClient(object): def __init__(self): - pass + self.baymodels = FakeBaymodelManager() class FakeWatcherClient(object): diff --git a/tests/unit/plugins/openstack/cleanup/test_resources.py b/tests/unit/plugins/openstack/cleanup/test_resources.py index be8cd735..37014498 100644 --- a/tests/unit/plugins/openstack/cleanup/test_resources.py +++ b/tests/unit/plugins/openstack/cleanup/test_resources.py @@ -65,6 +65,27 @@ class QuotaMixinTestCase(test.TestCase): self.assertEqual([quota.tenant_uuid], quota.list()) +class MagnumBaymodelTestCase(test.TestCase): + + def test_id(self): + baymodel = resources.MagnumBaymodel() + baymodel.raw_resource = mock.MagicMock() + self.assertEqual(baymodel.raw_resource.uuid, baymodel.id()) + + def test_list(self): + baymodels = [mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), + mock.MagicMock()] + baymodel = resources.MagnumBaymodel() + baymodel._manager = mock.MagicMock() + baymodel._manager.return_value.list.side_effect = ( + baymodels[:2], baymodels[2:4], []) + self.assertEqual(baymodels, baymodel.list()) + self.assertEqual( + [mock.call(marker=None), mock.call(marker=baymodels[1].uuid), + mock.call(marker=baymodels[3].uuid)], + baymodel._manager.return_value.list.call_args_list) + + class NovaServerTestCase(test.TestCase): def test_list(self): @@ -879,4 +900,4 @@ class WatcherActionPlanTestCase(test.TestCase): watcher.list() self.assertEqual("action_plan", watcher._resource) - watcher._manager().list.assert_called_once_with(limit=0) \ No newline at end of file + watcher._manager().list.assert_called_once_with(limit=0) diff --git a/tests/unit/plugins/openstack/context/magnum/__init__.py b/tests/unit/plugins/openstack/context/magnum/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/plugins/openstack/scenarios/magnum/__init__.py b/tests/unit/plugins/openstack/scenarios/magnum/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/plugins/openstack/scenarios/magnum/test_utils.py b/tests/unit/plugins/openstack/scenarios/magnum/test_utils.py new file mode 100644 index 00000000..747a1edd --- /dev/null +++ b/tests/unit/plugins/openstack/scenarios/magnum/test_utils.py @@ -0,0 +1,60 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock + +from rally.plugins.openstack.scenarios.magnum import utils +from tests.unit import test + + +class MagnumScenarioTestCase(test.ScenarioTestCase): + def setUp(self): + super(MagnumScenarioTestCase, self).setUp() + self.baymodel = mock.Mock() + self.scenario = utils.MagnumScenario(self.context) + + def test_list_baymodels(self): + scenario = utils.MagnumScenario(self.context) + fake_baymodel_list = [self.baymodel] + + self.clients("magnum").baymodels.list.return_value = fake_baymodel_list + return_baymodels_list = scenario._list_baymodels() + self.assertEqual(fake_baymodel_list, return_baymodels_list) + + self.clients("magnum").baymodels.list.assert_called_once_with() + self._test_atomic_action_timer(scenario.atomic_actions(), + "magnum.list_baymodels") + + def test_create_baymodel(self): + self.scenario.generate_random_name = mock.Mock( + return_value="generated_name") + fake_baymodel = self.baymodel + self.clients("magnum").baymodels.create.return_value = fake_baymodel + + return_baymodel = self.scenario._create_baymodel( + image="test_image", + keypair="test_key", + external_network="public", + dns_nameserver="8.8.8.8", + flavor="m1.large", + docker_volume_size=50, + network_driver="docker", + coe="swarm") + + self.assertEqual(fake_baymodel, return_baymodel) + args, kwargs = self.clients("magnum").baymodels.create.call_args + self.assertEqual("generated_name", kwargs["name"]) + + self._test_atomic_action_timer(self.scenario.atomic_actions(), + "magnum.create_baymodel")