diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java index 9d811255e14..689ed12b64e 100755 --- a/api/src/com/cloud/host/Host.java +++ b/api/src/com/cloud/host/Host.java @@ -78,6 +78,11 @@ public interface Host extends StateObject, Identity, InternalIdentity { */ String getPrivateIpAddress(); + /** + * @return the ip address of the host. + */ + String getStorageUrl(); + /** * @return the ip address of the host attached to the storage network. */ diff --git a/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java index d266eb3aabe..9edbf102471 100644 --- a/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java +++ b/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java @@ -81,7 +81,10 @@ public class CheckOnHostCommandTest { return "10.1.1.1"; }; - @Override + public String getStorageUrl() { + return null; + } + public String getStorageIpAddress() { return "10.1.1.2"; }; diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java index 369ee9c01e9..c4dfc5ceb7e 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java @@ -21,12 +21,17 @@ package org.apache.cloudstack.engine.subsystem.api.storage; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; +import com.cloud.host.Host; import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; public interface PrimaryDataStoreDriver extends DataStoreDriver { public ChapInfo getChapInfo(VolumeInfo volumeInfo); + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); + + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); + public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool); public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java index bcc4e7f9c54..3f676ae73dc 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java @@ -44,6 +44,10 @@ public interface VolumeService { ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore); + boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); + + void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); + /** * Creates the volume based on the given criteria * diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java index dad64087e00..266baa73556 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java @@ -36,6 +36,7 @@ import org.apache.cloudstack.storage.to.SnapshotObjectTO; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; +import com.cloud.host.Host; import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; @@ -43,10 +44,21 @@ public class FakePrimaryDataStoreDriver implements PrimaryDataStoreDriver { boolean snapshotResult = true; @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { - return null; //To change body of implemented methods use File | Settings | File Templates. + public Map getCapabilities() { + return null; } + @Override + public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + return null; // To change body of implemented methods, use File | Settings | File Templates. + } + + @Override + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { return false; } + + @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {} + @Override public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { return volume.getSize(); diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index c9d7fabbaba..ac507cf4629 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -158,6 +158,24 @@ public class VolumeServiceImpl implements VolumeService { return null; } + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { + DataStoreDriver dataStoreDriver = dataStore.getDriver(); + + if (dataStoreDriver instanceof PrimaryDataStoreDriver) { + return ((PrimaryDataStoreDriver)dataStoreDriver).connectVolumeToHost(volumeInfo, host, dataStore); + } + + return false; + } + + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { + DataStoreDriver dataStoreDriver = dataStore.getDriver(); + + if (dataStoreDriver instanceof PrimaryDataStoreDriver) { + ((PrimaryDataStoreDriver)dataStoreDriver).disconnectVolumeFromHost(volumeInfo, host, dataStore); + } + } + @Override public AsyncCallFuture createVolumeAsync(VolumeInfo volume, DataStore dataStore) { AsyncCallFuture future = new AsyncCallFuture(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index c1d8bac6681..4aa6f27991a 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -4800,22 +4800,26 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa target.setPort(storagePortNumber); target.setIScsiName(iqn); - HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties(); + if (StringUtils.isNotBlank(chapName) && StringUtils.isNotBlank(chapSecret)) { + HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties(); - String strAuthType = "chapRequired"; + String strAuthType = "chapRequired"; - auth.setChapAuthEnabled(true); - auth.setChapInherited(false); - auth.setChapAuthenticationType(strAuthType); - auth.setChapName(chapName); - auth.setChapSecret(chapSecret); + auth.setChapAuthEnabled(true); + auth.setChapInherited(false); + auth.setChapAuthenticationType(strAuthType); + auth.setChapName(chapName); + auth.setChapSecret(chapSecret); - auth.setMutualChapInherited(false); - auth.setMutualChapAuthenticationType(strAuthType); - auth.setMutualChapName(mutualChapName); - auth.setMutualChapSecret(mutualChapSecret); + if (StringUtils.isNotBlank(mutualChapName) && StringUtils.isNotBlank(mutualChapSecret)) { + auth.setMutualChapInherited(false); + auth.setMutualChapAuthenticationType(strAuthType); + auth.setMutualChapName(mutualChapName); + auth.setMutualChapSecret(mutualChapSecret); + } - target.setAuthenticationProperties(auth); + target.setAuthenticationProperties(auth); + } final List lstTargets = new ArrayList(); @@ -6052,11 +6056,34 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa cmd.setName(_url); cmd.setGuid(_guid); cmd.setDataCenter(_dcId); + cmd.setIqn(getIqn()); cmd.setPod(_pod); cmd.setCluster(_cluster); cmd.setVersion(VmwareResource.class.getPackage().getImplementationVersion()); } + private String getIqn() { + try { + VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); + + if (hyperHost instanceof HostMO) { + HostMO host = (HostMO)hyperHost; + HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO(); + + for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) { + if (hba instanceof HostInternetScsiHba) { + return ((HostInternetScsiHba)hba).getIScsiName(); + } + } + } + } + catch (Exception ex) { + s_logger.info("Could not locate an IQN for this host."); + } + + return null; + } + private void fillHostHardwareInfo(VmwareContext serviceContext, StartupRoutingCommand cmd) throws RuntimeFaultFaultMsg, RemoteException, Exception { VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java index c8e2582894e..ae217b63595 100644 --- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java @@ -61,6 +61,7 @@ import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.configuration.Config; import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.Host; import com.cloud.host.dao.HostDao; import com.cloud.storage.CreateSnapshotPayload; import com.cloud.storage.DataStoreRole; @@ -149,6 +150,12 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri return null; } + @Override + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { return false; } + + @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {} + @Override public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { return volume.getSize(); diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java index 4cfc0975613..1f9a128727e 100644 --- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java @@ -42,6 +42,7 @@ import org.apache.cloudstack.storage.datastore.DataObjectManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; +import com.cloud.host.Host; import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; import com.cloud.storage.dao.StoragePoolHostDao; @@ -80,6 +81,12 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver return null; } + @Override + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { return false; } + + @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {} + @Override public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { return volume.getSize(); diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java index 7959af9dd25..1212b600814 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java @@ -17,8 +17,10 @@ package org.apache.cloudstack.storage.datastore.driver; import java.text.NumberFormat; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.UUID; import javax.inject.Inject; @@ -44,7 +46,12 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; @@ -55,22 +62,18 @@ import com.cloud.user.AccountDetailVO; import com.cloud.user.AccountDetailsDao; import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; +import com.cloud.utils.exception.CloudRuntimeException; public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { - @Inject - private PrimaryDataStoreDao _storagePoolDao; - @Inject - private StoragePoolDetailsDao _storagePoolDetailsDao; - @Inject - private VolumeDao _volumeDao; - @Inject - private VolumeDetailsDao _volumeDetailsDao; - @Inject - private DataCenterDao _zoneDao; - @Inject - private AccountDao _accountDao; - @Inject - private AccountDetailsDao _accountDetailsDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; + @Inject private VolumeDao _volumeDao; + @Inject private VolumeDetailsDao _volumeDetailsDao; + @Inject private DataCenterDao _zoneDao; + @Inject private AccountDao _accountDao; + @Inject private AccountDetailsDao _accountDetailsDao; + @Inject private ClusterDetailsDao _clusterDetailsDao; + @Inject private HostDao _hostDao; @Override public Map getCapabilities() { @@ -149,25 +152,35 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { } private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) { - AccountDetailVO accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.ACCOUNT_ID, String.valueOf(sfAccount.getId())); + AccountDetailVO accountDetail = new AccountDetailVO(csAccountId, + SolidFireUtil.ACCOUNT_ID, + String.valueOf(sfAccount.getId())); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); - accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_INITIATOR_USERNAME, String.valueOf(sfAccount.getName())); + accountDetail = new AccountDetailVO(csAccountId, + SolidFireUtil.CHAP_INITIATOR_USERNAME, + String.valueOf(sfAccount.getName())); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); - accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_INITIATOR_SECRET, String.valueOf(sfAccount.getInitiatorSecret())); + accountDetail = new AccountDetailVO(csAccountId, + SolidFireUtil.CHAP_INITIATOR_SECRET, + String.valueOf(sfAccount.getInitiatorSecret())); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); - accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_TARGET_USERNAME, sfAccount.getName()); + accountDetail = new AccountDetailVO(csAccountId, + SolidFireUtil.CHAP_TARGET_USERNAME, + sfAccount.getName()); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); - accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_TARGET_SECRET, sfAccount.getTargetSecret()); + accountDetail = new AccountDetailVO(csAccountId, + SolidFireUtil.CHAP_TARGET_SECRET, + sfAccount.getTargetSecret()); - _accountDetailsDao.persist(accountDetails); + _accountDetailsDao.persist(accountDetail); } private class ChapInfoImpl implements ChapInfo { @@ -227,6 +240,179 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { return new ChapInfoImpl(chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret); } + // get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) + // if the VAG exists + // update the VAG to contain all IQNs of the hosts (ModifyVolumeAccessGroup) + // if the ID of volumeInfo in not in the VAG, add it (ModifyVolumeAccessGroup) + // if the VAG doesn't exist, create it with the IQNs of the hosts and the ID of volumeInfo (CreateVolumeAccessGroup) + @Override + public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) + { + if (volumeInfo == null || host == null || dataStore == null) { + return false; + } + + long sfVolumeId = Long.parseLong(volumeInfo.getFolder()); + long clusterId = host.getClusterId(); + long storagePoolId = dataStore.getId(); + + ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId)); + + String vagId = clusterDetail != null ? clusterDetail.getValue() : null; + + List hosts = _hostDao.findByClusterId(clusterId); + + if (!hostsSupport_iScsi(hosts)) { + return false; + } + + SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); + + if (vagId != null) { + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId)); + + long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); + + SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(), + getIqnsFromHosts(hosts), volumeIds); + } + else { + long lVagId = SolidFireUtil.createSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), "CloudStack-" + UUID.randomUUID().toString(), + getIqnsFromHosts(hosts), new long[] { sfVolumeId }); + + clusterDetail = new ClusterDetailsVO(clusterId, getVagKey(storagePoolId), String.valueOf(lVagId)); + + _clusterDetailsDao.persist(clusterDetail); + } + + return true; + } + + // get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) // might not exist if using CHAP + // if the VAG exists + // remove the ID of volumeInfo from the VAG (ModifyVolumeAccessGroup) + @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) + { + if (volumeInfo == null || host == null || dataStore == null) { + return; + } + + long sfVolumeId = Long.parseLong(volumeInfo.getFolder()); + long clusterId = host.getClusterId(); + long storagePoolId = dataStore.getId(); + + ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId)); + + String vagId = clusterDetail != null ? clusterDetail.getValue() : null; + + if (vagId != null) { + List hosts = _hostDao.findByClusterId(clusterId); + + SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); + + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId)); + + long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); + + SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), + sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(), + getIqnsFromHosts(hosts), volumeIds); + } + } + + private boolean hostsSupport_iScsi(List hosts) { + if (hosts == null || hosts.size() == 0) { + return false; + } + + for (Host host : hosts) { + if (host == null || host.getStorageUrl() == null || host.getStorageUrl().trim().length() == 0 || !host.getStorageUrl().startsWith("iqn")) { + return false; + } + } + + return true; + } + + private long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) { + if (add) { + return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove); + } + + return getNewVolumeIdsRemove(volumeIds, volumeIdToAddOrRemove); + } + + private long[] getNewVolumeIdsAdd(long[] volumeIds, long volumeIdToAdd) { + List lstVolumeIds = new ArrayList(); + + if (volumeIds != null) { + for (long volumeId : volumeIds) { + lstVolumeIds.add(volumeId); + } + } + + if (lstVolumeIds.contains(volumeIdToAdd)) { + return volumeIds; + } + + lstVolumeIds.add(volumeIdToAdd); + + return convertArray(lstVolumeIds); + } + + private long[] getNewVolumeIdsRemove(long[] volumeIds, long volumeIdToRemove) { + List lstVolumeIds = new ArrayList(); + + if (volumeIds != null) { + for (long volumeId : volumeIds) { + lstVolumeIds.add(volumeId); + } + } + + lstVolumeIds.remove(volumeIdToRemove); + + return convertArray(lstVolumeIds); + } + + private long[] convertArray(List items) { + if (items == null) { + return new long[0]; + } + + long[] outArray = new long[items.size()]; + + for (int i = 0; i < items.size(); i++) { + Long value = items.get(i); + + outArray[i] = value; + } + + return outArray; + } + + private String getVagKey(long storagePoolId) { + return "sfVolumeAccessGroup_" + storagePoolId; + } + + private String[] getIqnsFromHosts(List hosts) { + if (hosts == null || hosts.size() == 0) { + throw new CloudRuntimeException("There do not appear to be any hosts in this cluster."); + } + + List lstIqns = new ArrayList(); + + for (Host host : hosts) { + lstIqns.add(host.getStorageUrl()); + } + + return lstIqns.toArray(new String[0]); + } + private long getDefaultMinIops(long storagePoolId) { StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS); @@ -449,6 +635,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { callback.complete(result); } + /* private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) { String mVip = sfConnection.getManagementVip(); int mPort = sfConnection.getManagementPort(); @@ -488,6 +675,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { return false; } + */ @Override public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback callback) { diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java index 3c96c097b1d..8d023d66225 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -95,32 +95,8 @@ public class SolidFireUtil { return volumeCreateResult.result.volumeID; } - public static SolidFireVolume deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) + public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) { - SolidFireVolume sfVolume = getSolidFireVolume(strSfMvip, iSfPort, strSfAdmin, strSfPassword, lVolumeId); - - final Gson gson = new GsonBuilder().create(); - - VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId); - - String strVolumeToDeleteJson = gson.toJson(volumeToDelete); - - executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); - - return sfVolume; - } - - public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) { - final Gson gson = new GsonBuilder().create(); - - VolumeToPurge volumeToPurge = new VolumeToPurge(lVolumeId); - - String strVolumeToPurgeJson = gson.toJson(volumeToPurge); - - executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); - } - - public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) { final Gson gson = new GsonBuilder().create(); VolumeToGet volumeToGet = new VolumeToGet(lVolumeId); @@ -164,6 +140,56 @@ public class SolidFireUtil { return sfVolumes; } + public static List getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword) + { + final Gson gson = new GsonBuilder().create(); + + ListDeletedVolumes listDeletedVolumes = new ListDeletedVolumes(); + + String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes); + + String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort, + strSfAdmin, strSfPassword); + + VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class); + + verifyResult(volumeGetResult.result, strListDeletedVolumesResultJson, gson); + + List deletedVolumes = new ArrayList (); + + for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) { + deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.totalSize)); + } + + return deletedVolumes; + } + + public static SolidFireVolume deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) + { + SolidFireVolume sfVolume = getSolidFireVolume(strSfMvip, iSfPort, strSfAdmin, strSfPassword, lVolumeId); + + final Gson gson = new GsonBuilder().create(); + + VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId); + + String strVolumeToDeleteJson = gson.toJson(volumeToDelete); + + executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + return sfVolume; + } + + public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) + { + final Gson gson = new GsonBuilder().create(); + + VolumeToPurge volumeToPurge = new VolumeToPurge(lVolumeId); + + String strVolumeToPurgeJson = gson.toJson(volumeToPurge); + + executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + } + private static final String ACTIVE = "active"; public static class SolidFireVolume { @@ -257,17 +283,9 @@ public class SolidFireUtil { return accountAddResult.result.accountID; } - public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId) { - final Gson gson = new GsonBuilder().create(); - - AccountToRemove accountToRemove = new AccountToRemove(lAccountId); - - String strAccountToRemoveJson = gson.toJson(accountToRemove); - - executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); - } - - public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lSfAccountId) { + public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, + long lSfAccountId) + { final Gson gson = new GsonBuilder().create(); AccountToGetById accountToGetById = new AccountToGetById(lSfAccountId); @@ -307,7 +325,20 @@ public class SolidFireUtil { return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret); } - public static class SolidFireAccount { + public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, + long lAccountId) + { + final Gson gson = new GsonBuilder().create(); + + AccountToRemove accountToRemove = new AccountToRemove(lAccountId); + + String strAccountToRemoveJson = gson.toJson(accountToRemove); + + executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + } + + public static class SolidFireAccount + { private final long _id; private final String _name; private final String _initiatorSecret; @@ -358,7 +389,9 @@ public class SolidFireUtil { SolidFireAccount sfa = (SolidFireAccount)obj; - if (_id == sfa._id && _name.equals(sfa._name) && _initiatorSecret.equals(sfa._initiatorSecret) && _targetSecret.equals(sfa._targetSecret)) { + if (_id == sfa._id && _name.equals(sfa._name) && + _initiatorSecret.equals(sfa._initiatorSecret) && + _targetSecret.equals(sfa._targetSecret)) { return true; } @@ -366,32 +399,12 @@ public class SolidFireUtil { } } - public static List getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword) { + public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName, + String[] iqns, long[] volumeIds) + { final Gson gson = new GsonBuilder().create(); - ListDeletedVolumes listDeletedVolumes = new ListDeletedVolumes(); - - String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes); - - String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); - - VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class); - - verifyResult(volumeGetResult.result, strListDeletedVolumesResultJson, gson); - - List deletedVolumes = new ArrayList(); - - for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) { - deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.totalSize)); - } - - return deletedVolumes; - } - - public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName) { - final Gson gson = new GsonBuilder().create(); - - VagToCreate vagToCreate = new VagToCreate(strVagName); + VagToCreate vagToCreate = new VagToCreate(strVagName, iqns, volumeIds); String strVagCreateJson = gson.toJson(vagToCreate); @@ -404,6 +417,38 @@ public class SolidFireUtil { return vagCreateResult.result.volumeAccessGroupID; } + public static void modifySolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId, + String[] iqns, long[] volumeIds) + { + final Gson gson = new GsonBuilder().create(); + + VagToModify vagToModify = new VagToModify(lVagId, iqns, volumeIds); + + String strVagModifyJson = gson.toJson(vagToModify); + + executeJsonRpc(strVagModifyJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + } + + public static SolidFireVag getSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId) + { + final Gson gson = new GsonBuilder().create(); + + VagToGet vagToGet = new VagToGet(lVagId); + + String strVagToGetJson = gson.toJson(vagToGet); + + String strVagGetResultJson = executeJsonRpc(strVagToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); + + VagGetResult vagGetResult = gson.fromJson(strVagGetResultJson, VagGetResult.class); + + verifyResult(vagGetResult.result, strVagGetResultJson, gson); + + String[] vagIqns = getVagIqns(vagGetResult, lVagId); + long[] vagVolumeIds = getVagVolumeIds(vagGetResult, lVagId); + + return new SolidFireVag(lVagId, vagIqns, vagVolumeIds); + } + public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId) { final Gson gson = new GsonBuilder().create(); @@ -414,6 +459,64 @@ public class SolidFireUtil { executeJsonRpc(strVagToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword); } + public static class SolidFireVag + { + private final long _id; + private final String[] _initiators; + private final long[] _volumeIds; + + public SolidFireVag(long id, String[] initiators, long[] volumeIds) + { + _id = id; + _initiators = initiators; + _volumeIds = volumeIds; + } + + public long getId() + { + return _id; + } + + public String[] getInitiators() + { + return _initiators; + } + + public long[] getVolumeIds() + { + return _volumeIds; + } + + @Override + public int hashCode() { + return String.valueOf(_id).hashCode(); + } + + @Override + public String toString() { + return String.valueOf(_id); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (!obj.getClass().equals(SolidFireVag.class)) { + return false; + } + + SolidFireVag sfvag = (SolidFireVag)obj; + + if (_id == sfvag._id) { + return true; + } + + return false; + } + } + @SuppressWarnings("unused") private static final class VolumeToCreate { private final String method = "CreateVolume"; @@ -466,7 +569,59 @@ public class SolidFireUtil { } @SuppressWarnings("unused") - private static final class VolumeToDelete { + private static final class VolumeToGet + { + private final String method = "ListActiveVolumes"; + private final VolumeToGetParams params; + + private VolumeToGet(final long lVolumeId) + { + params = new VolumeToGetParams(lVolumeId); + } + + private static final class VolumeToGetParams + { + private final long startVolumeID; + private final long limit = 1; + + private VolumeToGetParams(final long lVolumeId) + { + startVolumeID = lVolumeId; + } + } + } + + @SuppressWarnings("unused") + private static final class VolumesToGetForAccount + { + private final String method = "ListVolumesForAccount"; + private final VolumesToGetForAccountParams params; + + private VolumesToGetForAccount(final long lAccountId) + { + params = new VolumesToGetForAccountParams(lAccountId); + } + + private static final class VolumesToGetForAccountParams + { + private final long accountID; + + private VolumesToGetForAccountParams(final long lAccountId) + { + accountID = lAccountId; + } + } + } + + @SuppressWarnings("unused") + private static final class ListDeletedVolumes + { + private final String method = "ListDeletedVolumes"; + } + + @SuppressWarnings("unused") + private static final class VolumeToDelete + { private final String method = "DeleteVolume"; private final VolumeToDeleteParams params; @@ -484,12 +639,8 @@ public class SolidFireUtil { } @SuppressWarnings("unused") - private static final class ListDeletedVolumes { - private final String method = "ListDeletedVolumes"; - } - - @SuppressWarnings("unused") - private static final class VolumeToPurge { + private static final class VolumeToPurge + { private final String method = "PurgeDeletedVolume"; private final VolumeToPurgeParams params; @@ -507,56 +658,67 @@ public class SolidFireUtil { } @SuppressWarnings("unused") - private static final class VolumeToGet { - private final String method = "ListActiveVolumes"; - private final VolumeToGetParams params; + private static final class AccountToAdd + { + private final String method = "AddAccount"; + private final AccountToAddParams params; - private VolumeToGet(final long lVolumeId) { - params = new VolumeToGetParams(lVolumeId); + private AccountToAdd(final String strAccountName) + { + params = new AccountToAddParams(strAccountName); } - private static final class VolumeToGetParams { - private final long startVolumeID; - private final long limit = 1; + private static final class AccountToAddParams + { + private final String username; - private VolumeToGetParams(final long lVolumeId) { - startVolumeID = lVolumeId; + private AccountToAddParams(final String strAccountName) + { + username = strAccountName; } } } @SuppressWarnings("unused") - private static final class VolumesToGetForAccount { - private final String method = "ListVolumesForAccount"; - private final VolumesToGetForAccountParams params; + private static final class AccountToGetById + { + private final String method = "GetAccountByID"; + private final AccountToGetByIdParams params; - private VolumesToGetForAccount(final long lAccountId) { - params = new VolumesToGetForAccountParams(lAccountId); + private AccountToGetById(final long lAccountId) + { + params = new AccountToGetByIdParams(lAccountId); } - private static final class VolumesToGetForAccountParams { + private static final class AccountToGetByIdParams + { private final long accountID; - private VolumesToGetForAccountParams(final long lAccountId) { + private AccountToGetByIdParams(final long lAccountId) + { accountID = lAccountId; } } } @SuppressWarnings("unused") - private static final class AccountToAdd { - private final String method = "AddAccount"; - private final AccountToAddParams params; + private static final class AccountToGetByName + { + private final String method = "GetAccountByName"; + private final AccountToGetByNameParams params; - private AccountToAdd(final String strAccountName) { - params = new AccountToAddParams(strAccountName); + private AccountToGetByName(final String strUsername) + { + params = new AccountToGetByNameParams(strUsername); } - private static final class AccountToAddParams { + private static final class AccountToGetByNameParams + { private final String username; - private AccountToAddParams(final String strAccountName) { - username = strAccountName; + private AccountToGetByNameParams(final String strUsername) + { + username = strUsername; } } } @@ -580,55 +742,76 @@ public class SolidFireUtil { } @SuppressWarnings("unused") - private static final class AccountToGetById { - private final String method = "GetAccountByID"; - private final AccountToGetByIdParams params; - - private AccountToGetById(final long lAccountId) { - params = new AccountToGetByIdParams(lAccountId); - } - - private static final class AccountToGetByIdParams { - private final long accountID; - - private AccountToGetByIdParams(final long lAccountId) { - accountID = lAccountId; - } - } - } - - @SuppressWarnings("unused") - private static final class AccountToGetByName { - private final String method = "GetAccountByName"; - private final AccountToGetByNameParams params; - - private AccountToGetByName(final String strUsername) { - params = new AccountToGetByNameParams(strUsername); - } - - private static final class AccountToGetByNameParams { - private final String username; - - private AccountToGetByNameParams(final String strUsername) { - username = strUsername; - } - } - } - - @SuppressWarnings("unused") - private static final class VagToCreate { + private static final class VagToCreate + { private final String method = "CreateVolumeAccessGroup"; private final VagToCreateParams params; - private VagToCreate(final String strVagName) { - params = new VagToCreateParams(strVagName); + private VagToCreate(final String strVagName, final String[] iqns, final long[] volumeIds) + { + params = new VagToCreateParams(strVagName, iqns, volumeIds); } - private static final class VagToCreateParams { + private static final class VagToCreateParams + { private final String name; + private final String[] initiators; + private final long[] volumes; - private VagToCreateParams(final String strVagName) { + private VagToCreateParams(final String strVagName, final String[] iqns, final long[] volumeIds) + { name = strVagName; + initiators = iqns; + volumes = volumeIds; + } + } + } + + @SuppressWarnings("unused") + private static final class VagToModify + { + private final String method = "ModifyVolumeAccessGroup"; + private final VagToModifyParams params; + + private VagToModify(final long lVagName, final String[] iqns, final long[] volumeIds) + { + params = new VagToModifyParams(lVagName, iqns, volumeIds); + } + + private static final class VagToModifyParams + { + private final long volumeAccessGroupID; + private final String[] initiators; + private final long[] volumes; + + private VagToModifyParams(final long lVagName, final String[] iqns, final long[] volumeIds) + { + volumeAccessGroupID = lVagName; + initiators = iqns; + volumes = volumeIds; + } + } + } + + @SuppressWarnings("unused") + private static final class VagToGet + { + private final String method = "ListVolumeAccessGroups"; + private final VagToGetParams params; + + private VagToGet(final long lVagId) + { + params = new VagToGetParams(lVagId); + } + + private static final class VagToGetParams + { + private final long startVolumeAccessGroupID; + private final long limit = 1; + + private VagToGetParams(final long lVagId) + { + startVolumeAccessGroupID = lVagId; } } } @@ -707,7 +890,25 @@ public class SolidFireUtil { } } - private static final class JsonError { + private static final class VagGetResult + { + private Result result; + + private static final class Result + { + private Vag[] volumeAccessGroups; + + private static final class Vag + { + private long volumeAccessGroupID; + private String[] initiators; + private long[] volumes; + } + } + } + + private static final class JsonError + { private Error error; private static final class Error { @@ -762,7 +963,7 @@ public class SolidFireUtil { httpClient = getHttpClient(iPort); - URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/1.0"); + URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/5.0"); AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME); UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(strAdmin, strPassword); @@ -865,4 +1066,26 @@ public class SolidFireUtil { throw new CloudRuntimeException("Could not determine the total size of the volume for volume ID of " + lVolumeId + "."); } + + private static String[] getVagIqns(VagGetResult vagGetResult, long lVagId) + { + if (vagGetResult.result.volumeAccessGroups != null && vagGetResult.result.volumeAccessGroups.length == 1 && + vagGetResult.result.volumeAccessGroups[0].volumeAccessGroupID == lVagId) + { + return vagGetResult.result.volumeAccessGroups[0].initiators; + } + + throw new CloudRuntimeException("Could not determine the IQNs of the volume access group for volume access group ID of " + lVagId + "."); + } + + private static long[] getVagVolumeIds(VagGetResult vagGetResult, long lVagId) + { + if (vagGetResult.result.volumeAccessGroups != null && vagGetResult.result.volumeAccessGroups.length == 1 && + vagGetResult.result.volumeAccessGroups[0].volumeAccessGroupID == lVagId) + { + return vagGetResult.result.volumeAccessGroups[0].volumes; + } + + throw new CloudRuntimeException("Could not determine the volume IDs of the volume access group for volume access group ID of " + lVagId + "."); + } } diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 5f15cac7322..ac0c438aab9 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -1434,8 +1434,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic Volume volume = _volumeDao.findById(volumeId); VMInstanceVO vm = _vmInstanceDao.findById(vmId); - String errorMsg = "Failed to detach volume: " + volume.getName() + " from VM: " + vm.getHostName(); - boolean sendCommand = (vm.getState() == State.Running); + String errorMsg = "Failed to detach volume " + volume.getName() + " from VM " + vm.getHostName(); + boolean sendCommand = vm.getState() == State.Running; Long hostId = vm.getHostId(); @@ -1449,10 +1449,11 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } } + HostVO host = null; StoragePoolVO volumePool = _storagePoolDao.findById(volume.getPoolId()); if (hostId != null) { - HostVO host = _hostDao.findById(hostId); + host = _hostDao.findById(hostId); if (host != null && host.getHypervisorType() == HypervisorType.XenServer && volumePool.isManaged()) { sendCommand = true; @@ -1481,10 +1482,14 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } } + DataStore dataStore = dataStoreMgr.getDataStore(volume.getPoolId(), DataStoreRole.Primary); + if (!sendCommand || (answer != null && answer.getResult())) { // Mark the volume as detached _volsDao.detachVolume(volume.getId()); + volService.disconnectVolumeFromHost(volFactory.getVolume(volume.getId()), host, dataStore); + return _volsDao.findById(volumeId); } else { @@ -1924,13 +1929,14 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, Long deviceId) { - String errorMsg = "Failed to attach volume: " + volumeToAttach.getName() + " to VM: " + vm.getHostName(); - boolean sendCommand = (vm.getState() == State.Running); + String errorMsg = "Failed to attach volume " + volumeToAttach.getName() + " to VM " + vm.getHostName(); + boolean sendCommand = vm.getState() == State.Running; AttachAnswer answer = null; Long hostId = vm.getHostId(); if (hostId == null) { hostId = vm.getLastHostId(); + HostVO host = _hostDao.findById(hostId); if (host != null && host.getHypervisorType() == HypervisorType.VMware) { @@ -1949,6 +1955,22 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } } + DataStore dataStore = dataStoreMgr.getDataStore(volumeToAttachStoragePool.getId(), DataStoreRole.Primary); + + boolean queryForChap = true; + + if (host != null) { + try { + // if connectVolumeToHost returns true, then we do not want to use CHAP because the volume is already connected to the host(s) + queryForChap = !volService.connectVolumeToHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore); + } + catch (Exception e) { + volService.disconnectVolumeFromHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore); + + throw new CloudRuntimeException(e.getMessage()); + } + } + if (sendCommand) { if (host.getHypervisorType() == HypervisorType.KVM && volumeToAttachStoragePool.isManaged() && @@ -1963,9 +1985,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic AttachCommand cmd = new AttachCommand(disk, vm.getInstanceName()); - VolumeInfo volumeInfo = volFactory.getVolume(volumeToAttach.getId()); - DataStore dataStore = dataStoreMgr.getDataStore(volumeToAttachStoragePool.getId(), DataStoreRole.Primary); - ChapInfo chapInfo = volService.getChapInfo(volumeInfo, dataStore); + ChapInfo chapInfo = queryForChap ? volService.getChapInfo(volFactory.getVolume(volumeToAttach.getId()), dataStore) : null; Map details = new HashMap(); @@ -1987,6 +2007,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic try { answer = (AttachAnswer)_agentMgr.send(hostId, cmd); } catch (Exception e) { + volService.disconnectVolumeFromHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore); + throw new CloudRuntimeException(errorMsg + " due to: " + e.getMessage()); } } @@ -2023,6 +2045,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic errorMsg += "; " + details; } } + + volService.disconnectVolumeFromHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore); + throw new CloudRuntimeException(errorMsg); } } diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java index 1b2a102d63c..b306b0c6632 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java @@ -698,7 +698,9 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost { ManagedObjectReference morDs = oc.getObj(); String name = (String)VmwareHelper.getPropValue(oc, "name"); - dsList.add(new Pair(morDs, name)); + if (!name.startsWith("-iqn.")) { + dsList.add(new Pair(morDs, name)); + } } } }