Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 1 | # Copyright (c) 2019 Ericsson |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 4 | # not use this file except in compliance with the License. You may obtain |
| 5 | # a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 12 | # License for the specific language governing permissions and limitations |
| 13 | # under the License. |
| 14 | |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 15 | import testtools |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 16 | |
| 17 | from tempest.common import utils |
| 18 | from tempest.common import waiters |
| 19 | from tempest import config |
| 20 | from tempest.lib.common.utils import data_utils |
| 21 | from tempest.lib.common.utils import test_utils |
| 22 | from tempest.lib import decorators |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 23 | from tempest.lib import exceptions as lib_exc |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 24 | from tempest.scenario import manager |
| 25 | |
| 26 | |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 27 | CONF = config.CONF |
| 28 | |
| 29 | |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 30 | class NetworkQoSPlacementTestBase(manager.NetworkScenarioTest): |
| 31 | """Base class for Network QoS testing |
| 32 | |
| 33 | Base class for testing Network QoS scenarios involving placement |
| 34 | resource allocations. |
| 35 | """ |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 36 | credentials = ['primary', 'admin'] |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 37 | # The feature QoS minimum bandwidth allocation in Placement API depends on |
| 38 | # Granular resource requests to GET /allocation_candidates and Support |
| 39 | # allocation candidates with nested resource providers features in |
| 40 | # Placement (see: https://specs.openstack.org/openstack/nova-specs/specs/ |
| 41 | # stein/approved/bandwidth-resource-provider.html#rest-api-impact) and this |
| 42 | # means that the minimum placement microversion is 1.29 |
| 43 | placement_min_microversion = '1.29' |
| 44 | placement_max_microversion = 'latest' |
| 45 | |
| 46 | # Nova rejects to boot VM with port which has resource_request field, below |
| 47 | # microversion 2.72 |
| 48 | compute_min_microversion = '2.72' |
| 49 | compute_max_microversion = 'latest' |
| 50 | |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 51 | INGRESS_DIRECTION = 'ingress' |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 52 | BW_RESOURCE_CLASS = "NET_BW_IGR_KILOBIT_PER_SEC" |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 53 | |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 54 | # For any realistic inventory value (that is inventory != MAX_INT) an |
| 55 | # allocation candidate request of MAX_INT is expected to be rejected, see: |
| 56 | # https://github.com/openstack/placement/blob/master/placement/ |
| 57 | # db/constants.py#L16 |
| 58 | PLACEMENT_MAX_INT = 0x7FFFFFFF |
| 59 | |
| 60 | @classmethod |
| 61 | def setup_clients(cls): |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 62 | super().setup_clients() |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 63 | cls.placement_client = cls.os_admin.placement_client |
| 64 | cls.networks_client = cls.os_admin.networks_client |
| 65 | cls.subnets_client = cls.os_admin.subnets_client |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 66 | cls.ports_client = cls.os_primary.ports_client |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 67 | cls.routers_client = cls.os_adm.routers_client |
| 68 | cls.qos_client = cls.os_admin.qos_client |
| 69 | cls.qos_min_bw_client = cls.os_admin.qos_min_bw_client |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 70 | cls.flavors_client = cls.os_adm.flavors_client |
Balazs Gibizer | 18accde | 2021-09-29 16:10:49 +0200 | [diff] [blame] | 71 | cls.servers_client = cls.os_primary.servers_client |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 72 | |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 73 | def _create_flavor_to_resize_to(self): |
| 74 | old_flavor = self.flavors_client.show_flavor( |
| 75 | CONF.compute.flavor_ref)['flavor'] |
| 76 | new_flavor = self.flavors_client.create_flavor(**{ |
| 77 | 'ram': old_flavor['ram'], |
| 78 | 'vcpus': old_flavor['vcpus'], |
| 79 | 'name': old_flavor['name'] + 'extra', |
| 80 | 'disk': old_flavor['disk'] + 1 |
| 81 | })['flavor'] |
| 82 | self.addCleanup(test_utils.call_and_ignore_notfound_exc, |
| 83 | self.flavors_client.delete_flavor, new_flavor['id']) |
| 84 | return new_flavor |
| 85 | |
| 86 | |
| 87 | class MinBwAllocationPlacementTest(NetworkQoSPlacementTestBase): |
| 88 | |
| 89 | required_extensions = ['port-resource-request', |
| 90 | 'qos', |
| 91 | 'qos-bw-minimum-ingress'] |
| 92 | |
| 93 | SMALLEST_POSSIBLE_BW = 1 |
| 94 | BANDWIDTH_1 = 1000 |
| 95 | BANDWIDTH_2 = 2000 |
| 96 | |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 97 | @classmethod |
| 98 | def skip_checks(cls): |
| 99 | super(MinBwAllocationPlacementTest, cls).skip_checks() |
| 100 | if not CONF.network_feature_enabled.qos_placement_physnet: |
| 101 | msg = "Skipped as no physnet is available in config for " \ |
| 102 | "placement based QoS allocation." |
| 103 | raise cls.skipException(msg) |
| 104 | |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 105 | def setUp(self): |
| 106 | super(MinBwAllocationPlacementTest, self).setUp() |
| 107 | self._check_if_allocation_is_possible() |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 108 | |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 109 | def _create_policy_and_min_bw_rule(self, name_prefix, min_kbps): |
| 110 | policy = self.qos_client.create_qos_policy( |
| 111 | name=data_utils.rand_name(name_prefix), |
| 112 | shared=True)['policy'] |
| 113 | self.addCleanup(test_utils.call_and_ignore_notfound_exc, |
| 114 | self.qos_client.delete_qos_policy, policy['id']) |
| 115 | rule = self.qos_min_bw_client.create_minimum_bandwidth_rule( |
| 116 | policy['id'], |
| 117 | **{ |
| 118 | 'min_kbps': min_kbps, |
| 119 | 'direction': self.INGRESS_DIRECTION |
| 120 | })['minimum_bandwidth_rule'] |
| 121 | self.addCleanup( |
| 122 | test_utils.call_and_ignore_notfound_exc, |
| 123 | self.qos_min_bw_client.delete_minimum_bandwidth_rule, policy['id'], |
| 124 | rule['id']) |
| 125 | |
| 126 | return policy |
| 127 | |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 128 | def _create_qos_basic_policies(self): |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 129 | self.qos_policy_valid = self._create_policy_and_min_bw_rule( |
| 130 | name_prefix='test_policy_valid', |
| 131 | min_kbps=self.SMALLEST_POSSIBLE_BW) |
| 132 | self.qos_policy_not_valid = self._create_policy_and_min_bw_rule( |
| 133 | name_prefix='test_policy_not_valid', |
| 134 | min_kbps=self.PLACEMENT_MAX_INT) |
| 135 | |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 136 | def _create_qos_policies_from_life(self): |
| 137 | # For tempest-slow the max bandwidth configured is 1000000, |
| 138 | # https://opendev.org/openstack/tempest/src/branch/master/ |
| 139 | # .zuul.yaml#L416-L420 |
| 140 | self.qos_policy_1 = self._create_policy_and_min_bw_rule( |
| 141 | name_prefix='test_policy_1', |
| 142 | min_kbps=self.BANDWIDTH_1 |
| 143 | ) |
| 144 | self.qos_policy_2 = self._create_policy_and_min_bw_rule( |
| 145 | name_prefix='test_policy_2', |
| 146 | min_kbps=self.BANDWIDTH_2 |
| 147 | ) |
| 148 | |
| 149 | def _create_network_and_qos_policies(self, policy_method): |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 150 | physnet_name = CONF.network_feature_enabled.qos_placement_physnet |
| 151 | base_segm = \ |
| 152 | CONF.network_feature_enabled.provider_net_base_segmentation_id |
| 153 | |
Ghanshyam Mann | 071d154 | 2021-03-24 19:10:47 -0500 | [diff] [blame] | 154 | self.prov_network, _, _ = self.setup_network_subnet_with_router( |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 155 | networks_client=self.networks_client, |
| 156 | routers_client=self.routers_client, |
| 157 | subnets_client=self.subnets_client, |
| 158 | **{ |
| 159 | 'shared': True, |
| 160 | 'provider:network_type': 'vlan', |
| 161 | 'provider:physical_network': physnet_name, |
| 162 | 'provider:segmentation_id': base_segm |
| 163 | }) |
| 164 | |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 165 | policy_method() |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 166 | |
| 167 | def _check_if_allocation_is_possible(self): |
| 168 | alloc_candidates = self.placement_client.list_allocation_candidates( |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 169 | resources1='%s:%s' % (self.BW_RESOURCE_CLASS, |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 170 | self.SMALLEST_POSSIBLE_BW)) |
| 171 | if len(alloc_candidates['provider_summaries']) == 0: |
Balazs Gibizer | a5f523b | 2021-08-26 13:38:19 +0200 | [diff] [blame] | 172 | self.fail('No allocation candidates are available for %s:%s' % |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 173 | (self.BW_RESOURCE_CLASS, self.SMALLEST_POSSIBLE_BW)) |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 174 | |
| 175 | # Just to be sure check with impossible high (placement max_int), |
| 176 | # allocation |
| 177 | alloc_candidates = self.placement_client.list_allocation_candidates( |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 178 | resources1='%s:%s' % (self.BW_RESOURCE_CLASS, |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 179 | self.PLACEMENT_MAX_INT)) |
| 180 | if len(alloc_candidates['provider_summaries']) != 0: |
| 181 | self.fail('For %s:%s there should be no available candidate!' % |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 182 | (self.BW_RESOURCE_CLASS, self.PLACEMENT_MAX_INT)) |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 183 | |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 184 | def _boot_vm_with_min_bw(self, qos_policy_id, status='ACTIVE'): |
| 185 | wait_until = (None if status == 'ERROR' else status) |
| 186 | port = self.create_port( |
| 187 | self.prov_network['id'], qos_policy_id=qos_policy_id) |
| 188 | |
| 189 | server = self.create_server(networks=[{'port': port['id']}], |
| 190 | wait_until=wait_until) |
| 191 | waiters.wait_for_server_status( |
Balazs Gibizer | 18accde | 2021-09-29 16:10:49 +0200 | [diff] [blame] | 192 | client=self.servers_client, server_id=server['id'], |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 193 | status=status, ready_wait=False, raise_on_error=False) |
| 194 | return server, port |
| 195 | |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 196 | def _assert_allocation_is_as_expected(self, consumer, port_ids, |
| 197 | min_kbps=SMALLEST_POSSIBLE_BW): |
| 198 | allocations = self.placement_client.list_allocations( |
| 199 | consumer)['allocations'] |
| 200 | self.assertGreater(len(allocations), 0) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 201 | bw_resource_in_alloc = False |
Balazs Gibizer | 20514ef | 2021-09-15 12:00:20 +0200 | [diff] [blame] | 202 | allocation_rp = None |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 203 | for rp, resources in allocations.items(): |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 204 | if self.BW_RESOURCE_CLASS in resources['resources']: |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 205 | self.assertEqual( |
| 206 | min_kbps, |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 207 | resources['resources'][self.BW_RESOURCE_CLASS]) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 208 | bw_resource_in_alloc = True |
| 209 | allocation_rp = rp |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 210 | if min_kbps: |
| 211 | self.assertTrue(bw_resource_in_alloc) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 212 | |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 213 | # Check binding_profile of the port is not empty and equals with |
| 214 | # the rp uuid |
| 215 | for port_id in port_ids: |
| 216 | port = self.os_admin.ports_client.show_port(port_id) |
Balazs Gibizer | 20514ef | 2021-09-15 12:00:20 +0200 | [diff] [blame] | 217 | port_binding_alloc = port['port']['binding:profile'][ |
| 218 | 'allocation'] |
| 219 | # NOTE(gibi): the format of the allocation key depends on the |
| 220 | # existence of port-resource-request-groups API extension. |
| 221 | # TODO(gibi): drop the else branch once tempest does not need |
| 222 | # to support Xena release any more. |
| 223 | if utils.is_extension_enabled( |
| 224 | 'port-resource-request-groups', 'network'): |
| 225 | self.assertEqual( |
| 226 | {allocation_rp}, |
| 227 | set(port_binding_alloc.values())) |
| 228 | else: |
| 229 | self.assertEqual(allocation_rp, port_binding_alloc) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 230 | |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 231 | @decorators.idempotent_id('78625d92-212c-400e-8695-dd51706858b8') |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 232 | @utils.services('compute', 'network') |
| 233 | def test_qos_min_bw_allocation_basic(self): |
| 234 | """"Basic scenario with QoS min bw allocation in placement. |
| 235 | |
| 236 | Steps: |
| 237 | * Create prerequisites: |
| 238 | ** VLAN type provider network with subnet. |
| 239 | ** valid QoS policy with minimum bandwidth rule with min_kbps=1 |
| 240 | (This is a simplification to skip the checks in placement for |
| 241 | detecting the resource provider tree and inventories, as if |
| 242 | bandwidth resource is available 1 kbs will be available). |
| 243 | ** invalid QoS policy with minimum bandwidth rule with |
| 244 | min_kbs=max integer from placement (this is a simplification again |
| 245 | to avoid detection of RP tress and inventories, as placement will |
| 246 | reject such big allocation). |
| 247 | * Create port with valid QoS policy, and boot VM with that, it should |
| 248 | pass. |
| 249 | * Create port with invalid QoS policy, and try to boot VM with that, |
| 250 | it should fail. |
| 251 | """ |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 252 | self._create_network_and_qos_policies(self._create_qos_basic_policies) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 253 | server1, valid_port = self._boot_vm_with_min_bw( |
| 254 | qos_policy_id=self.qos_policy_valid['id']) |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 255 | self._assert_allocation_is_as_expected(server1['id'], |
| 256 | [valid_port['id']]) |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 257 | |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 258 | server2, not_valid_port = self._boot_vm_with_min_bw( |
| 259 | self.qos_policy_not_valid['id'], status='ERROR') |
Lajos Katona | c87a06b | 2019-01-04 13:21:48 +0100 | [diff] [blame] | 260 | allocations = self.placement_client.list_allocations(server2['id']) |
| 261 | |
| 262 | self.assertEqual(0, len(allocations['allocations'])) |
| 263 | server2 = self.servers_client.show_server(server2['id']) |
| 264 | self.assertIn('fault', server2['server']) |
| 265 | self.assertIn('No valid host', server2['server']['fault']['message']) |
elajkat | e4f2820 | 2019-10-24 12:56:42 +0200 | [diff] [blame] | 266 | # Check that binding_profile of the port is empty |
| 267 | port = self.os_admin.ports_client.show_port(not_valid_port['id']) |
| 268 | self.assertEqual(0, len(port['port']['binding:profile'])) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 269 | |
| 270 | @decorators.idempotent_id('8a98150c-a506-49a5-96c6-73a5e7b04ada') |
| 271 | @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, |
| 272 | 'Cold migration is not available.') |
| 273 | @testtools.skipUnless(CONF.compute.min_compute_nodes > 1, |
| 274 | 'Less than 2 compute nodes, skipping multinode ' |
| 275 | 'tests.') |
| 276 | @utils.services('compute', 'network') |
| 277 | def test_migrate_with_qos_min_bw_allocation(self): |
| 278 | """Scenario to migrate VM with QoS min bw allocation in placement |
| 279 | |
| 280 | Boot a VM like in test_qos_min_bw_allocation_basic, do the same |
| 281 | checks, and |
| 282 | * migrate the server |
| 283 | * confirm the resize, if the VM state is VERIFY_RESIZE |
| 284 | * If the VM goes to ACTIVE state check that allocations are as |
| 285 | expected. |
| 286 | """ |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 287 | self._create_network_and_qos_policies(self._create_qos_basic_policies) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 288 | server, valid_port = self._boot_vm_with_min_bw( |
| 289 | qos_policy_id=self.qos_policy_valid['id']) |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 290 | self._assert_allocation_is_as_expected(server['id'], |
| 291 | [valid_port['id']]) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 292 | |
Balazs Gibizer | 18accde | 2021-09-29 16:10:49 +0200 | [diff] [blame] | 293 | self.os_adm.servers_client.migrate_server(server_id=server['id']) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 294 | waiters.wait_for_server_status( |
Balazs Gibizer | 18accde | 2021-09-29 16:10:49 +0200 | [diff] [blame] | 295 | client=self.servers_client, server_id=server['id'], |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 296 | status='VERIFY_RESIZE', ready_wait=False, raise_on_error=False) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 297 | |
| 298 | # TODO(lajoskatona): Check that the allocations are ok for the |
| 299 | # migration? |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 300 | self._assert_allocation_is_as_expected(server['id'], |
| 301 | [valid_port['id']]) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 302 | |
Balazs Gibizer | 18accde | 2021-09-29 16:10:49 +0200 | [diff] [blame] | 303 | self.os_adm.servers_client.confirm_resize_server( |
| 304 | server_id=server['id']) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 305 | waiters.wait_for_server_status( |
Balazs Gibizer | 18accde | 2021-09-29 16:10:49 +0200 | [diff] [blame] | 306 | client=self.servers_client, server_id=server['id'], |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 307 | status='ACTIVE', ready_wait=False, raise_on_error=True) |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 308 | self._assert_allocation_is_as_expected(server['id'], |
| 309 | [valid_port['id']]) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 310 | |
| 311 | @decorators.idempotent_id('c29e7fd3-035d-4993-880f-70819847683f') |
| 312 | @testtools.skipUnless(CONF.compute_feature_enabled.resize, |
| 313 | 'Resize not available.') |
| 314 | @utils.services('compute', 'network') |
| 315 | def test_resize_with_qos_min_bw_allocation(self): |
| 316 | """Scenario to resize VM with QoS min bw allocation in placement. |
| 317 | |
| 318 | Boot a VM like in test_qos_min_bw_allocation_basic, do the same |
| 319 | checks, and |
| 320 | * resize the server with new flavor |
| 321 | * confirm the resize, if the VM state is VERIFY_RESIZE |
| 322 | * If the VM goes to ACTIVE state check that allocations are as |
| 323 | expected. |
| 324 | """ |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 325 | self._create_network_and_qos_policies(self._create_qos_basic_policies) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 326 | server, valid_port = self._boot_vm_with_min_bw( |
| 327 | qos_policy_id=self.qos_policy_valid['id']) |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 328 | self._assert_allocation_is_as_expected(server['id'], |
| 329 | [valid_port['id']]) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 330 | |
Balazs Gibizer | bc0257c | 2021-08-26 16:41:51 +0200 | [diff] [blame] | 331 | new_flavor = self._create_flavor_to_resize_to() |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 332 | |
| 333 | self.servers_client.resize_server( |
| 334 | server_id=server['id'], flavor_ref=new_flavor['id']) |
| 335 | waiters.wait_for_server_status( |
Balazs Gibizer | 18accde | 2021-09-29 16:10:49 +0200 | [diff] [blame] | 336 | client=self.servers_client, server_id=server['id'], |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 337 | status='VERIFY_RESIZE', ready_wait=False, raise_on_error=False) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 338 | |
| 339 | # TODO(lajoskatona): Check that the allocations are ok for the |
| 340 | # migration? |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 341 | self._assert_allocation_is_as_expected(server['id'], |
| 342 | [valid_port['id']]) |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 343 | |
| 344 | self.servers_client.confirm_resize_server(server_id=server['id']) |
| 345 | waiters.wait_for_server_status( |
Balazs Gibizer | 18accde | 2021-09-29 16:10:49 +0200 | [diff] [blame] | 346 | client=self.servers_client, server_id=server['id'], |
elajkat | 064a340 | 2019-10-17 13:18:10 +0200 | [diff] [blame] | 347 | status='ACTIVE', ready_wait=False, raise_on_error=True) |
elajkat | 8b90b26 | 2020-07-15 16:11:56 +0200 | [diff] [blame] | 348 | self._assert_allocation_is_as_expected(server['id'], |
| 349 | [valid_port['id']]) |
| 350 | |
| 351 | @decorators.idempotent_id('79fdaa1c-df62-4738-a0f0-1cff9dc415f6') |
| 352 | @utils.services('compute', 'network') |
| 353 | def test_qos_min_bw_allocation_update_policy(self): |
| 354 | """Test the update of QoS policy on bound port |
| 355 | |
| 356 | Related RFE in neutron: #1882804 |
| 357 | The scenario is the following: |
| 358 | * Have a port with QoS policy and minimum bandwidth rule. |
| 359 | * Boot a VM with the port. |
| 360 | * Update the port with a new policy with different minimum bandwidth |
| 361 | values. |
| 362 | * The allocation on placement side should be according to the new |
| 363 | rules. |
| 364 | """ |
| 365 | if not utils.is_network_feature_enabled('update_port_qos'): |
| 366 | raise self.skipException("update_port_qos feature is not enabled") |
| 367 | |
| 368 | self._create_network_and_qos_policies( |
| 369 | self._create_qos_policies_from_life) |
| 370 | |
| 371 | port = self.create_port( |
| 372 | self.prov_network['id'], qos_policy_id=self.qos_policy_1['id']) |
| 373 | |
| 374 | server1 = self.create_server( |
| 375 | networks=[{'port': port['id']}]) |
| 376 | |
| 377 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], |
| 378 | self.BANDWIDTH_1) |
| 379 | |
| 380 | self.ports_client.update_port( |
| 381 | port['id'], |
| 382 | **{'qos_policy_id': self.qos_policy_2['id']}) |
| 383 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], |
| 384 | self.BANDWIDTH_2) |
| 385 | |
| 386 | # I changed my mind |
| 387 | self.ports_client.update_port( |
| 388 | port['id'], |
| 389 | **{'qos_policy_id': self.qos_policy_1['id']}) |
| 390 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], |
| 391 | self.BANDWIDTH_1) |
| 392 | |
| 393 | # bad request.... |
| 394 | self.qos_policy_not_valid = self._create_policy_and_min_bw_rule( |
| 395 | name_prefix='test_policy_not_valid', |
| 396 | min_kbps=self.PLACEMENT_MAX_INT) |
| 397 | port_orig = self.ports_client.show_port(port['id'])['port'] |
| 398 | self.assertRaises( |
| 399 | lib_exc.Conflict, |
| 400 | self.ports_client.update_port, |
| 401 | port['id'], **{'qos_policy_id': self.qos_policy_not_valid['id']}) |
| 402 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], |
| 403 | self.BANDWIDTH_1) |
| 404 | |
| 405 | port_upd = self.ports_client.show_port(port['id'])['port'] |
| 406 | self.assertEqual(port_orig['qos_policy_id'], |
| 407 | port_upd['qos_policy_id']) |
| 408 | self.assertEqual(self.qos_policy_1['id'], port_upd['qos_policy_id']) |
| 409 | |
| 410 | @decorators.idempotent_id('9cfc3bb8-f433-4c91-87b6-747cadc8958a') |
| 411 | @utils.services('compute', 'network') |
| 412 | def test_qos_min_bw_allocation_update_policy_from_zero(self): |
| 413 | """Test port without QoS policy to have QoS policy |
| 414 | |
| 415 | This scenario checks if updating a port without QoS policy to |
| 416 | have QoS policy with minimum_bandwidth rule succeeds only on |
| 417 | controlplane, but placement allocation remains 0. |
| 418 | """ |
| 419 | if not utils.is_network_feature_enabled('update_port_qos'): |
| 420 | raise self.skipException("update_port_qos feature is not enabled") |
| 421 | |
| 422 | self._create_network_and_qos_policies( |
| 423 | self._create_qos_policies_from_life) |
| 424 | |
| 425 | port = self.create_port(self.prov_network['id']) |
| 426 | |
| 427 | server1 = self.create_server( |
| 428 | networks=[{'port': port['id']}]) |
| 429 | |
| 430 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], 0) |
| 431 | |
| 432 | self.ports_client.update_port( |
| 433 | port['id'], **{'qos_policy_id': self.qos_policy_2['id']}) |
| 434 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], 0) |
| 435 | |
| 436 | @decorators.idempotent_id('a9725a70-1d28-4e3b-ae0e-450abc235962') |
| 437 | @utils.services('compute', 'network') |
| 438 | def test_qos_min_bw_allocation_update_policy_to_zero(self): |
| 439 | """Test port with QoS policy to remove QoS policy |
| 440 | |
| 441 | In this scenario port with QoS minimum_bandwidth rule update to |
| 442 | remove QoS policy results in 0 placement allocation. |
| 443 | """ |
| 444 | if not utils.is_network_feature_enabled('update_port_qos'): |
| 445 | raise self.skipException("update_port_qos feature is not enabled") |
| 446 | |
| 447 | self._create_network_and_qos_policies( |
| 448 | self._create_qos_policies_from_life) |
| 449 | |
| 450 | port = self.create_port( |
| 451 | self.prov_network['id'], qos_policy_id=self.qos_policy_1['id']) |
| 452 | |
| 453 | server1 = self.create_server( |
| 454 | networks=[{'port': port['id']}]) |
| 455 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], |
| 456 | self.BANDWIDTH_1) |
| 457 | |
| 458 | self.ports_client.update_port( |
| 459 | port['id'], |
| 460 | **{'qos_policy_id': None}) |
| 461 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], 0) |
| 462 | |
| 463 | @decorators.idempotent_id('756ced7f-6f1a-43e7-a851-2fcfc16f3dd7') |
| 464 | @utils.services('compute', 'network') |
| 465 | def test_qos_min_bw_allocation_update_with_multiple_ports(self): |
| 466 | if not utils.is_network_feature_enabled('update_port_qos'): |
| 467 | raise self.skipException("update_port_qos feature is not enabled") |
| 468 | |
| 469 | self._create_network_and_qos_policies( |
| 470 | self._create_qos_policies_from_life) |
| 471 | |
| 472 | port1 = self.create_port( |
| 473 | self.prov_network['id'], qos_policy_id=self.qos_policy_1['id']) |
| 474 | port2 = self.create_port( |
| 475 | self.prov_network['id'], qos_policy_id=self.qos_policy_2['id']) |
| 476 | |
| 477 | server1 = self.create_server( |
| 478 | networks=[{'port': port1['id']}, {'port': port2['id']}]) |
| 479 | self._assert_allocation_is_as_expected( |
| 480 | server1['id'], [port1['id'], port2['id']], |
| 481 | self.BANDWIDTH_1 + self.BANDWIDTH_2) |
| 482 | |
| 483 | self.ports_client.update_port( |
| 484 | port1['id'], |
| 485 | **{'qos_policy_id': self.qos_policy_2['id']}) |
| 486 | self._assert_allocation_is_as_expected( |
| 487 | server1['id'], [port1['id'], port2['id']], |
| 488 | 2 * self.BANDWIDTH_2) |
| 489 | |
| 490 | @decorators.idempotent_id('0805779e-e03c-44fb-900f-ce97a790653b') |
| 491 | @utils.services('compute', 'network') |
| 492 | def test_empty_update(self): |
| 493 | if not utils.is_network_feature_enabled('update_port_qos'): |
| 494 | raise self.skipException("update_port_qos feature is not enabled") |
| 495 | |
| 496 | self._create_network_and_qos_policies( |
| 497 | self._create_qos_policies_from_life) |
| 498 | |
| 499 | port = self.create_port( |
| 500 | self.prov_network['id'], qos_policy_id=self.qos_policy_1['id']) |
| 501 | |
| 502 | server1 = self.create_server( |
| 503 | networks=[{'port': port['id']}]) |
| 504 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], |
| 505 | self.BANDWIDTH_1) |
| 506 | self.ports_client.update_port( |
| 507 | port['id'], |
| 508 | **{'description': 'foo'}) |
| 509 | self._assert_allocation_is_as_expected(server1['id'], [port['id']], |
| 510 | self.BANDWIDTH_1) |