From 2352e8565e84543aa9715a2eae864a27192f4207 Mon Sep 17 00:00:00 2001 From: Kiran Date: Tue, 14 Jul 2015 20:05:10 +0530 Subject: [PATCH] Add Neutron LoadBalancer v1 create and list vips Enable benchmarking of the Neutron LoadBalancer v1 lb-vip-create and lb-vip-list APIs. Due to the different API scheme and confusing naming conventions in Neutron (LB is v1 API and LBaaS for v2 API) the appropriate code is explicitly marked with 'v1' since this only implements the API v1 benchmarking. Change-Id: I8a4f85bb62ae2a44be0a25d9a8327fd1ee48336b --- rally-jobs/rally-neutron.yaml | 23 ++++++++++++ .../context/quotas/neutron_quotas.py | 4 +++ .../scenarios/neutron/loadbalancer_v1.py | 28 +++++++++++++++ .../openstack/scenarios/neutron/utils.py | 21 +++++++++++ tests/unit/fakes.py | 22 ++++++++++++ .../scenarios/neutron/test_loadbalancer_v1.py | 33 +++++++++++++++++ .../openstack/scenarios/neutron/test_utils.py | 36 +++++++++++++++++++ 7 files changed, 167 insertions(+) diff --git a/rally-jobs/rally-neutron.yaml b/rally-jobs/rally-neutron.yaml index 486e302d..811cb75c 100644 --- a/rally-jobs/rally-neutron.yaml +++ b/rally-jobs/rally-neutron.yaml @@ -163,6 +163,29 @@ failure_rate: max: 0 + NeutronLoadbalancerV1.create_and_list_vips: + - + args: + vip_create_args: {} + runner: + type: "constant" + times: 20 + concurrency: 10 + context: + users: + tenants: 5 + users_per_tenant: 4 + network: {} + quotas: + neutron: + network: -1 + subnet: -1 + pool: -1 + vip: -1 + sla: + failure_rate: + max: 0 + NeutronNetworks.create_and_update_networks: - args: diff --git a/rally/plugins/openstack/context/quotas/neutron_quotas.py b/rally/plugins/openstack/context/quotas/neutron_quotas.py index ff91bc0a..0bdd38f6 100644 --- a/rally/plugins/openstack/context/quotas/neutron_quotas.py +++ b/rally/plugins/openstack/context/quotas/neutron_quotas.py @@ -56,6 +56,10 @@ class NeutronQuotas(object): "pool": { "type": "integer", "minimum": -1 + }, + "vip": { + "type": "integer", + "minimum": -1 } } } diff --git a/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py b/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py index 56a14a15..b11abbca 100644 --- a/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py +++ b/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py @@ -13,6 +13,7 @@ from rally import consts from rally.plugins.openstack import scenario from rally.plugins.openstack.scenarios.neutron import utils +from rally.task import atomic from rally.task import validation @@ -85,3 +86,30 @@ class NeutronLoadbalancerV1(utils.NeutronScenario): pools = self._create_v1_pools(networks, **pool_create_args) for pool in pools: self._update_v1_pool(pool, **pool_update_args) + + @validation.restricted_parameters(["pool_id", "subnet_id"], + subdict="vip_create_args") + @validation.required_neutron_extensions("lbaas") + @validation.required_services(consts.Service.NEUTRON) + @validation.required_openstack(admin=True) + @validation.required_contexts("network") + @scenario.configure(context={"cleanup": ["neutron"]}) + def create_and_list_vips(self, pool_create_args=None, + vip_create_args=None): + """Create a vip(v1) and then list vips(v1). + + Measure the "neutron lb-vip-create" and "neutron lb-vip-list" command + performance. The scenario creates a vip for every pool created and + then lists vips. + + :param vip_create_args: dict, POST /lb/vips request options + :param pool_create_args: dict, POST /lb/pools request options + """ + vip_create_args = vip_create_args or {} + pool_create_args = pool_create_args or {} + networks = self.context.get("tenant", {}).get("networks", []) + pools = self._create_v1_pools(networks, **pool_create_args) + with atomic.ActionTimer(self, "neutron.create_%s_vips" % len(pools)): + for pool in pools: + self._create_v1_vip(pool, **vip_create_args) + self._list_v1_vips() diff --git a/rally/plugins/openstack/scenarios/neutron/utils.py b/rally/plugins/openstack/scenarios/neutron/utils.py index 247a4d0a..8bf3a800 100644 --- a/rally/plugins/openstack/scenarios/neutron/utils.py +++ b/rally/plugins/openstack/scenarios/neutron/utils.py @@ -31,6 +31,7 @@ class NeutronScenario(scenario.OpenStackScenario): # TODO(rkiran): modify in case LBaaS-v2 requires LB_METHOD = "ROUND_ROBIN" LB_PROTOCOL = "HTTP" + LB_PROTOCOL_PORT = 80 def _warn_about_deprecated_name_kwarg(self, resource, kwargs): """Warn about use of a deprecated 'name' kwarg and replace it. @@ -347,3 +348,23 @@ class NeutronScenario(scenario.OpenStackScenario): self._warn_about_deprecated_name_kwarg(pool, pool_update_args) body = {"pool": pool_update_args} return self.clients("neutron").update_pool(pool["pool"]["id"], body) + + def _create_v1_vip(self, pool, **vip_create_args): + """Create VIP(v1) + + :parm pool: dict, neutron lb-pool + :parm vip_create_args: dict, POST /lb/vips request options + :returns: dict, neutron lb vip + """ + args = {"protocol": self.LB_PROTOCOL, + "protocol_port": self.LB_PROTOCOL_PORT, + "name": self._generate_random_name("rally_vip_"), + "pool_id": pool["pool"]["id"], + "subnet_id": pool["pool"]["subnet_id"]} + args.update(vip_create_args) + return self.clients("neutron").create_vip({"vip": args}) + + @atomic.action_timer("neutron.list_vips") + def _list_v1_vips(self, **kwargs): + """Return user lb vip list(v1).""" + return self.clients("neutron").list_vips(**kwargs) diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py index f5bbc339..72f8e5df 100644 --- a/tests/unit/fakes.py +++ b/tests/unit/fakes.py @@ -1035,6 +1035,7 @@ class FakeNeutronClient(object): self.__routers = {} self.__ports = {} self.__pools = {} + self.__vips = {} self.__tenant_id = kwargs.get("tenant_id", generate_uuid()) self.format = "json" @@ -1098,6 +1099,23 @@ class FakeNeutronClient(object): self.__pools[pool_id] = pool return {"pool": pool} + def create_vip(self, data): + vip = setup_dict(data["vip"], + required=["protocol_port", "protocol", "subnet_id", + "pool_id"], + defaults={"name": generate_name("vip_"), + "admin_state_up": True}) + if (vip["subnet_id"] not in self.__subnets) or (vip["pool_id"] not in + self.__pools): + raise neutron_exceptions.NeutronClientException + vip_id = generate_uuid() + + vip.update({"id": vip_id, + "status": "PENDING_CREATE", + "tenant_id": self.__tenant_id}) + self.__vips[vip_id] = vip + return {"vip": vip} + def create_port(self, data): port = setup_dict(data["port"], required=["network_id"], @@ -1234,6 +1252,10 @@ class FakeNeutronClient(object): pools = self._filter(self.__pools.values(), search_opts) return {"pools": pools} + def list_vips(self, **search_opts): + vips = self._filter(self.__vips.values(), search_opts) + return {"vips": vips} + def list_ports(self, **search_opts): ports = self._filter(self.__ports.values(), search_opts) return {"ports": ports} diff --git a/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py b/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py index 48005ed1..06c7412b 100644 --- a/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py +++ b/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py @@ -125,3 +125,36 @@ class NeutronLoadbalancerv1TestCase(test.TestCase): for pool in pools: neutron_scenario._update_v1_pool.assert_called_once_with( pool, **pool_update_args) + + @ddt.data( + {}, + {"vip_create_args": None}, + {"vip_create_args": {}}, + {"vip_create_args": {"name": "given-vip-name"}}, + {"pool_create_args": None}, + {"pool_create_args": {}}, + {"pool_create_args": {"name": "given-pool-name"}}, + ) + @ddt.unpack + def test_create_and_list_vips(self, pool_create_args=None, + vip_create_args=None): + neutron_scenario = loadbalancer_v1.NeutronLoadbalancerV1( + self._get_context()) + pools = [{ + "pool": { + "id": "pool-id" + } + }] + vip_data = vip_create_args or {} + pool_data = pool_create_args or {} + networks = self._get_context()["tenant"]["networks"] + neutron_scenario._create_v1_pools = mock.Mock(return_value=pools) + neutron_scenario._create_v1_vip = mock.Mock() + neutron_scenario._list_v1_vips = mock.Mock() + neutron_scenario.create_and_list_vips( + pool_create_args=pool_create_args, vip_create_args=vip_create_args) + neutron_scenario._create_v1_pools.assert_called_once_with( + networks, **pool_data) + neutron_scenario._create_v1_vip.assert_has_calls( + [mock.call(pool, **vip_data) for pool in pools]) + neutron_scenario._list_v1_vips.assert_called_once_with() diff --git a/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py b/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py index 7e7bfb69..6bbf6a05 100644 --- a/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py +++ b/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py @@ -476,6 +476,16 @@ class NeutronScenarioTestCase(test.ScenarioTestCase): self._test_atomic_action_timer(scenario.atomic_actions(), "neutron.list_pools") + def test_list_v1_vips(self): + scenario = utils.NeutronScenario() + vips_list = [] + vips_dict = {"vips": vips_list} + self.clients("neutron").list_vips.return_value = vips_dict + return_vips_dict = scenario._list_v1_vips() + self.assertEqual(vips_dict, return_vips_dict) + self._test_atomic_action_timer(scenario.atomic_actions(), + "neutron.list_vips") + class NeutronScenarioFunctionalTestCase(test.FakeClientsScenarioTestCase): @@ -572,3 +582,29 @@ class NeutronLoadbalancerScenarioTestCase(test.ScenarioTestCase): if atomic_action: self._test_atomic_action_timer( neutron_scenario.atomic_actions(), "neutron.create_pool") + + @ddt.data( + {}, + {"vip_create_args": {}}, + {"vip_create_args": {"name": "given-name"}}, + ) + @ddt.unpack + def test__create_v1_vip(self, vip_create_args=None): + neutron_scenario = utils.NeutronScenario() + vip = {"vip": {"id": "vip-id"}} + pool = {"pool": {"id": "pool-id", "subnet_id": "subnet-id"}} + vip_create_args = vip_create_args or {} + if vip_create_args.get("name") is None: + neutron_scenario._generate_random_name = mock.Mock( + return_value="random_name") + self.clients("neutron").create_vip.return_value = vip + args = {"protocol_port": 80, "protocol": "HTTP", "name": "random_name", + "subnet_id": pool["pool"]["subnet_id"], + "pool_id": pool["pool"]["id"]} + args.update(vip_create_args) + expected_vip_data = {"vip": args} + resultant_vip = neutron_scenario._create_v1_vip( + pool, **vip_create_args) + self.assertEqual(resultant_vip, vip) + self.clients("neutron").create_vip.assert_called_once_with( + expected_vip_data)