Skip to content

Commit 0a5bf30

Browse files
VMware to KVM: cold (VDDK) and warm (CBT) migration into Ceph/RBD and Linstor, plus importVm adoption of existing RBD root volumes and Linstor root/data volumes (#13656)
Signed-off-by: Andrija Panic <andrija.panic@gmail.com> Co-authored-by: dahn <daan.hoogland@gmail.com>
1 parent 602d9ec commit 0a5bf30

129 files changed

Lines changed: 20982 additions & 230 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎PendingReleaseNotes‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,25 @@ example.ver.1 > example.ver.2:
5555
continue to snapshot live.
5656

5757
4.23.0.0 > 24.0.0:
58+
* VMware-to-KVM import using VDDK can import powered-off VMware VMs directly
59+
into Ceph RBD primary storage when forceconverttopool is enabled and the
60+
selected KVM conversion host supports qemu RBD access and in-place virt-v2v
61+
finalization. Hosts without in-place finalization support can still use the
62+
staged VDDK flow, converting to temporary qcow2 storage before copying the
63+
finalized disks into RBD.
64+
65+
* Linstor primary storage can now be the destination for VMware-to-KVM
66+
imports in all three modes. Staged imports (virt-v2v to a temporary NFS
67+
location) copy the converted disks into pre-created DRBD block devices
68+
through the Linstor storage adaptor; the import host must be a LINSTOR
69+
satellite connected to the destination pool. Direct VDDK imports with
70+
forceconverttopool write each powered-off VMware disk over nbdkit/VDDK
71+
straight into the DRBD device and finalize it with virt-v2v in place.
72+
VMware CBT warm migrations replicate the initial full copy and all
73+
incremental changed-block cycles directly into Linstor volumes and
74+
finalize in place at cutover; the conversion host requires VDDK,
75+
in-place virt-v2v support and access to the Linstor pool.
76+
5877
* KVM/Ceph: RBD volumes can now be encrypted at rest using native librbd
5978
LUKS2 (<encryption format='luks2' engine='librbd'>), for both data disks
6079
and root disks. Encryption is transparent to the guest and reuses the

‎agent/src/main/java/com/cloud/agent/properties/AgentProperties.java‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,19 @@ public Property<Integer> getWorkers() {
848848
*/
849849
public static final Property<String> VDDK_TRANSPORTS = new Property<>("vddk.transports", null, String.class);
850850

851+
/**
852+
* NBD-transport compression used between the VDDK and the VMware server for the
853+
* agent-driven nbdkit full-disk copies (cold direct import and CBT initial full
854+
* sync). Passed to the nbdkit vddk plugin as <code>compression=&lt;value&gt;</code>.
855+
* Valid values: <code>none</code>, <code>zlib</code>, <code>fastlz</code>,
856+
* <code>skipz</code> (nbdkit &ge; 1.24, vSphere &ge; 6.5). <code>fastlz</code>
857+
* compresses both zero regions and real data at low CPU cost; <code>skipz</code>
858+
* only elides zero blocks. Does not affect the staged virt-v2v conversion path.
859+
* Data type: String.<br>
860+
* Default value: <code>fastlz</code>
861+
*/
862+
public static final Property<String> VDDK_NBD_COMPRESSION = new Property<>("vddk.nbd.compression", "fastlz", String.class);
863+
851864
/**
852865
* vCenter TLS certificate thumbprint used by virt-v2v VDDK mode, passed as <code>-io vddk-thumbprint=&lt;value&gt;</code>.
853866
* If unset, the KVM host computes it at runtime from the vCenter endpoint.

‎api/src/main/java/com/cloud/agent/api/to/RemoteInstanceTO.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class RemoteInstanceTO implements Serializable {
3838
private String datacenterName;
3939
private String clusterName;
4040
private String hostName;
41+
private String vmwareMoref;
4142

4243
public RemoteInstanceTO() {
4344
}
@@ -65,6 +66,11 @@ public RemoteInstanceTO(String instanceName, String instancePath, String vcenter
6566
this.hostName = hostName;
6667
}
6768

69+
public RemoteInstanceTO(String instanceName, String instancePath, String vcenterHost, String vcenterUsername, String vcenterPassword, String datacenterName, String clusterName, String hostName, String vmwareMoref) {
70+
this(instanceName, instancePath, vcenterHost, vcenterUsername, vcenterPassword, datacenterName, clusterName, hostName);
71+
this.vmwareMoref = vmwareMoref;
72+
}
73+
6874
public Hypervisor.HypervisorType getHypervisorType() {
6975
return this.hypervisorType;
7076
}
@@ -100,4 +106,12 @@ public String getClusterName() {
100106
public String getHostName() {
101107
return hostName;
102108
}
109+
110+
public String getVmwareMoref() {
111+
return vmwareMoref;
112+
}
113+
114+
public void setVmwareMoref(String vmwareMoref) {
115+
this.vmwareMoref = vmwareMoref;
116+
}
103117
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.agent.api.to;
18+
19+
import java.io.Serializable;
20+
21+
public class VmwareCbtChangedBlockRangeTO implements Serializable {
22+
23+
private String diskId;
24+
private long startOffset;
25+
private long length;
26+
27+
public VmwareCbtChangedBlockRangeTO() {
28+
}
29+
30+
public VmwareCbtChangedBlockRangeTO(String diskId, long startOffset, long length) {
31+
this.diskId = diskId;
32+
this.startOffset = startOffset;
33+
this.length = length;
34+
}
35+
36+
public String getDiskId() {
37+
return diskId;
38+
}
39+
40+
public long getStartOffset() {
41+
return startOffset;
42+
}
43+
44+
public long getLength() {
45+
return length;
46+
}
47+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.agent.api.to;
18+
19+
import java.io.Serializable;
20+
21+
public class VmwareCbtDiskSyncResultTO implements Serializable {
22+
23+
private String diskId;
24+
private String targetPath;
25+
private String changeId;
26+
private String snapshotMor;
27+
private long changedBytes;
28+
private long durationSeconds;
29+
private boolean result;
30+
private String details;
31+
32+
public VmwareCbtDiskSyncResultTO() {
33+
}
34+
35+
public VmwareCbtDiskSyncResultTO(String diskId, String targetPath, String changeId, String snapshotMor,
36+
long changedBytes, long durationSeconds, boolean result, String details) {
37+
this.diskId = diskId;
38+
this.targetPath = targetPath;
39+
this.changeId = changeId;
40+
this.snapshotMor = snapshotMor;
41+
this.changedBytes = changedBytes;
42+
this.durationSeconds = durationSeconds;
43+
this.result = result;
44+
this.details = details;
45+
}
46+
47+
public String getDiskId() {
48+
return diskId;
49+
}
50+
51+
public String getTargetPath() {
52+
return targetPath;
53+
}
54+
55+
public String getChangeId() {
56+
return changeId;
57+
}
58+
59+
public String getSnapshotMor() {
60+
return snapshotMor;
61+
}
62+
63+
public long getChangedBytes() {
64+
return changedBytes;
65+
}
66+
67+
public long getDurationSeconds() {
68+
return durationSeconds;
69+
}
70+
71+
public boolean getResult() {
72+
return result;
73+
}
74+
75+
public String getDetails() {
76+
return details;
77+
}
78+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.agent.api.to;
18+
19+
import java.io.Serializable;
20+
21+
public class VmwareCbtDiskTO implements Serializable {
22+
23+
private String diskId;
24+
private Integer diskDeviceKey;
25+
private String sourceDiskPath;
26+
private String datastoreName;
27+
private String targetPath;
28+
private String targetFormat;
29+
private String changeId;
30+
private String snapshotMor;
31+
private long capacityBytes;
32+
33+
public VmwareCbtDiskTO() {
34+
}
35+
36+
public VmwareCbtDiskTO(String diskId, Integer diskDeviceKey, String sourceDiskPath, String datastoreName,
37+
String targetPath, String targetFormat, String changeId, String snapshotMor,
38+
long capacityBytes) {
39+
this.diskId = diskId;
40+
this.diskDeviceKey = diskDeviceKey;
41+
this.sourceDiskPath = sourceDiskPath;
42+
this.datastoreName = datastoreName;
43+
this.targetPath = targetPath;
44+
this.targetFormat = targetFormat;
45+
this.changeId = changeId;
46+
this.snapshotMor = snapshotMor;
47+
this.capacityBytes = capacityBytes;
48+
}
49+
50+
public String getDiskId() {
51+
return diskId;
52+
}
53+
54+
public Integer getDiskDeviceKey() {
55+
return diskDeviceKey;
56+
}
57+
58+
public String getSourceDiskPath() {
59+
return sourceDiskPath;
60+
}
61+
62+
public String getDatastoreName() {
63+
return datastoreName;
64+
}
65+
66+
public String getTargetPath() {
67+
return targetPath;
68+
}
69+
70+
public String getTargetFormat() {
71+
return targetFormat;
72+
}
73+
74+
public String getChangeId() {
75+
return changeId;
76+
}
77+
78+
public String getSnapshotMor() {
79+
return snapshotMor;
80+
}
81+
82+
public long getCapacityBytes() {
83+
return capacityBytes;
84+
}
85+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.agent.api.to;
18+
19+
import java.io.Serializable;
20+
21+
public class VmwareVddkSourceDiskTO implements Serializable {
22+
23+
private String diskId;
24+
private String sourceDiskPath;
25+
private long capacityBytes;
26+
private Integer position;
27+
28+
public VmwareVddkSourceDiskTO() {
29+
}
30+
31+
public VmwareVddkSourceDiskTO(String diskId, String sourceDiskPath, long capacityBytes, Integer position) {
32+
this.diskId = diskId;
33+
this.sourceDiskPath = sourceDiskPath;
34+
this.capacityBytes = capacityBytes;
35+
this.position = position;
36+
}
37+
38+
public String getDiskId() {
39+
return diskId;
40+
}
41+
42+
public String getSourceDiskPath() {
43+
return sourceDiskPath;
44+
}
45+
46+
public long getCapacityBytes() {
47+
return capacityBytes;
48+
}
49+
50+
public Integer getPosition() {
51+
return position;
52+
}
53+
}

‎api/src/main/java/com/cloud/event/EventTypes.java‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ public class EventTypes {
127127
public static final String EVENT_VM_RESTORE = "VM.RESTORE";
128128
public static final String EVENT_VM_EXPUNGE = "VM.EXPUNGE";
129129
public static final String EVENT_VM_IMPORT = "VM.IMPORT";
130+
public static final String EVENT_VMWARE_CBT_MIGRATION_START = "VMWARE.CBT.MIGRATION.START";
131+
public static final String EVENT_VMWARE_CBT_MIGRATION_SYNC = "VMWARE.CBT.MIGRATION.SYNC";
132+
public static final String EVENT_VMWARE_CBT_MIGRATION_CUTOVER = "VMWARE.CBT.MIGRATION.CUTOVER";
130133
public static final String EVENT_VM_UNMANAGE = "VM.UNMANAGE";
131134
public static final String EVENT_VM_RECOVER = "VM.RECOVER";
132135

‎api/src/main/java/com/cloud/host/Host.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,18 @@ public static String[] toStrings(Host.Type... types) {
6262
String HOST_VDDK_SUPPORT = "host.vddk.support";
6363
String HOST_VDDK_LIB_DIR = "vddk.lib.dir";
6464
String HOST_VDDK_VERSION = "host.vddk.version";
65+
String HOST_VDDK_BLOCKCOPY_SUPPORT = "host.vddk.blockcopy.support";
66+
String HOST_VDDK_BLOCKCOPY_INPLACE_FINALIZATION_SUPPORT = "host.vddk.blockcopy.inplace.finalization.support";
67+
String HOST_VDDK_BLOCKCOPY_RBD_SUPPORT = "host.vddk.blockcopy.rbd.support";
68+
String HOST_QEMU_IMG_VERSION = "host.qemu.img.version";
69+
String HOST_QEMU_NBD_VERSION = "host.qemu.nbd.version";
70+
String HOST_QEMU_IO_VERSION = "host.qemu.io.version";
6571
String HOST_OVFTOOL_VERSION = "host.ovftool.version";
6672
String HOST_VIRTV2V_VERSION = "host.virtv2v.version";
73+
String HOST_VIRTV2V_INPLACE_VERSION = "host.virtv2v.inplace.version";
74+
String HOST_VDDK_RBD_DIRECT_IMPORT_SUPPORT = "host.vddk.rbd.direct.import.support";
75+
String HOST_VIRTV2V_INPLACE_SUPPORT = "host.virtv2v.inplace.support";
76+
String HOST_QEMU_RBD_SUPPORT = "host.qemu.rbd.support";
6777
String HOST_SSH_PORT = "host.ssh.port";
6878
String HOST_CDROM_MAX_COUNT = "host.cdrom.max.count";
6979
String GUEST_OS_CATEGORY_ID = "guest.os.category.id";

0 commit comments

Comments
 (0)