Skip to content

Commit e964395

Browse files
authored
vmware: improve solidfire storage plugin integration and fix cases (#3) (#7761)
This fixes the following cases in which Solidfire storage integration caused issues when using Solidfire datadisks with VMware: 1. Take Volume Snapshot of Solidfire data disk 2. Delete an active Instance with Solidfire data disk attached 3. Attach used existing Solidfire data disk to a running/stopped VM 4. Stop and Start an instance with Solidfire data disks attached 5. Expand disk by resizing Solidfire data disk by providing size 6. Expand disk by changing disk offering for the Solidfire data disk Additional changes: - Use VMFS6 as managed datastore type if the host supports - Refactor detection and splitting of managed storage ds name in storage processor - Restrict storage rescanning for managed datastore when resizing Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
1 parent 3c38ed7 commit e964395

File tree

8 files changed

+86
-24
lines changed

8 files changed

+86
-24
lines changed

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,8 +1906,8 @@ public void prepare(VirtualMachineProfile vm, DeployDestination dest) throws Sto
19061906
throw new StorageAccessException(String.format("Unable to grant access to volume [%s] on host [%s].", volToString, host));
19071907
}
19081908
} else {
1909-
// This might impact other managed storages, grant access for PowerFlex storage pool only
1910-
if (pool.getPoolType() == Storage.StoragePoolType.PowerFlex) {
1909+
// This might impact other managed storages, grant access for PowerFlex and Iscsi/Solidfire storage pool only
1910+
if (pool.getPoolType() == Storage.StoragePoolType.PowerFlex || pool.getPoolType() == Storage.StoragePoolType.Iscsi) {
19111911
try {
19121912
volService.grantAccess(volFactory.getVolume(vol.getId()), host, (DataStore)pool);
19131913
} catch (Exception e) {

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,12 +1107,25 @@ private static String getSnapshotRelativeDirInSecStorage(long accountId, long vo
11071107
return "snapshots/" + accountId + "/" + volumeId;
11081108
}
11091109

1110+
protected boolean isManagedStorageDatastorePath(final String datastorePath) {
1111+
// ex. [-iqn.2010-01.com.solidfire:3p53.data-9999.97-0] i-2-9999-VM
1112+
return datastorePath != null && datastorePath.startsWith("[-iqn.");
1113+
}
1114+
1115+
protected String getManagedDatastoreName(final String datastorePath) {
1116+
// ex. [-iqn.2010-01.com.solidfire:3p53.data-9999.97-0]
1117+
return datastorePath == null ? datastorePath : datastorePath.split(" ")[0];
1118+
}
1119+
11101120
private long getVMSnapshotChainSize(VmwareContext context, VmwareHypervisorHost hyperHost, String fileName, ManagedObjectReference morDs,
11111121
String exceptFileName, String vmName) throws Exception {
11121122
long size = 0;
11131123
DatastoreMO dsMo = new DatastoreMO(context, morDs);
11141124
HostDatastoreBrowserMO browserMo = dsMo.getHostDatastoreBrowserMO();
11151125
String datastorePath = (new DatastoreFile(dsMo.getName(), vmName)).getPath();
1126+
if (isManagedStorageDatastorePath(datastorePath)) {
1127+
datastorePath = getManagedDatastoreName(datastorePath);
1128+
}
11161129
HostDatastoreBrowserSearchSpec searchSpec = new HostDatastoreBrowserSearchSpec();
11171130
FileQueryFlags fqf = new FileQueryFlags();
11181131
fqf.setFileSize(true);
@@ -1241,11 +1254,9 @@ private Map<String, String> getNewDiskMap(VirtualMachineMO vmMo) throws Exceptio
12411254
String vmdkName = null;
12421255

12431256
// if this is managed storage
1244-
if (fullPath.startsWith("[-iqn.")) { // ex. [-iqn.2010-01.com.company:3y8w.vol-10.64-0] -iqn.2010-01.com.company:3y8w.vol-10.64-0-000001.vmdk
1245-
baseName = fullPath.split(" ")[0]; // ex. [-iqn.2010-01.com.company:3y8w.vol-10.64-0]
1246-
1247-
// remove '[' and ']'
1248-
baseName = baseName.substring(1, baseName.length() - 1);
1257+
if (isManagedStorageDatastorePath(fullPath)) {
1258+
baseName = getManagedDatastoreName(fullPath);
1259+
baseName = baseName.substring(1, baseName.length() - 1); // remove '[' and ']'
12491260

12501261
vmdkName = fullPath; // for managed storage, vmdkName == fullPath
12511262
} else {
@@ -1288,12 +1299,9 @@ protected void setVolumeToPathAndSize(List<VolumeObjectTO> volumeTOs, VirtualMac
12881299
}
12891300
} else {
12901301
Map<String, String> mapNewDisk = getNewDiskMap(vmMo);
1291-
// if this is managed storage
1292-
if (path.startsWith("[-iqn.")) { // ex. [-iqn.2010-01.com.company:3y8w.vol-10.64-0] -iqn.2010-01.com.company:3y8w.vol-10.64-0-000001.vmdk
1293-
path = path.split(" ")[0]; // ex. [-iqn.2010-01.com.company:3y8w.vol-10.64-0]
1294-
1295-
// remove '[' and ']'
1296-
baseName = path.substring(1, path.length() - 1);
1302+
if (isManagedStorageDatastorePath(path)) {
1303+
path = getManagedDatastoreName(path);
1304+
baseName = path.substring(1, path.length() - 1); // remove '[' and ']'
12971305
} else {
12981306
baseName = VmwareHelper.trimSnapshotDeltaPostfix(path);
12991307
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,11 @@ private Answer execute(ResizeVolumeCommand cmd) {
940940
ManagedObjectReference morDS = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, VmwareResource.getDatastoreName(iScsiName));
941941
DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDS);
942942

943+
if (path.startsWith("[-iqn.")) {
944+
// Rescan 1:1 LUN that VMware may not know the LUN was recently resized
945+
_storageProcessor.rescanAllHosts(context, lstHosts, true, true);
946+
}
947+
943948
_storageProcessor.expandDatastore(hostDatastoreSystem, dsMo);
944949
}
945950

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2825,7 +2825,15 @@ private ManagedObjectReference getVmfsDatastore(VmwareContext context, VmwareHyp
28252825

28262826
morDs = firstHostDatastoreSystemMO.findDatastoreByName(datastoreName);
28272827
if (morDs == null) {
2828-
morDs = firstHostDatastoreSystemMO.createVmfsDatastore(datastoreName, hostScsiDisk);
2828+
final String hostVersion = firstHostMO.getProductVersion();
2829+
if (hostVersion.compareTo(VmwareHelper.MIN_VERSION_VMFS6) >= 0) {
2830+
morDs = firstHostDatastoreSystemMO.createVmfs6Datastore(datastoreName, hostScsiDisk);
2831+
} else {
2832+
morDs = firstHostDatastoreSystemMO.createVmfs5Datastore(datastoreName, hostScsiDisk);
2833+
}
2834+
} else {
2835+
// in case of iSCSI/solidfire 1:1 VMFS datastore could be inaccessible
2836+
mountVmfsDatastore(new DatastoreMO(context, morDs), lstHosts);
28292837
}
28302838

28312839
if (morDs != null) {
@@ -3364,7 +3372,7 @@ private void addRemoveInternetScsiTargetsToAllHosts(boolean add, List<HostIntern
33643372
}
33653373
}
33663374

3367-
private void rescanAllHosts(VmwareContext context, List<Pair<ManagedObjectReference, String>> lstHostPairs, boolean rescanHba, boolean rescanVmfs) throws Exception {
3375+
public void rescanAllHosts(VmwareContext context, List<Pair<ManagedObjectReference, String>> lstHostPairs, boolean rescanHba, boolean rescanVmfs) throws Exception {
33683376
List<HostMO> hosts = new ArrayList<>(lstHostPairs.size());
33693377

33703378
for (Pair<ManagedObjectReference, String> hostPair : lstHostPairs) {

plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImplTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,15 @@ public void testSetVolumeToPathAndSizeDatastoreClusterSameChildStore() {
116116
public void testSetVolumeToPathAndSizeDatastoreClusterDifferentChildStore() {
117117
testCommon(Storage.StoragePoolType.PreSetup, Storage.StoragePoolType.DatastoreCluster, true);
118118
}
119+
120+
@Test
121+
public void testIsManagedStorageDatastorePath() {
122+
Assert.assertTrue("Test if [-iqn... is a managed storage", storageManager.isManagedStorageDatastorePath("[-iqn.2010-01.com.solidfire:3p53.data-9999.97-0] i-2-9999-VM.vmdk"));
123+
Assert.assertFalse("Test if [SomeDS] is not a managed storage", storageManager.isManagedStorageDatastorePath("[SomeDS] i-2-9999-VM/disk.vmdk"));
124+
}
125+
126+
@Test
127+
public void testGetManagedDatastoreName() {
128+
Assert.assertEquals("[-iqn.2010-01.com.solidfire:3p53.data-9999.97-0]", storageManager.getManagedDatastoreName("[-iqn.2010-01.com.solidfire:3p53.data-9999.97-0] i-2-9999-VM.vmdk"));
129+
}
119130
}

plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.apache.cloudstack.storage.datastore.driver;
1818

1919
import java.text.NumberFormat;
20+
import java.util.Arrays;
2021
import java.util.ArrayList;
2122
import java.util.HashMap;
2223
import java.util.List;
@@ -85,6 +86,8 @@
8586
import com.cloud.utils.Pair;
8687
import com.cloud.utils.db.GlobalLock;
8788
import com.cloud.utils.exception.CloudRuntimeException;
89+
import com.cloud.vm.dao.VMInstanceDao;
90+
import com.cloud.vm.VirtualMachine;
8891
import com.google.common.base.Preconditions;
8992

9093
public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
@@ -111,6 +114,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
111114
@Inject private PrimaryDataStoreDao storagePoolDao;
112115
@Inject private StoragePoolDetailsDao storagePoolDetailsDao;
113116
@Inject private VMTemplatePoolDao vmTemplatePoolDao;
117+
@Inject private VMInstanceDao vmDao;
114118
@Inject private VolumeDao volumeDao;
115119
@Inject private VolumeDetailsDao volumeDetailsDao;
116120
@Inject private VolumeDataFactory volumeFactory;
@@ -187,13 +191,33 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore
187191
}
188192
}
189193

194+
private boolean isRevokeAccessNotNeeded(DataObject dataObject) {
195+
// Workaround: don't unplug iscsi lun when volume is attached to a VM
196+
// This is regression workaround from upper layers which are calling
197+
// a releaseVmResources() method that calls the revoke on an attached disk
198+
if (dataObject.getType() == DataObjectType.VOLUME) {
199+
Volume volume = volumeDao.findById(dataObject.getId());
200+
if (volume.getInstanceId() != null) {
201+
VirtualMachine vm = vmDao.findById(volume.getInstanceId());
202+
if (vm != null && !Arrays.asList(VirtualMachine.State.Destroyed, VirtualMachine.State.Expunging, VirtualMachine.State.Error).contains(vm.getState())) {
203+
return true;
204+
}
205+
}
206+
}
207+
return false;
208+
}
209+
190210
@Override
191-
public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore)
192-
{
211+
public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) {
193212
if (dataObject == null || host == null || dataStore == null) {
194213
return;
195214
}
196215

216+
if (isRevokeAccessNotNeeded(dataObject)) {
217+
LOGGER.debug("Skipping revoke access for Solidfire data object type:" + dataObject.getType() + " id:" + dataObject.getId());
218+
return;
219+
}
220+
197221
long sfVolumeId = getSolidFireVolumeId(dataObject, false);
198222
long clusterId = host.getClusterId();
199223
long storagePoolId = dataStore.getId();
@@ -210,6 +234,8 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore)
210234
throw new CloudRuntimeException(errMsg);
211235
}
212236

237+
LOGGER.debug("Revoking access for Solidfire data object type:" + dataObject.getType() + " id:" + dataObject.getId());
238+
213239
try {
214240
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
215241

vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,18 +199,21 @@ public List<HostScsiDisk> queryAvailableDisksForVmfs() throws Exception {
199199
return _context.getService().queryAvailableDisksForVmfs(_mor, null);
200200
}
201201

202-
public ManagedObjectReference createVmfsDatastore(String datastoreName, HostScsiDisk hostScsiDisk) throws Exception {
203-
// just grab the first instance of VmfsDatastoreOption
204-
VmfsDatastoreOption vmfsDatastoreOption = _context.getService().queryVmfsDatastoreCreateOptions(_mor, hostScsiDisk.getDevicePath(), 5).get(0);
205-
202+
public ManagedObjectReference createVmfsDatastore(String datastoreName, HostScsiDisk hostScsiDisk, Integer vmfsVersion) throws Exception {
203+
VmfsDatastoreOption vmfsDatastoreOption = _context.getService().queryVmfsDatastoreCreateOptions(_mor, hostScsiDisk.getDevicePath(), vmfsVersion).get(0);
206204
VmfsDatastoreCreateSpec vmfsDatastoreCreateSpec = (VmfsDatastoreCreateSpec)vmfsDatastoreOption.getSpec();
207-
208-
// set the name of the datastore to be created
209205
vmfsDatastoreCreateSpec.getVmfs().setVolumeName(datastoreName);
210-
211206
return _context.getService().createVmfsDatastore(_mor, vmfsDatastoreCreateSpec);
212207
}
213208

209+
public ManagedObjectReference createVmfs5Datastore(String datastoreName, HostScsiDisk hostScsiDisk) throws Exception {
210+
return createVmfsDatastore(datastoreName, hostScsiDisk, 5);
211+
}
212+
213+
public ManagedObjectReference createVmfs6Datastore(String datastoreName, HostScsiDisk hostScsiDisk) throws Exception {
214+
return createVmfsDatastore(datastoreName, hostScsiDisk, 6);
215+
}
216+
214217
public boolean deleteDatastore(String name) throws Exception {
215218
ManagedObjectReference morDatastore = findDatastore(name);
216219
if (morDatastore != null) {

vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareHelper.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public class VmwareHelper {
9898
public static final int MAX_SUPPORTED_DEVICES_SCSI_CONTROLLER = MAX_ALLOWED_DEVICES_SCSI_CONTROLLER - 1; // One device node is unavailable for hard disks or SCSI devices
9999
public static final int MAX_USABLE_SCSI_CONTROLLERS = 2;
100100
public static final String MIN_VERSION_UEFI_LEGACY = "5.5";
101+
public static final String MIN_VERSION_VMFS6 = "6.5";
101102

102103
public static boolean isReservedScsiDeviceNumber(int deviceNumber) {
103104
// The SCSI controller is assigned to virtual device node (z:7), so that device node is unavailable for hard disks or SCSI devices.

0 commit comments

Comments
 (0)