Skip to content

Commit bced4c7

Browse files
author
Mike Tutkowski
committed
Add support for hypervisor snapshots to CloudStack-managed storage (for XenServer and VMware)
1 parent 66b8537 commit bced4c7

12 files changed

Lines changed: 172 additions & 107 deletions

File tree

core/src/com/cloud/agent/api/AttachVolumeCommand.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class AttachVolumeCommand extends Command {
2525
private StoragePoolType pooltype;
2626
private String volumePath;
2727
private String volumeName;
28+
private Long volumeSize;
2829
private Long deviceId;
2930
private String chainInfo;
3031
private String poolUuid;
@@ -45,13 +46,14 @@ protected AttachVolumeCommand() {
4546

4647
public AttachVolumeCommand(boolean attach, boolean managed, String vmName,
4748
StoragePoolType pooltype, String volumePath, String volumeName,
48-
Long deviceId, String chainInfo) {
49+
Long volumeSize, Long deviceId, String chainInfo) {
4950
this.attach = attach;
5051
this._managed = managed;
5152
this.vmName = vmName;
5253
this.pooltype = pooltype;
5354
this.volumePath = volumePath;
5455
this.volumeName = volumeName;
56+
this.volumeSize = volumeSize;
5557
this.deviceId = deviceId;
5658
this.chainInfo = chainInfo;
5759
}
@@ -85,6 +87,10 @@ public String getVolumeName() {
8587
return volumeName;
8688
}
8789

90+
public Long getVolumeSize() {
91+
return volumeSize;
92+
}
93+
8894
public Long getDeviceId() {
8995
return deviceId;
9096
}

core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
public class AttachVolumeAnswerTest {
2929
AttachVolumeCommand avc = new AttachVolumeCommand(true, false, "vmname",
30-
StoragePoolType.Filesystem, "vPath", "vName",
30+
StoragePoolType.Filesystem, "vPath", "vName", 1073741824L,
3131
123456789L, "chainInfo");
3232
AttachVolumeAnswer ava1 = new AttachVolumeAnswer(avc);
3333
String results = "";

core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
public class AttachVolumeCommandTest {
2828
AttachVolumeCommand avc = new AttachVolumeCommand(true, false, "vmname",
29-
StoragePoolType.Filesystem, "vPath", "vName",
29+
StoragePoolType.Filesystem, "vPath", "vName", 1073741824L,
3030
123456789L, "chainInfo");
3131

3232
@Test

plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.cloud.hypervisor.vmware.manager;
1818

1919
import com.cloud.agent.api.Command;
20+
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
2021
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
2122
import com.cloud.hypervisor.vmware.util.VmwareContext;
2223
import com.vmware.vim25.ManagedObjectReference;
@@ -28,7 +29,8 @@ public interface VmwareHostService {
2829

2930
String getWorkerName(VmwareContext context, Command cmd, int workerSequence);
3031

31-
ManagedObjectReference handleDatastoreAndVmdkAttach(Command cmd, String iqn, String storageHost, int storagePort,
32-
String initiatorUsername, String initiatorPassword, String targetUsername, String targetPassword) throws Exception;
32+
ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber,
33+
String iqn, String initiatorChapName, String initiatorChapSecret, String mutualChapName, String mutualChapSecret) throws Exception;
34+
void createVmdk(Command cmd, DatastoreMO dsMo, String volumeDatastorePath, Long volumeSize) throws Exception;
3335
void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception;
3436
}

plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4439,7 +4439,7 @@ public static String getDatastoreName(String str) {
44394439
return str.replace('/', '-');
44404440
}
44414441

4442-
private String trimIqn(String iqn) {
4442+
public static String trimIqn(String iqn) {
44434443
String[] tmp = iqn.split("/");
44444444

44454445
if (tmp.length != 3) {
@@ -4454,36 +4454,23 @@ private String trimIqn(String iqn) {
44544454
}
44554455

44564456
@Override
4457-
public ManagedObjectReference handleDatastoreAndVmdkAttach(Command cmd, String iqn, String storageHost, int storagePort,
4458-
String initiatorUsername, String initiatorPassword, String targetUsername, String targetPassword) throws Exception {
4457+
public void createVmdk(Command cmd, DatastoreMO dsMo, String vmdkDatastorePath, Long volumeSize) throws Exception {
44594458
VmwareContext context = getServiceContext();
44604459
VmwareHypervisorHost hyperHost = getHyperHost(context);
44614460

4462-
ManagedObjectReference morDs = createVmfsDatastore(hyperHost, getDatastoreName(iqn),
4463-
storageHost, storagePort, trimIqn(iqn),
4464-
initiatorUsername, initiatorPassword,
4465-
targetUsername, targetPassword);
4461+
String dummyVmName = getWorkerName(context, cmd, 0);
44664462

4467-
DatastoreMO dsMo = new DatastoreMO(context, morDs);
4463+
VirtualMachineMO vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
44684464

4469-
String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName());
4470-
4471-
if (!dsMo.fileExists(volumeDatastorePath)) {
4472-
String dummyVmName = getWorkerName(context, cmd, 0);
4473-
4474-
VirtualMachineMO vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
4475-
4476-
if (vmMo == null) {
4477-
throw new Exception("Unable to create a dummy VM for volume creation");
4478-
}
4479-
4480-
vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dsMo.getSummary().getFreeSpace()),
4481-
morDs, vmMo.getScsiDeviceControllerKey());
4482-
vmMo.detachDisk(volumeDatastorePath, false);
4483-
vmMo.destroy();
4465+
if (vmMo == null) {
4466+
throw new Exception("Unable to create a dummy VM for volume creation");
44844467
}
44854468

4486-
return morDs;
4469+
Long volumeSizeToUse = volumeSize < dsMo.getSummary().getFreeSpace() ? volumeSize : dsMo.getSummary().getFreeSpace();
4470+
4471+
vmMo.createDisk(vmdkDatastorePath, getMBsFromBytes(volumeSizeToUse), dsMo.getMor(), vmMo.getScsiDeviceControllerKey());
4472+
vmMo.detachDisk(vmdkDatastorePath, false);
4473+
vmMo.destroy();
44874474
}
44884475

44894476
@Override
@@ -4516,9 +4503,16 @@ protected Answer execute(AttachVolumeCommand cmd) {
45164503
ManagedObjectReference morDs = null;
45174504

45184505
if (cmd.getAttach() && cmd.isManaged()) {
4519-
morDs = handleDatastoreAndVmdkAttach(cmd, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.getStoragePort(),
4520-
cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(),
4521-
cmd.getChapTargetUsername(), cmd.getChapTargetPassword());
4506+
morDs = getVmfsDatastore(hyperHost, getDatastoreName(cmd.get_iScsiName()), cmd.getStorageHost(), cmd.getStoragePort(), trimIqn(cmd.get_iScsiName()),
4507+
cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(), cmd.getChapTargetUsername(), cmd.getChapTargetPassword());
4508+
4509+
DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs);
4510+
4511+
String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName());
4512+
4513+
if (!dsMo.fileExists(volumeDatastorePath)) {
4514+
createVmdk(cmd, dsMo, VmwareResource.getDatastoreName(cmd.get_iScsiName()), cmd.getVolumeSize());
4515+
}
45224516
}
45234517
else {
45244518
morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
@@ -4531,10 +4525,18 @@ protected Answer execute(AttachVolumeCommand cmd) {
45314525
}
45324526

45334527
DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs);
4534-
VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), cmd.getVmName(),
4535-
dsMo, cmd.getVolumePath());
4536-
4537-
String datastoreVolumePath = dsMo.searchFileInSubFolders(cmd.getVolumePath() + ".vmdk", true);
4528+
4529+
String datastoreVolumePath = null;
4530+
4531+
if (cmd.isManaged()) {
4532+
datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
4533+
}
4534+
else {
4535+
VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), cmd.getVmName(), dsMo, cmd.getVolumePath());
4536+
4537+
datastoreVolumePath = dsMo.searchFileInSubFolders(cmd.getVolumePath() + ".vmdk", true);
4538+
}
4539+
45384540
assert (datastoreVolumePath != null) : "Virtual disk file must exist in specified datastore for attach/detach operations.";
45394541
if (datastoreVolumePath == null) {
45404542
throw new CloudRuntimeException("Unable to find file " + cmd.getVolumePath() + ".vmdk in datastore " + dsMo.getName());
@@ -4687,7 +4689,7 @@ public void run() {
46874689
}
46884690
}
46894691

4690-
private ManagedObjectReference createVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress,
4692+
public ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress,
46914693
int storagePortNumber, String iqn, String chapName, String chapSecret, String mutualChapName, String mutualChapSecret) throws Exception {
46924694
VmwareContext context = getServiceContext();
46934695
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();

plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import com.cloud.hypervisor.vmware.manager.VmwareStorageManagerImpl;
3838
import com.cloud.hypervisor.vmware.manager.VmwareStorageMount;
3939
import com.cloud.hypervisor.vmware.mo.ClusterMO;
40+
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
4041
import com.cloud.hypervisor.vmware.mo.HostMO;
4142
import com.cloud.hypervisor.vmware.mo.VmwareHostType;
4243
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
@@ -347,8 +348,12 @@ private boolean validateContext(VmwareContext context, Command cmd) {
347348
return true;
348349
}
349350

350-
public ManagedObjectReference handleDatastoreAndVmdkAttach(Command cmd, String iqn, String storageHost, int storagePort,
351-
String initiatorUsername, String initiatorPassword, String targetUsername, String targetPassword) throws Exception {
351+
public ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber,
352+
String iqn, String initiatorChapName, String initiatorChapSecret, String mutualChapName, String mutualChapSecret) throws Exception {
353+
throw new OperationNotSupportedException();
354+
}
355+
356+
public void createVmdk(Command cmd, DatastoreMO dsMo, String volumeDatastorePath, Long volumeSize) throws Exception {
352357
throw new OperationNotSupportedException();
353358
}
354359

plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,8 +1191,16 @@ private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean
11911191
ManagedObjectReference morDs = null;
11921192

11931193
if (isAttach && isManaged) {
1194-
morDs = hostService.handleDatastoreAndVmdkAttach(cmd, iScsiName, storageHost, storagePort,
1195-
initiatorUsername, initiatorPassword, targetUsername, targetPassword);
1194+
morDs = hostService.getVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iScsiName), storageHost, storagePort,
1195+
VmwareResource.trimIqn(iScsiName), initiatorUsername, initiatorPassword, targetUsername, targetPassword);
1196+
1197+
DatastoreMO dsMo = new DatastoreMO(hostService.getServiceContext(null), morDs);
1198+
1199+
String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName());
1200+
1201+
if (!dsMo.fileExists(volumeDatastorePath)) {
1202+
hostService.createVmdk(cmd, dsMo, VmwareResource.getDatastoreName(iScsiName), volumeTO.getSize());
1203+
}
11961204
}
11971205
else {
11981206
morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid());
@@ -1207,24 +1215,35 @@ private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean
12071215
DatastoreMO dsMo = new DatastoreMO(this.hostService.getServiceContext(null), morDs);
12081216
String datastoreVolumePath;
12091217

1210-
if(isAttach) {
1211-
if(!isManaged)
1212-
datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName,
1213-
dsMo, volumeTO.getPath());
1214-
else
1218+
if (isAttach) {
1219+
if (isManaged) {
12151220
datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
1216-
} else {
1217-
datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk");
1218-
if(!dsMo.fileExists(datastoreVolumePath))
1219-
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk");
1221+
}
1222+
else {
1223+
datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, dsMo, volumeTO.getPath());
1224+
}
1225+
}
1226+
else {
1227+
if (isManaged) {
1228+
datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
1229+
}
1230+
else {
1231+
datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk");
1232+
1233+
if (!dsMo.fileExists(datastoreVolumePath)) {
1234+
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk");
1235+
}
1236+
}
12201237
}
12211238

12221239
disk.setVdiUuid(datastoreVolumePath);
12231240

12241241
AttachAnswer answer = new AttachAnswer(disk);
1242+
12251243
if (isAttach) {
12261244
vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
1227-
} else {
1245+
}
1246+
else {
12281247
vmMo.removeAllSnapshots();
12291248
vmMo.detachDisk(datastoreVolumePath, false);
12301249

0 commit comments

Comments
 (0)