diff --git a/rally-jobs/rally-neutron.yaml b/rally-jobs/rally-neutron.yaml index 11747d54..43269462 100644 --- a/rally-jobs/rally-neutron.yaml +++ b/rally-jobs/rally-neutron.yaml @@ -212,6 +212,31 @@ failure_rate: max: 0 + NeutronLoadbalancerV1.create_and_update_vips: + - + args: + vip_create_args: {} + vip_update_args: {} + pool_create_args: {} + runner: + type: "constant" + times: 20 + concurrency: 10 + context: + users: + tenants: 4 + users_per_tenant: 5 + 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/scenarios/neutron/loadbalancer_v1.py b/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py index fad34f79..db11cb0b 100644 --- a/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py +++ b/rally/plugins/openstack/scenarios/neutron/loadbalancer_v1.py @@ -141,3 +141,34 @@ class NeutronLoadbalancerV1(utils.NeutronScenario): vips.append(self._create_v1_vip(pool, **vip_create_args)) for vip in vips: self._delete_v1_vip(vip["vip"]) + + @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") + @scenario.configure(context={"cleanup": ["neutron"]}) + def create_and_update_vips(self, pool_create_args=None, + vip_update_args=None, + vip_create_args=None): + """Create vips(v1) and update vips(v1). + + Measure the "neutron lb-vip-create" and "neutron lb-vip-update" + command performance. The scenario creates a pool for every subnet + and then update those pools. + + :param pool_create_args: dict, POST /lb/pools request options + :param vip_create_args: dict, POST /lb/vips request options + :param vip_update_args: dict, POST /lb/vips update options + """ + vips = [] + pool_create_args = pool_create_args or {} + vip_create_args = vip_create_args or {} + vip_update_args = vip_update_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: + vips.append(self._create_v1_vip(pool, **vip_create_args)) + for vip in vips: + self._update_v1_vip(vip, **vip_update_args) diff --git a/rally/plugins/openstack/scenarios/neutron/utils.py b/rally/plugins/openstack/scenarios/neutron/utils.py index 33e2c200..0e58041f 100644 --- a/rally/plugins/openstack/scenarios/neutron/utils.py +++ b/rally/plugins/openstack/scenarios/neutron/utils.py @@ -376,3 +376,17 @@ class NeutronScenario(scenario.OpenStackScenario): :param vip: neutron Virtual IP object """ self.clients("neutron").delete_vip(vip["id"]) + + @atomic.action_timer("neutron.update_vip") + def _update_v1_vip(self, vip, **vip_update_args): + """Updates vip. + + This atomic function updates vip name and admin state + + :param vip: Vip object + :param vip_update_args: dict, POST /lb/vips update options + :returns: updated neutron vip dict + """ + self._warn_about_deprecated_name_kwarg(vip, vip_update_args) + body = {"vip": vip_update_args} + return self.clients("neutron").update_vip(vip["vip"]["id"], body) diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py index 12f6f097..fced5e99 100644 --- a/tests/unit/fakes.py +++ b/tests/unit/fakes.py @@ -1189,6 +1189,9 @@ class FakeNeutronClient(object): def update_pool(self, pool_id, data): self.update_resource(pool_id, self.__pools, data) + def update_vip(self, vip_id, data): + self.update_resource(vip_id, self.__vips, data) + def update_subnet(self, subnet_id, data): self.update_resource(subnet_id, self.__subnets, data) 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 42178dcf..a1296262 100644 --- a/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py +++ b/tests/unit/plugins/openstack/scenarios/neutron/test_loadbalancer_v1.py @@ -190,3 +190,53 @@ class NeutronLoadbalancerv1TestCase(test.TestCase): [mock.call(pool, **vip_data) for pool in net["lb_pools"]]) neutron_scenario._delete_v1_vip.assert_has_calls( [mock.call(vip["vip"])]) + + @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_update_vips(self, pool_create_args=None, + vip_create_args=None, + vip_update_args=None): + neutron_scenario = loadbalancer_v1.NeutronLoadbalancerV1( + self._get_context()) + pools = [{ + "pool": { + "id": "pool-id", + } + }] + expected_vip = { + "vip": { + "id": "vip-id", + "name": "vip-name" + } + } + updated_vip = { + "vip": { + "id": "vip-id", + "name": "updated-vip-name" + } + } + vips = [expected_vip] + vip_data = vip_create_args or {} + vip_update_data = vip_update_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(return_value=expected_vip) + neutron_scenario._update_v1_vip = mock.Mock(return_value=updated_vip) + neutron_scenario.create_and_update_vips( + pool_create_args=pool_create_args, vip_create_args=vip_create_args, + vip_update_args=vip_update_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._update_v1_vip.assert_has_calls( + [mock.call(vip, **vip_update_data) for vip in vips]) diff --git a/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py b/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py index 5c784c8f..38102a29 100644 --- a/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py +++ b/tests/unit/plugins/openstack/scenarios/neutron/test_utils.py @@ -496,6 +496,27 @@ class NeutronScenarioTestCase(test.ScenarioTestCase): self._test_atomic_action_timer(scenario.atomic_actions(), "neutron.delete_vip") + def test_update_v1_vip(self): + scenario = utils.NeutronScenario() + scenario._generate_random_name = mock.Mock(return_value="random_name") + expected_vip = { + "vip": { + "name": scenario._generate_random_name.return_value, + "admin_state_up": False + } + } + self.clients("neutron").update_vip.return_value = expected_vip + + vip = {"vip": {"name": "vip-name", "id": "vip-id"}} + vip_update_args = {"name": "foo", "admin_state_up": False} + + result_vip = scenario._update_v1_vip(vip, **vip_update_args) + self.assertEqual(result_vip, expected_vip) + self.clients("neutron").update_vip.assert_called_once_with( + vip["vip"]["id"], expected_vip) + self._test_atomic_action_timer(scenario.atomic_actions(), + "neutron.update_vip") + class NeutronScenarioFunctionalTestCase(test.FakeClientsScenarioTestCase):