Skip to content

Commit bd86d7c

Browse files
Support VDDK imports into RBD storage
1 parent c0ce5b4 commit bd86d7c

21 files changed

Lines changed: 839 additions & 35 deletions

File tree

PendingReleaseNotes

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,11 @@ example.ver.1 > example.ver.2:
3939
which can now be attached to Instances. This is to prevent the Secondary
4040
Storage to grow to enormous sizes as Linux Distributions keep growing in
4141
size while a stripped down Linux should fit on a 2.88MB floppy.
42+
43+
4.23.0.0:
44+
* VMware-to-KVM import using VDDK can import powered-off VMware VMs directly
45+
into Ceph RBD primary storage when forceconverttopool is enabled and the
46+
selected KVM conversion host supports qemu RBD access and in-place virt-v2v
47+
finalization. Hosts without in-place finalization support can still use the
48+
staged VDDK flow, converting to temporary qcow2 storage before copying the
49+
finalized disks into RBD.

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

Lines changed: 9 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
}
@@ -100,4 +101,12 @@ public String getClusterName() {
100101
public String getHostName() {
101102
return hostName;
102103
}
104+
105+
public String getVmwareMoref() {
106+
return vmwareMoref;
107+
}
108+
109+
public void setVmwareMoref(String vmwareMoref) {
110+
this.vmwareMoref = vmwareMoref;
111+
}
103112
}
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/host/Host.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ public static String[] toStrings(Host.Type... types) {
6262
String HOST_VDDK_VERSION = "host.vddk.version";
6363
String HOST_OVFTOOL_VERSION = "host.ovftool.version";
6464
String HOST_VIRTV2V_VERSION = "host.virtv2v.version";
65+
String HOST_VDDK_RBD_DIRECT_IMPORT_SUPPORT = "host.vddk.rbd.direct.import.support";
66+
String HOST_VIRTV2V_INPLACE_SUPPORT = "host.virt.v2v.inplace.support";
67+
String HOST_QEMU_IMG_RBD_SUPPORT = "host.qemu.img.rbd.support";
68+
String HOST_RBD_QEMU_COPY_SUPPORT = "host.rbd.qemu.copy.support";
6569
String HOST_SSH_PORT = "host.ssh.port";
6670

6771
int DEFAULT_SSH_PORT = 22;

api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportVmCmd.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
153153
private Long importInstanceHostId;
154154

155155
@Parameter(name = ApiConstants.CONVERT_INSTANCE_STORAGE_POOL_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class,
156-
description = "(only for importing VMs from VMware to KVM) optional - the temporary storage pool to perform the virt-v2v migration from VMware to KVM.")
156+
description = "(only for importing VMs from VMware to KVM) optional - the temporary storage pool to perform the virt-v2v migration from VMware to KVM. " +
157+
"When " + ApiConstants.USE_VDDK + " and " + ApiConstants.FORCE_CONVERT_TO_POOL + " are true, this can be an RBD primary storage pool for direct RBD import.")
157158
private Long convertStoragePoolId;
158159

159160
@Parameter(name = ApiConstants.FORCE_MS_TO_IMPORT_VM_FILES, type = CommandType.BOOLEAN,
@@ -183,7 +184,9 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
183184
type = CommandType.BOOLEAN,
184185
since = "4.22.1",
185186
description = "(only for importing VMs from VMware to KVM) optional - if true, uses VDDK on the KVM conversion host for converting the VM. " +
186-
"This parameter is mutually exclusive with " + ApiConstants.FORCE_MS_TO_IMPORT_VM_FILES + ".")
187+
"This parameter is mutually exclusive with " + ApiConstants.FORCE_MS_TO_IMPORT_VM_FILES + ". " +
188+
"With " + ApiConstants.FORCE_CONVERT_TO_POOL + "=true and an RBD conversion pool, the source VMware VM must be powered off and " +
189+
"the conversion host must support qemu RBD access and in-place virt-v2v finalization.")
187190
private Boolean useVddk;
188191

189192

api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstanceTO.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public enum PowerState {
6666

6767
private String bootType;
6868
private String bootMode;
69+
private String vmwareMoref;
6970

7071
public String getName() {
7172
return name;
@@ -234,6 +235,14 @@ public void setBootMode(String bootMode) {
234235
this.bootMode = bootMode;
235236
}
236237

238+
public String getVmwareMoref() {
239+
return vmwareMoref;
240+
}
241+
242+
public void setVmwareMoref(String vmwareMoref) {
243+
this.vmwareMoref = vmwareMoref;
244+
}
245+
237246
public static class Disk {
238247
private String diskId;
239248

core/src/main/java/com/cloud/agent/api/CheckConvertInstanceCommand.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
public class CheckConvertInstanceCommand extends Command {
2020
boolean checkWindowsGuestConversionSupport = false;
2121
boolean useVddk = false;
22+
boolean checkVddkRbdDirectImportSupport = false;
2223
String vddkLibDir;
2324

2425
public CheckConvertInstanceCommand() {
@@ -50,6 +51,14 @@ public void setUseVddk(boolean useVddk) {
5051
this.useVddk = useVddk;
5152
}
5253

54+
public boolean isCheckVddkRbdDirectImportSupport() {
55+
return checkVddkRbdDirectImportSupport;
56+
}
57+
58+
public void setCheckVddkRbdDirectImportSupport(boolean checkVddkRbdDirectImportSupport) {
59+
this.checkVddkRbdDirectImportSupport = checkVddkRbdDirectImportSupport;
60+
}
61+
5362
public String getVddkLibDir() {
5463
return vddkLibDir;
5564
}

core/src/main/java/com/cloud/agent/api/ConvertInstanceCommand.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818

1919
import com.cloud.agent.api.to.DataStoreTO;
2020
import com.cloud.agent.api.to.RemoteInstanceTO;
21+
import com.cloud.agent.api.to.VmwareVddkSourceDiskTO;
2122
import com.cloud.hypervisor.Hypervisor;
2223

24+
import java.util.List;
25+
2326
public class ConvertInstanceCommand extends Command {
2427

2528
private RemoteInstanceTO sourceInstance;
@@ -35,6 +38,7 @@ public class ConvertInstanceCommand extends Command {
3538
private String vddkLibDir;
3639
private String vddkTransports;
3740
private String vddkThumbprint;
41+
private List<VmwareVddkSourceDiskTO> vmwareVddkSourceDisks;
3842

3943
public ConvertInstanceCommand() {
4044
}
@@ -126,6 +130,14 @@ public void setVddkThumbprint(String vddkThumbprint) {
126130
this.vddkThumbprint = vddkThumbprint;
127131
}
128132

133+
public List<VmwareVddkSourceDiskTO> getVmwareVddkSourceDisks() {
134+
return vmwareVddkSourceDisks;
135+
}
136+
137+
public void setVmwareVddkSourceDisks(List<VmwareVddkSourceDiskTO> vmwareVddkSourceDisks) {
138+
this.vmwareVddkSourceDisks = vmwareVddkSourceDisks;
139+
}
140+
129141
@Override
130142
public boolean executeInSequence() {
131143
return false;

core/src/main/java/com/cloud/agent/api/ImportConvertedInstanceCommand.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818

1919
import com.cloud.agent.api.to.DataStoreTO;
2020
import com.cloud.agent.api.to.RemoteInstanceTO;
21+
import com.cloud.storage.Storage;
2122

2223
import java.util.List;
2324

2425
public class ImportConvertedInstanceCommand extends Command {
2526

2627
private RemoteInstanceTO sourceInstance;
2728
private List<String> destinationStoragePools;
29+
private List<Storage.StoragePoolType> destinationStoragePoolTypes;
2830
private DataStoreTO conversionTemporaryLocation;
2931
private String temporaryConvertUuid;
3032
private boolean forceConvertToPool;
@@ -34,15 +36,24 @@ public ImportConvertedInstanceCommand() {
3436

3537
public ImportConvertedInstanceCommand(RemoteInstanceTO sourceInstance,
3638
List<String> destinationStoragePools,
39+
List<Storage.StoragePoolType> destinationStoragePoolTypes,
3740
DataStoreTO conversionTemporaryLocation, String temporaryConvertUuid,
3841
boolean forceConvertToPool) {
3942
this.sourceInstance = sourceInstance;
4043
this.destinationStoragePools = destinationStoragePools;
44+
this.destinationStoragePoolTypes = destinationStoragePoolTypes;
4145
this.conversionTemporaryLocation = conversionTemporaryLocation;
4246
this.temporaryConvertUuid = temporaryConvertUuid;
4347
this.forceConvertToPool = forceConvertToPool;
4448
}
4549

50+
public ImportConvertedInstanceCommand(RemoteInstanceTO sourceInstance,
51+
List<String> destinationStoragePools,
52+
DataStoreTO conversionTemporaryLocation, String temporaryConvertUuid,
53+
boolean forceConvertToPool) {
54+
this(sourceInstance, destinationStoragePools, null, conversionTemporaryLocation, temporaryConvertUuid, forceConvertToPool);
55+
}
56+
4657
public RemoteInstanceTO getSourceInstance() {
4758
return sourceInstance;
4859
}
@@ -51,6 +62,10 @@ public List<String> getDestinationStoragePools() {
5162
return destinationStoragePools;
5263
}
5364

65+
public List<Storage.StoragePoolType> getDestinationStoragePoolTypes() {
66+
return destinationStoragePoolTypes;
67+
}
68+
5469
public DataStoreTO getConversionTemporaryLocation() {
5570
return conversionTemporaryLocation;
5671
}

engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -808,8 +808,13 @@ protected AgentAttache notifyMonitorsOfConnection(final AgentAttache attache, fi
808808
String vddkSupport = detailsMap.get(Host.HOST_VDDK_SUPPORT);
809809
String vddkLibDir = detailsMap.get(Host.HOST_VDDK_LIB_DIR);
810810
String vddkVersion = detailsMap.get(Host.HOST_VDDK_VERSION);
811+
String virtv2vInPlaceSupport = detailsMap.get(Host.HOST_VIRTV2V_INPLACE_SUPPORT);
812+
String qemuImgRbdSupport = detailsMap.get(Host.HOST_QEMU_IMG_RBD_SUPPORT);
813+
String rbdQemuCopySupport = detailsMap.get(Host.HOST_RBD_QEMU_COPY_SUPPORT);
814+
String vddkRbdDirectImportSupport = detailsMap.get(Host.HOST_VDDK_RBD_DIRECT_IMPORT_SUPPORT);
811815
logger.debug("Got HOST_UEFI_ENABLE [{}] for host [{}]:", uefiEnabled, host);
812-
if (ObjectUtils.anyNotNull(uefiEnabled, virtv2vVersion, ovftoolVersion, vddkSupport, vddkLibDir, vddkVersion)) {
816+
if (ObjectUtils.anyNotNull(uefiEnabled, virtv2vVersion, ovftoolVersion, vddkSupport, vddkLibDir, vddkVersion,
817+
virtv2vInPlaceSupport, qemuImgRbdSupport, rbdQemuCopySupport, vddkRbdDirectImportSupport)) {
813818
_hostDao.loadDetails(host);
814819
boolean updateNeeded = false;
815820
if (StringUtils.isNotBlank(uefiEnabled) && !uefiEnabled.equals(host.getDetails().get(Host.HOST_UEFI_ENABLE))) {
@@ -844,6 +849,22 @@ protected AgentAttache notifyMonitorsOfConnection(final AgentAttache attache, fi
844849
}
845850
updateNeeded = true;
846851
}
852+
if (StringUtils.isNotBlank(virtv2vInPlaceSupport) && !virtv2vInPlaceSupport.equals(host.getDetails().get(Host.HOST_VIRTV2V_INPLACE_SUPPORT))) {
853+
host.getDetails().put(Host.HOST_VIRTV2V_INPLACE_SUPPORT, virtv2vInPlaceSupport);
854+
updateNeeded = true;
855+
}
856+
if (StringUtils.isNotBlank(qemuImgRbdSupport) && !qemuImgRbdSupport.equals(host.getDetails().get(Host.HOST_QEMU_IMG_RBD_SUPPORT))) {
857+
host.getDetails().put(Host.HOST_QEMU_IMG_RBD_SUPPORT, qemuImgRbdSupport);
858+
updateNeeded = true;
859+
}
860+
if (StringUtils.isNotBlank(rbdQemuCopySupport) && !rbdQemuCopySupport.equals(host.getDetails().get(Host.HOST_RBD_QEMU_COPY_SUPPORT))) {
861+
host.getDetails().put(Host.HOST_RBD_QEMU_COPY_SUPPORT, rbdQemuCopySupport);
862+
updateNeeded = true;
863+
}
864+
if (StringUtils.isNotBlank(vddkRbdDirectImportSupport) && !vddkRbdDirectImportSupport.equals(host.getDetails().get(Host.HOST_VDDK_RBD_DIRECT_IMPORT_SUPPORT))) {
865+
host.getDetails().put(Host.HOST_VDDK_RBD_DIRECT_IMPORT_SUPPORT, vddkRbdDirectImportSupport);
866+
updateNeeded = true;
867+
}
847868
if (updateNeeded) {
848869
_hostDao.saveDetails(host);
849870
}

0 commit comments

Comments
 (0)