Visitar URL original
CloudStack Volume support with ONTAP storage (#13053) · apache/cloudstack@3327e14 · GitHub
Skip to content

Commit 3327e14

Browse files
rajiv-jain-netappJain, Rajivsuryag1201Gupta, SuryaLocharla, Sandeep
authored
CloudStack Volume support with ONTAP storage (#13053)
Co-authored-by: Jain, Rajiv <Rajiv.Jain@netapp.com> Co-authored-by: Surya Gupta <suryag@netapp.com> Co-authored-by: Gupta, Surya <Surya.Gupta@netapp.com> Co-authored-by: Locharla, Sandeep <Sandeep.Locharla@netapp.com> Co-authored-by: Srivastava, Piyush <Piyush.Srivastava@netapp.com>
1 parent b7d4df0 commit 3327e14

47 files changed

Lines changed: 9388 additions & 490 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.

‎.github/CODEOWNERS‎

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

1818
/plugins/storage/volume/linstor @rp-
1919
/plugins/storage/volume/storpool @slavkap
20-
/plugins/storage/volume/ontap @rajiv1 @sandeeplocharla @piyush5 @suryag
20+
/plugins/storage/volume/ontap @rajiv-jain-netapp @sandeeplocharla @piyush5netapp @suryag1201
2121

2222
.pre-commit-config.yaml @jbampton
2323
/.github/linters/ @jbampton

‎engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ public interface DataStoreProvider {
2929
String SAMPLE_IMAGE = "Sample";
3030
String SMB = "NFS";
3131
String DEFAULT_PRIMARY = "DefaultPrimary";
32+
/**
33+
* Primary storage provider name for NetApp ONTAP ({@code OntapPrimaryDatastoreProvider#getName}).
34+
* Single canonical value; use this instead of duplicating the string across modules.
35+
*/
36+
String ONTAP_PLUGIN_NAME = "NetApp ONTAP";
3237

3338
enum DataStoreProviderType {
3439
PRIMARY, IMAGE, ImageCache, OBJECT

‎engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/KvmFileBasedStorageVmSnapshotStrategy.java‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import com.cloud.vm.snapshot.VMSnapshotVO;
5252
import org.apache.cloudstack.backup.BackupOfferingVO;
5353
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
54+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
5455
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
5556
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
5657
import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
@@ -325,8 +326,13 @@ public StrategyPriority canHandle(Long vmId, Long rootPoolId, boolean snapshotMe
325326
List<VolumeVO> volumes = volumeDao.findByInstance(vmId);
326327
for (VolumeVO volume : volumes) {
327328
StoragePoolVO storagePoolVO = storagePool.findById(volume.getPoolId());
329+
if (storagePoolVO.isManaged() && DataStoreProvider.ONTAP_PLUGIN_NAME.equals(storagePoolVO.getStorageProviderName())) {
330+
logger.debug("{} as the VM has a volume on ONTAP managed storage pool [{}]. " +
331+
"ONTAP managed storage has its own dedicated VM snapshot strategy.", cantHandleLog, storagePoolVO.getName());
332+
return StrategyPriority.CANT_HANDLE;
333+
}
328334
if (!supportedStoragePoolTypes.contains(storagePoolVO.getPoolType())) {
329-
logger.debug(String.format("%s as the VM has a volume that is in a storage with unsupported type [%s].", cantHandleLog, storagePoolVO.getPoolType()));
335+
logger.debug("{} as the VM has a volume that is in a storage with unsupported type [{}].", cantHandleLog, storagePoolVO.getPoolType());
330336
return StrategyPriority.CANT_HANDLE;
331337
}
332338
List<SnapshotVO> snapshots = snapshotDao.listByVolumeIdAndTypeNotInAndStateNotRemoved(volume.getId(), Snapshot.Type.GROUP);
@@ -503,8 +509,9 @@ protected VMSnapshot takeVmSnapshotInternal(VMSnapshot vmSnapshot, Map<VolumeInf
503509
return processCreateVmSnapshotAnswer(vmSnapshot, volumeInfoToSnapshotObjectMap, createDiskOnlyVMSnapshotAnswer, userVm, vmSnapshotVO, virtualSize, parentSnapshotVo);
504510
}
505511

506-
logger.error("Disk-only VM snapshot for VM [{}] failed{}.", userVm.getUuid(), answer != null ? " due to" + answer.getDetails() : "");
507-
throw new CloudRuntimeException(String.format("Disk-only VM snapshot for VM [%s] failed.", userVm.getUuid()));
512+
String details = answer != null ? answer.getDetails() : String.format("No answer received from host [%s]. The host may be unreachable.", hostId);
513+
logger.error("Disk-only VM snapshot for VM [{}] failed due to: {}.", userVm.getUuid(), details);
514+
throw new CloudRuntimeException(String.format("Disk-only VM snapshot for VM [%s] failed due to: %s.", userVm.getUuid(), details));
508515
}
509516

510517
/**

‎engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
import org.apache.cloudstack.storage.to.TemplateObjectTO;
8787
import org.apache.cloudstack.storage.to.VolumeObjectTO;
8888
import org.apache.commons.collections.CollectionUtils;
89+
import org.apache.commons.lang3.ObjectUtils;
8990
import org.apache.commons.lang3.StringUtils;
9091
import org.apache.logging.log4j.Logger;
9192
import org.apache.logging.log4j.LogManager;
@@ -1362,6 +1363,11 @@ private void createManagedVolumeCopyTemplateAsync(VolumeInfo volumeInfo, Primary
13621363
primaryDataStore.setDetails(details);
13631364

13641365
grantAccess(volumeInfo, destHost, primaryDataStore);
1366+
volumeInfo = volFactory.getVolume(volumeInfo.getId(), primaryDataStore);
1367+
// For Netapp ONTAP iscsiName or Lun path is available only after grantAccess
1368+
String managedStoreTarget = ObjectUtils.defaultIfNull(volumeInfo.get_iScsiName(), volumeInfo.getUuid());
1369+
details.put(PrimaryDataStore.MANAGED_STORE_TARGET, managedStoreTarget);
1370+
primaryDataStore.setDetails(details);
13651371

13661372
try {
13671373
motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller);

‎plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCreateDiskOnlyVMSnapshotCommandWrapper.java‎

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ protected Answer takeDiskOnlyVmSnapshotOfRunningVm(CreateDiskOnlyVmSnapshotComma
106106
return new CreateDiskOnlyVmSnapshotAnswer(cmd, false, errorMsg, null);
107107
}
108108
return new CreateDiskOnlyVmSnapshotAnswer(cmd, false, e.getMessage(), null);
109+
} catch (Exception e) {
110+
String errorMsg = String.format("Creation of disk-only VM snapshot for VM [%s] failed due to %s.", vmName, e.getMessage());
111+
logger.error(errorMsg, e);
112+
return new CreateDiskOnlyVmSnapshotAnswer(cmd, false, errorMsg, null);
109113
} finally {
110114
if (dm != null) {
111115
try {
@@ -146,21 +150,13 @@ protected Answer takeDiskOnlyVmSnapshotOfStoppedVm(CreateDiskOnlyVmSnapshotComma
146150
}
147151
} catch (LibvirtException | QemuImgException e) {
148152
logger.error("Exception while creating disk-only VM snapshot for VM [{}]. Deleting leftover deltas.", vmName, e);
149-
for (VolumeObjectTO volumeObjectTO : volumeObjectTos) {
150-
Pair<Long, String> volSizeAndNewPath = mapVolumeToSnapshotSizeAndNewVolumePath.get(volumeObjectTO.getUuid());
151-
PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO) volumeObjectTO.getDataStore();
152-
KVMStoragePool kvmStoragePool = storagePoolMgr.getStoragePool(primaryDataStoreTO.getPoolType(), primaryDataStoreTO.getUuid());
153-
154-
if (volSizeAndNewPath == null) {
155-
continue;
156-
}
157-
try {
158-
Files.deleteIfExists(Path.of(kvmStoragePool.getLocalPathFor(volSizeAndNewPath.second())));
159-
} catch (IOException ex) {
160-
logger.warn("Tried to delete leftover snapshot at [{}] failed.", volSizeAndNewPath.second(), ex);
161-
}
162-
}
153+
cleanupLeftoverDeltas(volumeObjectTos, mapVolumeToSnapshotSizeAndNewVolumePath, storagePoolMgr);
163154
return new Answer(cmd, e);
155+
} catch (Exception e) {
156+
logger.error("Unexpected exception while creating disk-only VM snapshot for VM [{}]. Deleting leftover deltas.", vmName, e);
157+
cleanupLeftoverDeltas(volumeObjectTos, mapVolumeToSnapshotSizeAndNewVolumePath, storagePoolMgr);
158+
return new CreateDiskOnlyVmSnapshotAnswer(cmd, false,
159+
String.format("Creation of disk-only VM snapshot for VM [%s] failed due to %s.", vmName, e.getMessage()), null);
164160
}
165161

166162
return new CreateDiskOnlyVmSnapshotAnswer(cmd, true, null, mapVolumeToSnapshotSizeAndNewVolumePath);
@@ -192,6 +188,23 @@ protected Pair<String, Map<String, Pair<Long, String>>> createSnapshotXmlAndNewV
192188
return new Pair<>(snapshotXml, volumeObjectToNewPathMap);
193189
}
194190

191+
protected void cleanupLeftoverDeltas(List<VolumeObjectTO> volumeObjectTos, Map<String, Pair<Long, String>> mapVolumeToSnapshotSizeAndNewVolumePath, KVMStoragePoolManager storagePoolMgr) {
192+
for (VolumeObjectTO volumeObjectTO : volumeObjectTos) {
193+
Pair<Long, String> volSizeAndNewPath = mapVolumeToSnapshotSizeAndNewVolumePath.get(volumeObjectTO.getUuid());
194+
PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO) volumeObjectTO.getDataStore();
195+
KVMStoragePool kvmStoragePool = storagePoolMgr.getStoragePool(primaryDataStoreTO.getPoolType(), primaryDataStoreTO.getUuid());
196+
197+
if (volSizeAndNewPath == null) {
198+
continue;
199+
}
200+
try {
201+
Files.deleteIfExists(Path.of(kvmStoragePool.getLocalPathFor(volSizeAndNewPath.second())));
202+
} catch (IOException ex) {
203+
logger.warn("Tried to delete leftover snapshot at [{}] failed.", volSizeAndNewPath.second(), ex);
204+
}
205+
}
206+
}
207+
195208
protected long getFileSize(String path) {
196209
return new File(path).length();
197210
}

0 commit comments

Comments
 (0)