Skip to content

Commit 6fd071b

Browse files
maaoyulyarwood
andcommitted
compute: Update volume_id within connection_info during swap_volume
When Cinder orchestrates a volume migration between backends it initially creates a temporary volume on the destination before calling Nova to swap to that volume. When this is complete Nova calls back to Cinder and the temporary volume on the destination is renamed to the original volume UUID making the migration transparent to end users. Previously Nova would not account for this within the connection_info stahed when connecting the new volume and would continue to point to the original UUID of the temporary volume. For most codepaths in Nova this isn't an issue but when dealing with multiattach volumes the libvirt driver has a specific path that uses this stored volume_id within the connection_info when an attempt is made to detach the volume, nova.virt.libvirt.LibvirtDriver._should_disconnect_target. In this case this would lead to a failed lookup of the volume in Cinder and an eventual 500 returned by Nova. This change corrects this by ensuring any volume_id stashed in the new connection_info we gather during a swap_volume is overwritten with the correct id returned by the eventual call to Cinder's os-migrate_volume_completion API [1]. [1] https://docs.openstack.org/api-ref/block-storage/v3/index.html?expanded=complete-migration-of-a-volume-detail#volumes-volumes Co-Authored-By: Lee Yarwood <[email protected]> Closes-Bug: #1943431 Change-Id: I43612714b343d98320b19b5b38264afc700790e3
1 parent 6657401 commit 6fd071b

File tree

3 files changed

+36
-31
lines changed

3 files changed

+36
-31
lines changed

nova/compute/manager.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7463,7 +7463,16 @@ def _do_swap_volume(self, context, old_volume_id, new_volume_id,
74637463
# NOTE(lyarwood): Update the BDM with the modified new_cinfo and
74647464
# correct volume_id returned by Cinder.
74657465
save_volume_id = comp_ret['save_volume_id']
7466+
7467+
# NOTE(lyarwood): Overwrite the possibly stale serial and volume_id in
7468+
# the connection_info with the volume_id returned from Cinder. This
7469+
# could be the case during a volume migration where the new_cinfo here
7470+
# refers to the temporary volume *before* Cinder renames it to the
7471+
# original volume UUID at the end of the migration.
74667472
new_cinfo['serial'] = save_volume_id
7473+
new_cinfo['volume_id'] = save_volume_id
7474+
if 'data' in new_cinfo:
7475+
new_cinfo['data']['volume_id'] = save_volume_id
74677476
values = {
74687477
'connection_info': jsonutils.dumps(new_cinfo),
74697478
'source_type': 'volume',

nova/tests/functional/regressions/test_bug_1943431.py

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
from nova import context
1818
from nova import objects
19-
from nova.tests.functional.api import client
2019
from nova.tests.functional import integrated_helpers
2120
from nova.tests.functional.libvirt import base
2221
from nova.virt import block_device as driver_block_device
@@ -28,9 +27,9 @@ class TestLibvirtROMultiattachMigrate(
2827
):
2928
"""Regression test for bug 1939545
3029
31-
This regression test asserts the current broken behaviour of Nova during
30+
This regression test asserts the now fixed behaviour of Nova during
3231
a Cinder orchestrated volume migration that leaves the stashed
33-
connection_info of the attachment pointing at a now deleted temporary
32+
connection_info of the attachment pointing at the original
3433
volume UUID used during the migration.
3534
3635
This is slightly different to the Nova orchestrated pure swap_volume
@@ -83,6 +82,10 @@ def test_ro_multiattach_swap_volume(self):
8382
self.assertEqual(
8483
self.cinder.MULTIATTACH_RO_SWAP_NEW_VOL,
8584
connection_info['data']['volume_id'])
85+
self.assertIn('volume_id', connection_info)
86+
self.assertEqual(
87+
self.cinder.MULTIATTACH_RO_SWAP_NEW_VOL,
88+
connection_info['volume_id'])
8689
self.assertIn('serial', connection_info)
8790
self.assertEqual(
8891
self.cinder.MULTIATTACH_RO_SWAP_NEW_VOL,
@@ -123,39 +126,26 @@ def test_ro_multiattach_migrate_volume(self):
123126
server_id)
124127
connection_info = jsonutils.loads(bdm.connection_info)
125128

126-
# FIXME(lyarwood): This is bug #1943431 where only the serial within
127-
# the connection_info of the temporary volume has been updated to point
128-
# to the old volume UUID with the stashed volume_id provided by the
129-
# backend still pointing to the temporary volume UUID that has now been
130-
# deleted by cinder.
129+
# Assert that only the old volume UUID is referenced within the stashed
130+
# connection_info and returned by driver_block_device.get_volume_id
131131
self.assertIn('serial', connection_info)
132132
self.assertEqual(
133133
self.cinder.MULTIATTACH_RO_MIGRATE_OLD_VOL,
134134
connection_info.get('serial'))
135+
self.assertIn('volume_id', connection_info)
136+
self.assertEqual(
137+
self.cinder.MULTIATTACH_RO_MIGRATE_OLD_VOL,
138+
connection_info['volume_id'])
135139
self.assertIn('volume_id', connection_info.get('data'))
136140
self.assertEqual(
137-
self.cinder.MULTIATTACH_RO_MIGRATE_NEW_VOL,
141+
self.cinder.MULTIATTACH_RO_MIGRATE_OLD_VOL,
138142
connection_info['data']['volume_id'])
139143
self.assertEqual(
140-
self.cinder.MULTIATTACH_RO_MIGRATE_NEW_VOL,
144+
self.cinder.MULTIATTACH_RO_MIGRATE_OLD_VOL,
141145
driver_block_device.get_volume_id(connection_info))
142146

143-
# FIXME(lyarwood): As a result of the above any request to detach the
144-
# migrated multiattach volume from the instance or any action that
145-
# would cause the _disconnect_volume and _should_disconnect_target
146-
# logic to trigger in the libvirt driver will fail as
147-
# driver_block_device.get_volume_id points to the now deleted temporary
148-
# volume used during the migration.
149-
#
150-
# Replace this with the following once fixed:
151-
#
152-
# self.api.delete_server_volume(
153-
# server_id, self.cinder.MULTIATTACH_RO_MIGRATE_OLD_VOL)
154-
# self._wait_for_volume_detach(
155-
# server_id, self.cinder.MULTIATTACH_RO_MIGRATE_OLD_VOL)
156-
ex = self.assertRaises(
157-
client.OpenStackApiException,
158-
self.api.delete_server_volume,
159-
server_id,
160-
self.cinder.MULTIATTACH_RO_MIGRATE_OLD_VOL)
161-
self.assertEqual(500, ex.response.status_code)
147+
# Assert that the old volume can be detached from the instance
148+
self.api.delete_server_volume(
149+
server_id, self.cinder.MULTIATTACH_RO_MIGRATE_OLD_VOL)
150+
self._wait_for_volume_detach(
151+
server_id, self.cinder.MULTIATTACH_RO_MIGRATE_OLD_VOL)

nova/tests/unit/compute/test_compute_mgr.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2977,8 +2977,11 @@ def test_swap_volume_with_new_attachment_id_cinder_migrate_true(
29772977
self.assertEqual(uuids.old_volume_id, bdm.volume_id)
29782978
self.assertEqual(uuids.new_attachment_id, bdm.attachment_id)
29792979
self.assertEqual(1, bdm.volume_size)
2980-
self.assertEqual(uuids.old_volume_id,
2981-
jsonutils.loads(bdm.connection_info)['serial'])
2980+
new_conn_info = jsonutils.loads(bdm.connection_info)
2981+
self.assertEqual(uuids.old_volume_id, new_conn_info['serial'])
2982+
self.assertEqual(uuids.old_volume_id, new_conn_info['volume_id'])
2983+
self.assertEqual(
2984+
uuids.old_volume_id, new_conn_info['data']['volume_id'])
29822985

29832986
@mock.patch.object(compute_utils, 'notify_about_volume_swap')
29842987
@mock.patch.object(objects.BlockDeviceMapping,
@@ -3049,6 +3052,9 @@ def test_swap_volume_with_new_attachment_id_cinder_migrate_false(
30493052
self.assertEqual(2, bdm.volume_size)
30503053
new_conn_info = jsonutils.loads(bdm.connection_info)
30513054
self.assertEqual(uuids.new_volume_id, new_conn_info['serial'])
3055+
self.assertEqual(uuids.new_volume_id, new_conn_info['volume_id'])
3056+
self.assertEqual(
3057+
uuids.new_volume_id, new_conn_info['data']['volume_id'])
30523058
self.assertNotIn('multiattach', new_conn_info)
30533059

30543060
@mock.patch.object(compute_utils, 'add_instance_fault_from_exc')

0 commit comments

Comments
 (0)