Skip to content

Commit a2984b6

Browse files
Balazs GibizerBalazs Gibizer
authored andcommitted
update allocation in binding profile during migrate
If the server has port with resource allocation and the server is migrated then when the port is bound to the destination host the allocation key needs to be updated in the binding:profile to point to the resource provider that provides resources for this port on the destination host. This patch extends the migrate_instance_finish() network api method to pass the updated resource providers of the ports during migration. Change-Id: I220fa02ee916728e241503084b14984bab4b0c3b blueprint: support-move-ops-with-qos-ports
1 parent f7f5e18 commit a2984b6

File tree

8 files changed

+135
-42
lines changed

8 files changed

+135
-42
lines changed

nova/compute/manager.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4203,8 +4203,8 @@ def revert_resize(self, context, instance, migration, request_spec=None):
42034203
self.compute_rpcapi.finish_revert_resize(context, instance,
42044204
migration, migration.source_compute, request_spec)
42054205

4206-
def _finish_revert_resize_network_migrate_finish(self, context, instance,
4207-
migration):
4206+
def _finish_revert_resize_network_migrate_finish(
4207+
self, context, instance, migration, provider_mappings):
42084208
"""Causes port binding to be updated. In some Neutron or port
42094209
configurations - see NetworkModel.get_bind_time_events() - we
42104210
expect the vif-plugged event from Neutron immediately and wait for it.
@@ -4214,6 +4214,8 @@ def _finish_revert_resize_network_migrate_finish(self, context, instance,
42144214
:param context: The request context.
42154215
:param instance: The instance undergoing the revert resize.
42164216
:param migration: The Migration object of the resize being reverted.
4217+
:param provider_mappings: a dict of list of resource provider uuids
4218+
keyed by port uuid
42174219
:raises: eventlet.timeout.Timeout or
42184220
exception.VirtualInterfacePlugException.
42194221
"""
@@ -4238,9 +4240,8 @@ def _finish_revert_resize_network_migrate_finish(self, context, instance,
42384240
# the migration.dest_compute to source host at here.
42394241
with utils.temporary_mutation(
42404242
migration, dest_compute=migration.source_compute):
4241-
self.network_api.migrate_instance_finish(context,
4242-
instance,
4243-
migration)
4243+
self.network_api.migrate_instance_finish(
4244+
context, instance, migration, provider_mappings)
42444245
except eventlet.timeout.Timeout:
42454246
with excutils.save_and_reraise_exception():
42464247
LOG.error('Timeout waiting for Neutron events: %s', events,
@@ -4292,10 +4293,12 @@ def finish_revert_resize(
42924293
'migration_uuid': migration.uuid})
42934294
raise
42944295

4296+
provider_mappings = self._get_request_group_mapping(request_spec)
4297+
42954298
self.network_api.setup_networks_on_host(context, instance,
42964299
migration.source_compute)
42974300
self._finish_revert_resize_network_migrate_finish(
4298-
context, instance, migration)
4301+
context, instance, migration, provider_mappings)
42994302
network_info = self.network_api.get_instance_nw_info(context,
43004303
instance)
43014304

@@ -4746,7 +4749,7 @@ def _complete_volume_attachments(self, context, bdms):
47464749
context, bdm.attachment_id)
47474750

47484751
def _finish_resize(self, context, instance, migration, disk_info,
4749-
image_meta, bdms):
4752+
image_meta, bdms, request_spec):
47504753
resize_instance = False # indicates disks have been resized
47514754
old_instance_type_id = migration['old_instance_type_id']
47524755
new_instance_type_id = migration['new_instance_type_id']
@@ -4772,11 +4775,12 @@ def _finish_resize(self, context, instance, migration, disk_info,
47724775
# NOTE(tr3buchet): setup networks on destination host
47734776
self.network_api.setup_networks_on_host(context, instance,
47744777
migration.dest_compute)
4778+
provider_mappings = self._get_request_group_mapping(request_spec)
4779+
47754780
# For neutron, migrate_instance_finish updates port bindings for this
47764781
# host including any PCI devices claimed for SR-IOV ports.
4777-
self.network_api.migrate_instance_finish(context,
4778-
instance,
4779-
migration)
4782+
self.network_api.migrate_instance_finish(
4783+
context, instance, migration, provider_mappings)
47804784

47814785
network_info = self.network_api.get_instance_nw_info(context, instance)
47824786

@@ -4850,7 +4854,7 @@ def finish_resize(self, context, disk_info, image, instance,
48504854
"""
48514855
try:
48524856
self._finish_resize_helper(context, disk_info, image, instance,
4853-
migration)
4857+
migration, request_spec)
48544858
except Exception:
48554859
with excutils.save_and_reraise_exception():
48564860
# At this point, resize_instance (which runs on the source) has
@@ -4871,7 +4875,7 @@ def finish_resize(self, context, disk_info, image, instance,
48714875
context, instance, migration)
48724876

48734877
def _finish_resize_helper(self, context, disk_info, image, instance,
4874-
migration):
4878+
migration, request_spec):
48754879
"""Completes the migration process.
48764880
48774881
The caller must revert the instance's allocations if the migration
@@ -4883,7 +4887,8 @@ def _finish_resize_helper(self, context, disk_info, image, instance,
48834887
with self._error_out_instance_on_exception(context, instance):
48844888
image_meta = objects.ImageMeta.from_dict(image)
48854889
network_info = self._finish_resize(context, instance, migration,
4886-
disk_info, image_meta, bdms)
4890+
disk_info, image_meta, bdms,
4891+
request_spec)
48874892

48884893
# TODO(melwitt): We should clean up instance console tokens here. The
48894894
# instance is on a new host and will need to establish a new console
@@ -7242,9 +7247,9 @@ def post_live_migration_at_destination(self, context, instance,
72427247
migration = {'source_compute': instance.host,
72437248
'dest_compute': self.host,
72447249
'migration_type': 'live-migration'}
7245-
self.network_api.migrate_instance_finish(context,
7246-
instance,
7247-
migration)
7250+
# TODO(gibi): calculate and pass resource_provider_mapping
7251+
self.network_api.migrate_instance_finish(
7252+
context, instance, migration, provider_mappings=None)
72487253

72497254
network_info = self.network_api.get_instance_nw_info(context, instance)
72507255
self._notify_about_instance_usage(

nova/network/api.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,8 @@ def migrate_instance_start(self, context, instance, migration):
502502

503503
self.network_rpcapi.migrate_instance_start(context, **args)
504504

505-
def migrate_instance_finish(self, context, instance, migration):
505+
def migrate_instance_finish(
506+
self, context, instance, migration, provider_mappings):
506507
"""Finish migrating the network of an instance."""
507508
flavor = instance.get_flavor()
508509
args = dict(
@@ -524,9 +525,9 @@ def migrate_instance_finish(self, context, instance, migration):
524525
def setup_instance_network_on_host(self, context, instance, host,
525526
migration=None):
526527
"""Setup network for specified instance on host."""
527-
self.migrate_instance_finish(context, instance,
528-
{'source_compute': None,
529-
'dest_compute': host})
528+
self.migrate_instance_finish(
529+
context, instance, {'source_compute': None, 'dest_compute': host},
530+
None)
530531

531532
def cleanup_instance_network_on_host(self, context, instance, host):
532533
"""Cleanup network for specified instance on host."""

nova/network/base_api.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,16 @@ def migrate_instance_start(self, context, instance, migration):
343343
"""Start to migrate the network of an instance."""
344344
raise NotImplementedError()
345345

346-
def migrate_instance_finish(self, context, instance, migration):
347-
"""Finish migrating the network of an instance."""
346+
def migrate_instance_finish(
347+
self, context, instance, migration, provider_mappings):
348+
"""Finish migrating the network of an instance.
349+
350+
:param context: The request context.
351+
:param instance: nova.objects.instance.Instance object.
352+
:param migration: nova.objects.migration.Migration object.
353+
:param provider_mappings: a dict of list of resource provider uuids
354+
keyed by port uuid
355+
"""
348356
raise NotImplementedError()
349357

350358
def setup_instance_network_on_host(self, context, instance, host,

nova/network/neutronv2/api.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2749,11 +2749,12 @@ def migrate_instance_start(self, context, instance, migration):
27492749
'Error: %s', vif['id'], dest_host, resp.status_code,
27502750
resp.text)
27512751

2752-
def migrate_instance_finish(self, context, instance, migration):
2752+
def migrate_instance_finish(
2753+
self, context, instance, migration, provider_mappings):
27532754
"""Finish migrating the network of an instance."""
2754-
self._update_port_binding_for_instance(context, instance,
2755-
migration['dest_compute'],
2756-
migration=migration)
2755+
self._update_port_binding_for_instance(
2756+
context, instance, migration['dest_compute'], migration=migration,
2757+
provider_mappings=provider_mappings)
27572758

27582759
def add_network_to_project(self, context, project_id, network_uuid=None):
27592760
"""Force add a network to the project."""
@@ -3224,8 +3225,10 @@ def _get_pci_mapping_for_migration(self, instance, migration):
32243225
migration.get('status') == 'reverted')
32253226
return instance.migration_context.get_pci_mapping_for_migration(revert)
32263227

3227-
def _update_port_binding_for_instance(self, context, instance, host,
3228-
migration=None):
3228+
def _update_port_binding_for_instance(
3229+
self, context, instance, host, migration=None,
3230+
provider_mappings=None):
3231+
32293232
neutron = get_client(context, admin=True)
32303233
search_opts = {'device_id': instance.uuid,
32313234
'tenant_id': instance.project_id}
@@ -3244,9 +3247,6 @@ def _update_port_binding_for_instance(self, context, instance, host,
32443247
vif_type = p.get('binding:vif_type')
32453248
if (p.get(constants.BINDING_HOST_ID) != host or
32463249
vif_type in FAILED_VIF_TYPES):
3247-
# TODO(gibi): To support ports with resource request during
3248-
# server move operations we need to take care of 'allocation'
3249-
# key in the binding profile per binding.
32503250

32513251
updates[constants.BINDING_HOST_ID] = host
32523252
# If the host changed, the AZ could have also changed so we
@@ -3286,6 +3286,28 @@ def _update_port_binding_for_instance(self, context, instance, host,
32863286
reason=_("Unable to correlate PCI slot %s") %
32873287
pci_slot)
32883288

3289+
if p.get('resource_request'):
3290+
if not provider_mappings:
3291+
# NOTE(gibi): This should not happen as the API level
3292+
# minimum compute service version check ensures that the
3293+
# compute services already send the RequestSpec during
3294+
# the move operations between the source and the
3295+
# destination and the dest compute calculates the
3296+
# mapping based on that.
3297+
raise exception.PortUpdateFailed(
3298+
port_id=p['id'],
3299+
reason=_("Provider mappings wasn't provided for the "
3300+
"port with resource request"))
3301+
3302+
# NOTE(gibi): In the resource provider mapping there can be
3303+
# more than one RP fulfilling a request group. But resource
3304+
# requests of a Neutron port is always mapped to a
3305+
# numbered request group that is always fulfilled by one
3306+
# resource provider. So we only pass that single RP UUID here.
3307+
binding_profile[constants.ALLOCATION] = \
3308+
provider_mappings[p['id']][0]
3309+
updates[constants.BINDING_PROFILE] = binding_profile
3310+
32893311
port_updates.append((p['id'], updates))
32903312

32913313
# Avoid rolling back updates if we catch an error above.

nova/tests/unit/compute/test_compute.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4866,7 +4866,7 @@ def _instance_save1(expected_task_state=None):
48664866
mock_setup.assert_called_once_with(self.context, instance,
48674867
'fake-mini')
48684868
mock_net_mig.assert_called_once_with(self.context,
4869-
test.MatchType(objects.Instance), migration)
4869+
test.MatchType(objects.Instance), migration, None)
48704870
mock_get_nw.assert_called_once_with(self.context, instance)
48714871
mock_notify.assert_has_calls([
48724872
mock.call(self.context, instance, 'finish_resize.start',

nova/tests/unit/compute/test_compute_mgr.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5250,7 +5250,8 @@ def _test_finish_revert_resize_network_migrate_finish(
52505250
source_compute='fake-source',
52515251
dest_compute='fake-dest')
52525252

5253-
def fake_migrate_instance_finish(context, instance, migration):
5253+
def fake_migrate_instance_finish(
5254+
context, instance, migration, mapping):
52545255
# NOTE(artom) This looks weird, but it's checking that the
52555256
# temporaty_mutation() context manager did its job.
52565257
self.assertEqual(migration.dest_compute, migration.source_compute)
@@ -5263,12 +5264,12 @@ def fake_migrate_instance_finish(context, instance, migration):
52635264
side_effect=fake_migrate_instance_finish)
52645265
) as (mock_wait, mock_migrate_instance_finish):
52655266
self.compute._finish_revert_resize_network_migrate_finish(
5266-
self.context, instance, migration)
5267+
self.context, instance, migration, mock.sentinel.mapping)
52675268
mock_wait.assert_called_once_with(
52685269
instance, events, deadline=CONF.vif_plugging_timeout,
52695270
error_callback=self.compute._neutron_failed_migration_callback)
52705271
mock_migrate_instance_finish.assert_called_once_with(
5271-
self.context, instance, migration)
5272+
self.context, instance, migration, mock.sentinel.mapping)
52725273

52735274
def test_finish_revert_resize_network_migrate_finish_wait(self):
52745275
"""Test that we wait for bind-time events if we have a hybrid-plugged
@@ -7397,7 +7398,8 @@ def test_revert_resize_instance_destroy_disks_non_shared_storage(self):
73977398
def test_finish_revert_resize_network_calls_order(self):
73987399
self.nw_info = None
73997400

7400-
def _migrate_instance_finish(context, instance, migration):
7401+
def _migrate_instance_finish(
7402+
context, instance, migration, provider_mappings):
74017403
# The migration.dest_compute is temporarily set to source_compute.
74027404
self.assertEqual(migration.source_compute, migration.dest_compute)
74037405
self.nw_info = 'nw_info'
@@ -8446,7 +8448,8 @@ def _do_test(mock_notify, post_live_migration_at_destination,
84468448
self.context, self.instance,
84478449
{'source_compute': cn_old,
84488450
'dest_compute': self.compute.host,
8449-
'migration_type': 'live-migration'})
8451+
'migration_type': 'live-migration'},
8452+
provider_mappings=None)
84508453
_get_instance_block_device_info.assert_called_once_with(
84518454
self.context, self.instance
84528455
)

nova/tests/unit/network/test_api.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,14 +279,14 @@ def test_migrate_instance_finish_with_multihost(self):
279279
arg1, arg2, expected = self._stub_migrate_instance_calls(
280280
'migrate_instance_finish', True, info)
281281
expected['host'] = 'fake_compute_dest'
282-
self.network_api.migrate_instance_finish(self.context, arg1, arg2)
282+
self.network_api.migrate_instance_finish(self.context, arg1, arg2, {})
283283
self.assertEqual(info['kwargs'], expected)
284284

285285
def test_migrate_instance_finish_without_multihost(self):
286286
info = {'kwargs': {}}
287287
arg1, arg2, expected = self._stub_migrate_instance_calls(
288288
'migrate_instance_finish', False, info)
289-
self.network_api.migrate_instance_finish(self.context, arg1, arg2)
289+
self.network_api.migrate_instance_finish(self.context, arg1, arg2, {})
290290
self.assertEqual(info['kwargs'], expected)
291291

292292
def test_is_multi_host_instance_has_no_fixed_ip(self):
@@ -516,7 +516,8 @@ def test_setup_instance_network_on_host(self, fake_migrate_finish):
516516
self.context, instance, 'fake_compute_source')
517517
fake_migrate_finish.assert_called_once_with(
518518
self.context, instance,
519-
{'source_compute': None, 'dest_compute': 'fake_compute_source'})
519+
{'source_compute': None, 'dest_compute': 'fake_compute_source'},
520+
None)
520521

521522
@mock.patch('oslo_concurrency.lockutils.lock')
522523
@mock.patch.object(api.API, '_get_instance_nw_info')

0 commit comments

Comments
 (0)