Skip to content

VMware-to-KVM Resize Support for Instances Using Ephemeral Root Disks - #652

Open
anokfireball wants to merge 4 commits into
stable/2023.2-m3from
kvmotion-eph-support
Open

VMware-to-KVM Resize Support for Instances Using Ephemeral Root Disks#652
anokfireball wants to merge 4 commits into
stable/2023.2-m3from
kvmotion-eph-support

Conversation

@anokfireball

@anokfireball anokfireball commented Jul 31, 2026

Copy link
Copy Markdown
Member

Implements Nova-side KVMotion support for image-backed VMware instances. This extends the BFV-only cross-HV resize flow from #627 to instances whose root disk is still a Nova-managed VMDK or FCD on a VMware ephemeral datastore. SCI KVM does not support ephemeral root disks, so Nova first converts the root disk to a Cinder FCD volume and then continues with the existing BFV resize path.

From the customer's point of view this stays a normal nova resize to a KVM flavor. After scheduling selects the KVM target, conductor detects the image-backed root and starts the conversion before prep_resize. The existing image/local root BDM is modified in place: source_type='image' and the image reference stay, while the BDM gets the new Cinder volume id and reserved attachment. This avoids creating a second root BDM for the same disk.

The VMware driver provides the source-side prep and abort operations. Prep powers off the VM, detaches the root disk without deleting the backing files, and returns the VMDK path, disk size, Cinder host data, rollback data, and optional VirtualDisk.vDiskId. Nova then calls the Cinder manage_existing wrapper with source-name, size_gb, and optional source-id. If source-id is present, Cinder can reuse the existing FCD id. Otherwise Cinder registers the detached VMDK as an FCD and relocates it to the Cinder datastore.

Abort is only safe before Cinder crosses the storage point of no return. Nova can abort after synchronous Cinder failures and Cinder error state. Nova must not abort after error_managing, because relocation may have started or finished. On timeout, Nova reads the latest volume state and only aborts if that state is definitely safe.

The FCD volume type comes from [cross_hv] fcd_volume_type, with no safe default because the correct type is deployment-specific. Missing config fails before Nova powers off the VM or detaches the disk. The Cinder manage wait uses [cross_hv] manage_existing_timeout.

The conversion is permanent. Confirm leaves the instance BFV on KVM. Revert moves it back to VMware, but it stays BFV-on-VMware. A second resize after revert skips conversion and uses the BFV-only path directly.

Cross-HV resize can use an image/local root only after conductor has a
chance to convert it to BFV. The old utility-level BFV check rejected those
instances before scheduling, so validate the root BDM in MigrationTask
instead.

Allow image/local and */volume roots. Reject blank/local, missing root BDMs,
and cross-cell selections because the prep and abort RPCs run against the
source cell.

Change-Id: Ib66d7de2da1865437b0db9a2127cfd928c3ab073
KVM cannot boot a Nova-managed VMDK from a VMware ephemeral datastore, so an
image/local root must be imported into Cinder before the existing BFV resize
path runs.

The conductor prep step powers off the source VM, detaches the root VMDK,
imports it with manage_existing using source-name, size_gb, and optional
source-id, creates a reserved attachment, and mutates the root BDM to
volume-backed.

The conversion is permanent across revert. Abort is only safe before Cinder
relocates the disk; later code reports that through structured safe_to_abort
metadata.

Change-Id: I7e991b5da895b059a5b9f459c44ad3e4d5f93c3d
Cross-HV conversion needs a reversible source-side prep step around Cinder
manage_existing. Add VMwareVMOps prep and abort helpers that detach the root
VMDK and, when abort is safe, attach it back.

Prep discovers the root disk before changing power state, accepts already
shutdown guests, and powers the VM back on after detach failure only when Nova
powered it off in this attempt. It returns the VMDK path, size, Cinder host,
rollback device data, and optional FCD id needed by conductor.

Abort is retry-tolerant: it skips reattach if the disk is already present and
skips power-on if the VM is already running.

Change-Id: I5b8057f8797d714c1e33f782a3b9f72a47f50407
Expose source-side prep and abort through compute RPC so conductor can drive
VMware conversion without reaching into virt code.

Bump compute RPC to 6.2.1, add driver stubs, delegate the VMware driver to
VMops, and leave unsupported drivers on NotImplementedError.
prep_cross_hv_conversion preserves DiskNotFound and InstanceInvalidState as
expected RPC exceptions; abort failures remain unexpected and surface to the
caller.

Change-Id: I277618423e1fe881e56a36cd277b713bcc7a6cda
@anokfireball
anokfireball marked this pull request as ready for review August 10, 2026 11:57
Comment on lines +582 to +584
LOG.info('Detached root disk %(path)s from instance '
'%(instance)s for cross-HV conversion.',
{'path': vmdk_path, 'instance': instance.uuid})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd make this debug.

Comment on lines +6550 to +6585
@mock.patch.object(fake_driver.FakeDriver, 'prep_cross_hv_conversion')
def test_prep_cross_hv_conversion(self, mock_prep):
mock_prep.return_value = {
'vmdk_path': '[ds] uuid/uuid.vmdk',
'size_bytes': 68719476736,
'cinder_host': 'cinder-volume-vmware-vc@vmware_fcd',
'rollback': {
'controller_key': 1000,
'unit_number': 0,
'capacity_in_bytes': 68719476736,
},
}
instance = fake_instance.fake_instance_obj(self.context)
result = self.compute.prep_cross_hv_conversion(
self.context, instance=instance)
mock_prep.assert_called_once_with(self.context, instance)
self.assertEqual(result['vmdk_path'], '[ds] uuid/uuid.vmdk')

@mock.patch.object(fake_driver.FakeDriver, 'abort_cross_hv_conversion')
def test_abort_cross_hv_conversion(self, mock_abort):
instance = fake_instance.fake_instance_obj(self.context)
prep_data = {
'vmdk_path': '[ds] uuid/uuid.vmdk',
'size_bytes': 68719476736,
'cinder_host': 'cinder-volume-vmware-vc@vmware_fcd',
'rollback': {
'controller_key': 1000,
'unit_number': 0,
'capacity_in_bytes': 68719476736,
},
}
self.compute.abort_cross_hv_conversion(
self.context, instance=instance, prep_data=prep_data)
mock_abort.assert_called_once_with(
self.context, instance, prep_data)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do these tests test anything really? it seems as if it's 36 lines, to test oneliner wrapper methods?

Comment thread nova/compute/rpcapi.py
flavor
* 6.1 - Add reimage_boot_volume parameter to rebuild_instance()
* 6.2 - Add target_state parameter to rebuild_instance()
* 6.2.1 - Add prep_cross_hv_conversion() and

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need another feature-flag toggle to roll this out consistently across the fleet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants