From 449bc70ffa64ca8d071f9535311d439f81b7341a Mon Sep 17 00:00:00 2001 From: Fabian Fulga Date: Fri, 3 Jul 2026 10:35:54 +0300 Subject: [PATCH] Support migrating volumes_info entries with legacy disk ids --- coriolis/schemas/vm_export_info_schema.json | 7 +++ coriolis/tasks/replica_tasks.py | 60 +++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/coriolis/schemas/vm_export_info_schema.json b/coriolis/schemas/vm_export_info_schema.json index 05f3017e1..867fdb92e 100644 --- a/coriolis/schemas/vm_export_info_schema.json +++ b/coriolis/schemas/vm_export_info_schema.json @@ -118,6 +118,13 @@ "type": "string", "description": "The allocation scheme for the given disk (static = thick; dynamic = thin)", "enum": ["static", "dynamic"] + }, + "legacy_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Identifiers which previous versions of the source provider may have reported as this disk's 'id' (e.g. the VMware provider moving from per-VM device keys to virtual disk UUIDs). Used to migrate the 'disk_id' fields of pre-existing replicas' volumes_info to the current identifier." } }, "required": [ diff --git a/coriolis/tasks/replica_tasks.py b/coriolis/tasks/replica_tasks.py index 0407e8bca..8e49bf373 100644 --- a/coriolis/tasks/replica_tasks.py +++ b/coriolis/tasks/replica_tasks.py @@ -74,6 +74,60 @@ def _check_ensure_volumes_info_ordering(export_info, volumes_info): return ordered_volumes_info +def _update_legacy_disk_ids_in_volumes_info(export_info, volumes_info): + """Migrates volumes_info entries keyed on legacy disk identifiers. + + Source providers may change their disk identification methodology + over time (e.g. the VMware provider moving from per-VM device keys + to virtual disk UUIDs). Replicas created before such a change have + volumes_info entries whose 'disk_id' no longer matches any disk 'id' + in a freshly-fetched export_info, which would lead the destination + provider to consider the existing volumes orphaned (deleting them) + and to create brand new ones. + + To allow safely updating such replicas, each export_info disk may + declare the identifiers it was previously reported under via its + 'legacy_ids' field. Any volumes_info entry whose 'disk_id' does not + match a current disk 'id' but does match a legacy one is updated + in-place to the current 'id'. + """ + disks = export_info.get('devices', {}).get('disks', []) + current_ids = {str(d['id']) for d in disks if d.get('id')} + legacy_ids_map = {} + for disk in disks: + disk_id = disk.get('id') + if not disk_id: + continue + for legacy_id in disk.get('legacy_ids') or []: + legacy_ids_map[str(legacy_id)] = str(disk_id) + + existing_volume_disk_ids = { + str(v.get('disk_id')) for v in volumes_info} + for volume_info in volumes_info: + disk_id = str(volume_info.get('disk_id')) + if disk_id in current_ids: + continue + new_disk_id = legacy_ids_map.get(disk_id) + if not new_disk_id: + continue + if new_disk_id in existing_volume_disk_ids: + # Migrating would duplicate an already-present entry; leave + # the legacy-keyed one for the destination provider to clean + # up as an orphaned volume instead. + LOG.warning( + "Not migrating volumes_info entry with legacy disk_id " + "'%s' to '%s': an entry with the new id already exists.", + disk_id, new_disk_id) + continue + LOG.info( + "Migrating volumes_info entry from legacy disk_id '%s' to " + "'%s'.", disk_id, new_disk_id) + volume_info['disk_id'] = new_disk_id + existing_volume_disk_ids.add(new_disk_id) + + return volumes_info + + def _preserve_old_export_info_nic_ips(old_export_info, new_export_info): def _get_nic(nics_info, nic_id): for nic_info in nics_info: @@ -291,6 +345,12 @@ def _run(self, ctxt, instance, origin, destination, task_info, connection_info = base.get_connection_info(ctxt, destination) volumes_info = task_info.get("volumes_info", []) + # NOTE: migrate any volumes_info entries of pre-existing replicas + # which are still keyed on a legacy disk identifier (e.g. VMware + # device keys before the switch to virtual disk UUIDs) before the + # provider matches them against the current export_info disk ids: + _update_legacy_disk_ids_in_volumes_info(export_info, volumes_info) + volumes_info = provider.deploy_replica_disks( ctxt, connection_info, target_environment, instance, export_info, volumes_info)