diff --git a/rally-jobs/rally-neutron.yaml b/rally-jobs/rally-neutron.yaml index f6ab538a35..75a0b7e571 100644 --- a/rally-jobs/rally-neutron.yaml +++ b/rally-jobs/rally-neutron.yaml @@ -115,6 +115,28 @@ failure_rate: max: 0 + NeutronLoadbalancerV1.create_and_delete_pools: + - + args: + pool_create_args: {} + runner: + type: "constant" + times: {{smoke or 20}} + concurrency: 10 + context: + users: + tenants: 1 + users_per_tenant: 1 + network: {} + quotas: + neutron: + network: -1 + subnet: -1 + pool: -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 a0de8426d6..4c53c547d9 100644 --- a/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py +++ b/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py @@ -36,3 +36,26 @@ class NeutronLoadbalancerV1(utils.NeutronScenario): for subnet_id in net["subnets"]: self._create_v1_pool(subnet_id, **pool_create_args) self._list_v1_pools() + + @validation.restricted_parameters("subnet_id", subdict="pool_create_args") + @validation.required_services(consts.Service.NEUTRON) + @validation.required_openstack(users=True) + @validation.required_contexts("network") + @base.scenario(context={"cleanup": ["neutron"]}) + def create_and_delete_pools(self, pool_create_args=None): + """Create pools(v1) and delete pools(v1). + + Measure the "neutron lb-pool-create" and "neutron lb-pool-delete" + command performance. The scenario creates a pool for every subnet + and then deletes those pools. + + :param pool_create_args: dict, POST /lb/pools request options + """ + pools = [] + pool_create_args = pool_create_args or {} + for net in self.context.get("tenant", {}).get("networks", []): + for subnet_id in net["subnets"]: + pools.append(self._create_v1_pool(subnet_id=subnet_id, + **pool_create_args)) + for pool in pools: + self._delete_v1_pool(pool["pool"]) diff --git a/rally/plugins/openstack/scenarios/neutron/utils.py b/rally/plugins/openstack/scenarios/neutron/utils.py index ef5f595186..ee49582eaa 100644 --- a/rally/plugins/openstack/scenarios/neutron/utils.py +++ b/rally/plugins/openstack/scenarios/neutron/utils.py @@ -309,3 +309,11 @@ class NeutronScenario(base.Scenario): def _list_v1_pools(self, **kwargs): """Return user lb pool list(v1).""" return self.clients("neutron").list_pools() + + @base.atomic_action_timer("neutron.delete_pool") + def _delete_v1_pool(self, pool): + """Delete neutron pool. + + :param pool: Pool object + """ + self.clients("neutron").delete_pool(pool["id"]) diff --git a/samples/tasks/scenarios/neutron/create_and_delete_pools.json b/samples/tasks/scenarios/neutron/create_and_delete_pools.json new file mode 100644 index 0000000000..f07f888759 --- /dev/null +++ b/samples/tasks/scenarios/neutron/create_and_delete_pools.json @@ -0,0 +1,28 @@ +{ + "NeutronLoadbalancerV1.create_and_delete_pools": [ + { + "args": { + "pool_create_args":{} + }, + "runner": { + "type": "constant", + "times": 100, + "concurrency": 10 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + }, + "network":{}, + "quotas": { + "neutron": { + "network": -1, + "subnet": -1, + "pool": -1 + } + } + } + } + ] +} diff --git a/samples/tasks/scenarios/neutron/create_and_delete_pools.yaml b/samples/tasks/scenarios/neutron/create_and_delete_pools.yaml new file mode 100644 index 0000000000..cd6c48276d --- /dev/null +++ b/samples/tasks/scenarios/neutron/create_and_delete_pools.yaml @@ -0,0 +1,19 @@ +--- + NeutronLoadbalancerV1.create_and_delete_pools: + - + args: + pool_create_args: {} + runner: + type: "constant" + times: 100 + concurrency: 10 + context: + users: + tenants: 1 + users_per_tenant: 1 + network: {} + quotas: + neutron: + network: -1 + subnet: -1 + pool: -1 diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py index d88d1a116c..0dc567f3db 100644 --- a/tests/unit/fakes.py +++ b/tests/unit/fakes.py @@ -1220,6 +1220,12 @@ class FakeNeutronClient(object): del self.__networks[network_id] return "" + def delete_pool(self, pool_id): + if pool_id not in self.__pools: + raise neutron_exceptions.NeutronClientException + del self.__pools[pool_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 c88997bbe3..2e6686cf21 100644 --- a/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py +++ b/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py @@ -25,7 +25,7 @@ class NeutronLoadbalancerv1TestCase(test.TestCase): "networks": [{"id": "fake_net", "subnets": ["fake_subnet"]}]}} - def _validate_scenario(self, pool_create_args): + def _validate_create_and_list_pools_scenario(self, pool_create_args): neutron_scenario = loadbalancer_v1.NeutronLoadbalancerV1( self._get_context()) neutron_scenario._create_v1_pool = mock.Mock() @@ -38,8 +38,37 @@ class NeutronLoadbalancerv1TestCase(test.TestCase): subnet_id, **pool_create_args) neutron_scenario._list_v1_pools.assert_called_once_with() + def _validate_create_and_delete_pools_scenario(self, pool_create_args): + neutron_scenario = loadbalancer_v1.NeutronLoadbalancerV1( + self._get_context()) + pool = { + "pool": { + "id": "pool-id" + } + } + neutron_scenario._create_v1_pool = mock.Mock(return_value=pool) + neutron_scenario._delete_v1_pool = mock.Mock() + neutron_scenario.create_and_delete_pools( + pool_create_args=pool_create_args) + pools = [] + for net in self._get_context()["tenant"]["networks"]: + for subnet_id in net["subnets"]: + self.assertEqual([mock.call(subnet_id=subnet_id, + **pool_create_args)], + neutron_scenario._create_v1_pool.mock_calls) + for pool in pools: + self.assertEqual(1, neutron_scenario._delete_v1_pool.call_count) + def test_create_and_list_pools_default(self): - self._validate_scenario(pool_create_args={}) + self._validate_create_and_list_pools_scenario(pool_create_args={}) def test_create_and_list_pools_explicit(self): - self._validate_scenario(pool_create_args={"name": "given-name"}) + self._validate_create_and_list_pools_scenario( + pool_create_args={"name": "given-name"}) + + def test_create_and_delete_pools_default(self): + self._validate_create_and_delete_pools_scenario(pool_create_args={}) + + def test_create_and_delete_pools_explicit(self): + self._validate_create_and_delete_pools_scenario( + pool_create_args={"name": "given-name"}) diff --git a/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py b/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py index 032bdcb7bd..18e97f00e1 100644 --- a/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py +++ b/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py @@ -431,6 +431,16 @@ class NeutronScenarioTestCase(test.ClientsTestCase): self._test_atomic_action_timer( neutron_scenario.atomic_actions(), "neutron.create_pool") + def test_delete_v1_pool(self): + scenario = utils.NeutronScenario() + + pool = {"pool": {"id": "fake-id"}} + scenario._delete_v1_pool(pool["pool"]) + self.clients("neutron").delete_pool.assert_called_once_with( + pool["pool"]["id"]) + self._test_atomic_action_timer(scenario.atomic_actions(), + "neutron.delete_pool") + def test_list_v1_pools(self): scenario = utils.NeutronScenario() pools_list = []