diff --git a/rally-jobs/rally-neutron.yaml b/rally-jobs/rally-neutron.yaml index 811cb75c..11747d54 100644 --- a/rally-jobs/rally-neutron.yaml +++ b/rally-jobs/rally-neutron.yaml @@ -186,6 +186,32 @@ failure_rate: max: 0 + NeutronLoadbalancerV1.create_and_delete_vips: + - + args: + vip_create_args: {} + runner: + type: "constant" + times: 2 + concurrency: 1 + context: + users: + tenants: 1 + users_per_tenant: 1 + network: {} + lbaas: + pool: {} + lbaas_version: 1 + 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/scenarios/neutron/loadbalancer_v1.py b/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py index b11abbca..fad34f79 100644 --- a/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py +++ b/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py @@ -113,3 +113,31 @@ class NeutronLoadbalancerV1(utils.NeutronScenario): for pool in pools: self._create_v1_vip(pool, **vip_create_args) self._list_v1_vips() + + @validation.restricted_parameters(["pool_id", "subnet_id"], + subdict="vip_create_args") + @validation.required_services(consts.Service.NEUTRON) + @validation.required_openstack(users=True) + @validation.required_contexts("network") + @validation.required_contexts("lbaas") + @scenario.configure(context={"cleanup": ["neutron"]}) + def create_and_delete_vips(self, vip_create_args=None): + """Create a vip(v1) and then delete vips(v1). + + Measure the "neutron lb-vip-create" and "neutron lb-vip-delete" + command performance. The scenario creates a vip for pool and + then deletes those vips. + + :param vip_create_args: dict, POST /lb/vips request options + """ + vips = [] + pools = [] + vip_create_args = vip_create_args or {} + networks = self.context.get("tenant", {}).get("networks", []) + for net in networks: + [pools.append(pool) for pool in net.get("lb_pools")] + with atomic.ActionTimer(self, "neutron.create_%s_vips" % len(pools)): + for pool in pools: + vips.append(self._create_v1_vip(pool, **vip_create_args)) + for vip in vips: + self._delete_v1_vip(vip["vip"]) diff --git a/rally/plugins/openstack/scenarios/neutron/utils.py b/rally/plugins/openstack/scenarios/neutron/utils.py index 8bf3a800..33e2c200 100644 --- a/rally/plugins/openstack/scenarios/neutron/utils.py +++ b/rally/plugins/openstack/scenarios/neutron/utils.py @@ -368,3 +368,11 @@ class NeutronScenario(scenario.OpenStackScenario): def _list_v1_vips(self, **kwargs): """Return user lb vip list(v1).""" return self.clients("neutron").list_vips(**kwargs) + + @atomic.action_timer("neutron.delete_vip") + def _delete_v1_vip(self, vip): + """Delete neutron vip. + + :param vip: neutron Virtual IP object + """ + self.clients("neutron").delete_vip(vip["id"]) diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py index 72f8e5df..12f6f097 100644 --- a/tests/unit/fakes.py +++ b/tests/unit/fakes.py @@ -1214,6 +1214,12 @@ class FakeNeutronClient(object): del self.__pools[pool_id] return "" + def delete_vip(self, vip_id): + if vip_id not in self.__vips: + raise neutron_exceptions.NeutronClientException + del self.__vips[vip_id] + return "" + def delete_port(self, port_id): if port_id not in self.__ports: raise neutron_exceptions.PortNotFoundClient 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 06c7412b..42178dcf 100644 --- a/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py +++ b/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py @@ -31,6 +31,12 @@ class NeutronLoadbalancerv1TestCase(test.TestCase): "networks": [{"id": "fake_net", "subnets": ["fake_subnet"]}]}} + def _get_context_pools(self): + context = self._get_context() + for network in context["tenant"]["networks"]: + network.update({"lb_pools": [{"pool": {"id": "pool-id"}}]}) + return context + @ddt.data( {}, {"pool_create_args": None}, @@ -158,3 +164,29 @@ class NeutronLoadbalancerv1TestCase(test.TestCase): 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() + + @ddt.data( + {}, + {"vip_create_args": None}, + {"vip_create_args": {}}, + {"vip_create_args": {"name": "given-name"}}, + ) + @ddt.unpack + def test_create_and_delete_vips(self, vip_create_args=None): + vip = { + "vip": { + "id": "vip-id" + } + } + neutron_scenario = loadbalancer_v1.NeutronLoadbalancerV1( + self._get_context_pools()) + vip_data = vip_create_args or {} + neutron_scenario._create_v1_vip = mock.Mock(return_value=vip) + neutron_scenario._delete_v1_vip = mock.Mock() + neutron_scenario.create_and_delete_vips( + vip_create_args=vip_create_args) + for net in self._get_context_pools()["tenant"]["networks"]: + neutron_scenario._create_v1_vip.assert_has_calls( + [mock.call(pool, **vip_data) for pool in net["lb_pools"]]) + neutron_scenario._delete_v1_vip.assert_has_calls( + [mock.call(vip["vip"])]) diff --git a/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py b/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py index 6bbf6a05..5c784c8f 100644 --- a/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py +++ b/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py @@ -486,6 +486,16 @@ class NeutronScenarioTestCase(test.ScenarioTestCase): self._test_atomic_action_timer(scenario.atomic_actions(), "neutron.list_vips") + def test_delete_v1_vip(self): + scenario = utils.NeutronScenario() + + vip = {"vip": {"id": "fake-id"}} + scenario._delete_v1_vip(vip["vip"]) + self.clients("neutron").delete_vip.assert_called_once_with( + vip["vip"]["id"]) + self._test_atomic_action_timer(scenario.atomic_actions(), + "neutron.delete_vip") + class NeutronScenarioFunctionalTestCase(test.FakeClientsScenarioTestCase):