From b1a1fdcbb70c4e78eeb5fe32d8c363d9fca97ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Savignan?= Date: Wed, 7 Jun 2017 17:27:24 +0200 Subject: [PATCH] Add router in context Scenarios will be able to call router in user context as the network resource. Change-Id: I0e7d4fbcc108d5a5c2f681a844d874c40737630f --- .../openstack/context/network/routers.py | 118 ++++++++++++++++++ samples/tasks/contexts/router.json | 40 ++++++ samples/tasks/contexts/router.yaml | 27 ++++ .../openstack/context/network/test_routers.py | 98 +++++++++++++++ 4 files changed, 283 insertions(+) create mode 100644 rally/plugins/openstack/context/network/routers.py create mode 100644 samples/tasks/contexts/router.json create mode 100644 samples/tasks/contexts/router.yaml create mode 100644 tests/unit/plugins/openstack/context/network/test_routers.py diff --git a/rally/plugins/openstack/context/network/routers.py b/rally/plugins/openstack/context/network/routers.py new file mode 100644 index 00000000..ead8b7a9 --- /dev/null +++ b/rally/plugins/openstack/context/network/routers.py @@ -0,0 +1,118 @@ +# Copyright 2017: Orange +# 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.common.i18n import _ +from rally.common import logging +from rally.common import utils +from rally.common import validation +from rally import consts +from rally.plugins.openstack.cleanup import manager as resource_manager +from rally.plugins.openstack.scenarios.neutron import utils as neutron_utils +from rally.task import context + + +LOG = logging.getLogger(__name__) + + +@validation.add("required_platform", platform="openstack", admin=True, + users=True) +@context.configure(name="router", order=351) +class Router(context.Context): + """Create networking resources. + + This creates router for all tenants. + """ + + CONFIG_SCHEMA = { + "type": "object", + "$schema": consts.JSON_SCHEMA, + "properties": { + "routers_per_tenant": { + "type": "integer", + "minimum": 1 + }, + "admin_state_up ": { + "description": "A human-readable description for the resource", + "type": "boolean", + }, + "external_gateway_info": { + "description": "The external gateway information .", + "type": "object", + "properties": { + "network_id": {"type": "string"}, + "enable_snat": {"type": "boolean"} + } + }, + "network_id": { + "description": "Network ID", + "type": "string" + }, + "external_fixed_ips": { + "description": "Ip(s) of the external gateway interface.", + "type": "array", + "items": { + "type": "object", + "properties": { + "ip_address": {"type": "string"}, + "subnet_id": {"type": "string"} + } + } + }, + "distributed": { + "description": "Distributed router. Require dvr extension.", + "type": "boolean" + }, + "ha": { + "description": "Highly-available router. Require l3-ha.", + "type": "boolean" + }, + "availability_zone_hints": { + "description": "Require router_availability_zone extension.", + "type": "boolean" + } + }, + "additionalProperties": False + } + + DEFAULT_CONFIG = { + "routers_per_tenant": 1, + } + + @logging.log_task_wrapper(LOG.info, _("Enter context: `router`")) + def setup(self): + kwargs = {} + parameters = ("admin_state_up", "external_gateway_info", "network_id", + "external_fixed_ips", "distributed", "ha", + "availability_zone_hints") + for parameter in parameters: + if parameter in self.config: + kwargs[parameter] = self.config[parameter] + for user, tenant_id in (utils.iterate_per_tenants( + self.context.get("users", []))): + self.context["tenants"][tenant_id]["routers"] = [] + scenario = neutron_utils.NeutronScenario( + context={"user": user, "task": self.context["task"]} + ) + for i in range(self.config["routers_per_tenant"]): + router = scenario._create_router(kwargs) + self.context["tenants"][tenant_id]["routers"].append(router) + + @logging.log_task_wrapper(LOG.info, _("Exit context: `router`")) + def cleanup(self): + resource_manager.cleanup( + names=["neutron.router"], + users=self.context.get("users", []), + superclass=neutron_utils.NeutronScenario, + task_id=self.get_owner_id()) diff --git a/samples/tasks/contexts/router.json b/samples/tasks/contexts/router.json new file mode 100644 index 00000000..b9b83e89 --- /dev/null +++ b/samples/tasks/contexts/router.json @@ -0,0 +1,40 @@ +{ + "Dummy.openstack": [ + { + "args": { + "sleep": 0.1 + }, + "runner": { + "type": "constant", + "times": 4, + "concurrency": 2 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 2 + }, + "router": {} + } + }, + { + "args": { + "sleep": 0.1 + }, + "runner": { + "type": "constant", + "times": 4, + "concurrency": 2 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 2 + }, + "router": { + "routers_per_tenant": 1 + } + } + } + ] +} diff --git a/samples/tasks/contexts/router.yaml b/samples/tasks/contexts/router.yaml new file mode 100644 index 00000000..436cfa83 --- /dev/null +++ b/samples/tasks/contexts/router.yaml @@ -0,0 +1,27 @@ +--- + Dummy.openstack: + - + args: + sleep: 0.1 + runner: + type: "constant" + times: 4 + concurrency: 2 + context: + users: + tenants: 1 + users_per_tenant: 2 + router: {} + - + args: + sleep: 0.1 + runner: + type: "constant" + times: 4 + concurrency: 2 + context: + users: + tenants: 1 + users_per_tenant: 2 + router: + routers_per_tenant: 1 diff --git a/tests/unit/plugins/openstack/context/network/test_routers.py b/tests/unit/plugins/openstack/context/network/test_routers.py new file mode 100644 index 00000000..fec83b36 --- /dev/null +++ b/tests/unit/plugins/openstack/context/network/test_routers.py @@ -0,0 +1,98 @@ +# Copyright 2017: Orange +# 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 copy +import mock + +from rally.plugins.openstack.context.network import routers as router_context +from rally.plugins.openstack.scenarios.neutron import utils as neutron_utils + +from tests.unit import test + +SCN = "rally.plugins.openstack.scenarios" +CTX = "rally.plugins.openstack.context.network.routers" + + +class RouterTestCase(test.ScenarioTestCase): + + def _gen_tenants(self, count): + tenants = {} + for id_ in range(count): + tenants[str(id_)] = {"name": str(id_)} + return tenants + + def test__init__default(self): + self.context.update({ + "config": { + "router": { + "routers_per_tenant": 1, + } + } + }) + context = router_context.Router(self.context) + self.assertEqual(context.config["routers_per_tenant"], 1) + + @mock.patch("%s.neutron.utils.NeutronScenario._create_router" % SCN, + return_value={"id": "uuid"}) + def test_setup(self, mock_neutron_scenario__create_router): + tenants_count = 2 + users_per_tenant = 3 + routers_per_tenant = 2 + + tenants = self._gen_tenants(tenants_count) + users = [] + for id_ in tenants.keys(): + for i in range(users_per_tenant): + users.append({"id": i, "tenant_id": id_, + "credential": mock.MagicMock()}) + + self.context.update({ + "config": { + "users": { + "tenants": 2, + "users_per_tenant": 3, + "concurrent": 2, + }, + "router": { + "routers_per_tenant": routers_per_tenant, + } + }, + "admin": { + "credential": mock.MagicMock() + }, + "users": users, + "tenants": tenants + }) + + new_context = copy.deepcopy(self.context) + for id_ in tenants.keys(): + new_context["tenants"][id_].setdefault("routers", []) + for i in range(routers_per_tenant): + new_context["tenants"][id_]["routers"].append({"id": "uuid"}) + + routers_ctx = router_context.Router(self.context) + routers_ctx.setup() + self.assertEqual(new_context, self.context) + + @mock.patch("%s.resource_manager.cleanup" % CTX) + def test_cleanup(self, mock_cleanup): + self.context.update({"users": mock.MagicMock()}) + routers_ctx = router_context.Router(self.context) + routers_ctx.cleanup() + mock_cleanup.assert_called_once_with( + names=["neutron.router"], + users=self.context["users"], + superclass=neutron_utils.NeutronScenario, + task_id=self.context["owner_id"])