mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Merge from 4.3: CLOUDSTACK-5662: XenServer can't discover iSCSI targets with different credentials
This commit is contained in:
parent
bc1eec9f70
commit
ae35782ccd
@ -78,6 +78,11 @@ public interface Host extends StateObject<Status>, Identity, InternalIdentity {
|
|||||||
*/
|
*/
|
||||||
String getPrivateIpAddress();
|
String getPrivateIpAddress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the ip address of the host.
|
||||||
|
*/
|
||||||
|
String getStorageUrl();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the ip address of the host attached to the storage network.
|
* @return the ip address of the host attached to the storage network.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -81,7 +81,10 @@ public class CheckOnHostCommandTest {
|
|||||||
return "10.1.1.1";
|
return "10.1.1.1";
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
public String getStorageUrl() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public String getStorageIpAddress() {
|
public String getStorageIpAddress() {
|
||||||
return "10.1.1.2";
|
return "10.1.1.2";
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,12 +21,17 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
|
|||||||
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||||
import org.apache.cloudstack.storage.command.CommandResult;
|
import org.apache.cloudstack.storage.command.CommandResult;
|
||||||
|
|
||||||
|
import com.cloud.host.Host;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
|
|
||||||
public interface PrimaryDataStoreDriver extends DataStoreDriver {
|
public interface PrimaryDataStoreDriver extends DataStoreDriver {
|
||||||
public ChapInfo getChapInfo(VolumeInfo volumeInfo);
|
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 long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool);
|
||||||
|
|
||||||
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback);
|
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||||
|
|||||||
@ -44,6 +44,10 @@ public interface VolumeService {
|
|||||||
|
|
||||||
ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore);
|
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
|
* Creates the volume based on the given criteria
|
||||||
*
|
*
|
||||||
|
|||||||
@ -36,6 +36,7 @@ import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
|||||||
|
|
||||||
import com.cloud.agent.api.to.DataStoreTO;
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.agent.api.to.DataTO;
|
import com.cloud.agent.api.to.DataTO;
|
||||||
|
import com.cloud.host.Host;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
|
|
||||||
@ -43,10 +44,21 @@ public class FakePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
boolean snapshotResult = true;
|
boolean snapshotResult = true;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
|
public Map<String, String> getCapabilities() {
|
||||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
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
|
@Override
|
||||||
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
|
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
|
||||||
return volume.getSize();
|
return volume.getSize();
|
||||||
|
|||||||
@ -158,6 +158,24 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
return null;
|
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
|
@Override
|
||||||
public AsyncCallFuture<VolumeApiResult> createVolumeAsync(VolumeInfo volume, DataStore dataStore) {
|
public AsyncCallFuture<VolumeApiResult> createVolumeAsync(VolumeInfo volume, DataStore dataStore) {
|
||||||
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
|
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
|
||||||
|
|||||||
@ -4800,22 +4800,26 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
target.setPort(storagePortNumber);
|
target.setPort(storagePortNumber);
|
||||||
target.setIScsiName(iqn);
|
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.setChapAuthEnabled(true);
|
||||||
auth.setChapInherited(false);
|
auth.setChapInherited(false);
|
||||||
auth.setChapAuthenticationType(strAuthType);
|
auth.setChapAuthenticationType(strAuthType);
|
||||||
auth.setChapName(chapName);
|
auth.setChapName(chapName);
|
||||||
auth.setChapSecret(chapSecret);
|
auth.setChapSecret(chapSecret);
|
||||||
|
|
||||||
auth.setMutualChapInherited(false);
|
if (StringUtils.isNotBlank(mutualChapName) && StringUtils.isNotBlank(mutualChapSecret)) {
|
||||||
auth.setMutualChapAuthenticationType(strAuthType);
|
auth.setMutualChapInherited(false);
|
||||||
auth.setMutualChapName(mutualChapName);
|
auth.setMutualChapAuthenticationType(strAuthType);
|
||||||
auth.setMutualChapSecret(mutualChapSecret);
|
auth.setMutualChapName(mutualChapName);
|
||||||
|
auth.setMutualChapSecret(mutualChapSecret);
|
||||||
|
}
|
||||||
|
|
||||||
target.setAuthenticationProperties(auth);
|
target.setAuthenticationProperties(auth);
|
||||||
|
}
|
||||||
|
|
||||||
final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
|
final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
|
||||||
|
|
||||||
@ -6052,11 +6056,34 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
cmd.setName(_url);
|
cmd.setName(_url);
|
||||||
cmd.setGuid(_guid);
|
cmd.setGuid(_guid);
|
||||||
cmd.setDataCenter(_dcId);
|
cmd.setDataCenter(_dcId);
|
||||||
|
cmd.setIqn(getIqn());
|
||||||
cmd.setPod(_pod);
|
cmd.setPod(_pod);
|
||||||
cmd.setCluster(_cluster);
|
cmd.setCluster(_cluster);
|
||||||
cmd.setVersion(VmwareResource.class.getPackage().getImplementationVersion());
|
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 {
|
private void fillHostHardwareInfo(VmwareContext serviceContext, StartupRoutingCommand cmd) throws RuntimeFaultFaultMsg, RemoteException, Exception {
|
||||||
|
|
||||||
VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
|
VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
|
||||||
|
|||||||
@ -61,6 +61,7 @@ import com.cloud.agent.api.to.DataTO;
|
|||||||
import com.cloud.agent.api.to.StorageFilerTO;
|
import com.cloud.agent.api.to.StorageFilerTO;
|
||||||
import com.cloud.configuration.Config;
|
import com.cloud.configuration.Config;
|
||||||
import com.cloud.exception.StorageUnavailableException;
|
import com.cloud.exception.StorageUnavailableException;
|
||||||
|
import com.cloud.host.Host;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.storage.CreateSnapshotPayload;
|
import com.cloud.storage.CreateSnapshotPayload;
|
||||||
import com.cloud.storage.DataStoreRole;
|
import com.cloud.storage.DataStoreRole;
|
||||||
@ -149,6 +150,12 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
|
|||||||
return null;
|
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
|
@Override
|
||||||
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
|
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
|
||||||
return volume.getSize();
|
return volume.getSize();
|
||||||
|
|||||||
@ -42,6 +42,7 @@ import org.apache.cloudstack.storage.datastore.DataObjectManager;
|
|||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
import com.cloud.agent.api.to.DataStoreTO;
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.agent.api.to.DataTO;
|
import com.cloud.agent.api.to.DataTO;
|
||||||
|
import com.cloud.host.Host;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
@ -80,6 +81,12 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
|
|||||||
return null;
|
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
|
@Override
|
||||||
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
|
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
|
||||||
return volume.getSize();
|
return volume.getSize();
|
||||||
|
|||||||
@ -17,8 +17,10 @@
|
|||||||
package org.apache.cloudstack.storage.datastore.driver;
|
package org.apache.cloudstack.storage.datastore.driver;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
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.DataObjectType;
|
||||||
import com.cloud.agent.api.to.DataStoreTO;
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.agent.api.to.DataTO;
|
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.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.Storage.StoragePoolType;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
@ -55,22 +62,18 @@ import com.cloud.user.AccountDetailVO;
|
|||||||
import com.cloud.user.AccountDetailsDao;
|
import com.cloud.user.AccountDetailsDao;
|
||||||
import com.cloud.user.AccountVO;
|
import com.cloud.user.AccountVO;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||||
@Inject
|
@Inject private PrimaryDataStoreDao _storagePoolDao;
|
||||||
private PrimaryDataStoreDao _storagePoolDao;
|
@Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
|
||||||
@Inject
|
@Inject private VolumeDao _volumeDao;
|
||||||
private StoragePoolDetailsDao _storagePoolDetailsDao;
|
@Inject private VolumeDetailsDao _volumeDetailsDao;
|
||||||
@Inject
|
@Inject private DataCenterDao _zoneDao;
|
||||||
private VolumeDao _volumeDao;
|
@Inject private AccountDao _accountDao;
|
||||||
@Inject
|
@Inject private AccountDetailsDao _accountDetailsDao;
|
||||||
private VolumeDetailsDao _volumeDetailsDao;
|
@Inject private ClusterDetailsDao _clusterDetailsDao;
|
||||||
@Inject
|
@Inject private HostDao _hostDao;
|
||||||
private DataCenterDao _zoneDao;
|
|
||||||
@Inject
|
|
||||||
private AccountDao _accountDao;
|
|
||||||
@Inject
|
|
||||||
private AccountDetailsDao _accountDetailsDao;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> getCapabilities() {
|
public Map<String, String> getCapabilities() {
|
||||||
@ -149,25 +152,35 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) {
|
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 {
|
private class ChapInfoImpl implements ChapInfo {
|
||||||
@ -227,6 +240,179 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
return new ChapInfoImpl(chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret);
|
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<HostVO> 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<HostVO> 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<HostVO> 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<Long> lstVolumeIds = new ArrayList<Long>();
|
||||||
|
|
||||||
|
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<Long> lstVolumeIds = new ArrayList<Long>();
|
||||||
|
|
||||||
|
if (volumeIds != null) {
|
||||||
|
for (long volumeId : volumeIds) {
|
||||||
|
lstVolumeIds.add(volumeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lstVolumeIds.remove(volumeIdToRemove);
|
||||||
|
|
||||||
|
return convertArray(lstVolumeIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long[] convertArray(List<Long> 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<? extends Host> hosts) {
|
||||||
|
if (hosts == null || hosts.size() == 0) {
|
||||||
|
throw new CloudRuntimeException("There do not appear to be any hosts in this cluster.");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> lstIqns = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (Host host : hosts) {
|
||||||
|
lstIqns.add(host.getStorageUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstIqns.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
private long getDefaultMinIops(long storagePoolId) {
|
private long getDefaultMinIops(long storagePoolId) {
|
||||||
StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS);
|
StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS);
|
||||||
|
|
||||||
@ -449,6 +635,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
callback.complete(result);
|
callback.complete(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) {
|
private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) {
|
||||||
String mVip = sfConnection.getManagementVip();
|
String mVip = sfConnection.getManagementVip();
|
||||||
int mPort = sfConnection.getManagementPort();
|
int mPort = sfConnection.getManagementPort();
|
||||||
@ -488,6 +675,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
|
public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
|
||||||
|
|||||||
@ -95,32 +95,8 @@ public class SolidFireUtil {
|
|||||||
return volumeCreateResult.result.volumeID;
|
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();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
VolumeToGet volumeToGet = new VolumeToGet(lVolumeId);
|
VolumeToGet volumeToGet = new VolumeToGet(lVolumeId);
|
||||||
@ -164,6 +140,56 @@ public class SolidFireUtil {
|
|||||||
return sfVolumes;
|
return sfVolumes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<SolidFireVolume> 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<SolidFireVolume> deletedVolumes = new ArrayList<SolidFireVolume> ();
|
||||||
|
|
||||||
|
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";
|
private static final String ACTIVE = "active";
|
||||||
|
|
||||||
public static class SolidFireVolume {
|
public static class SolidFireVolume {
|
||||||
@ -257,17 +283,9 @@ public class SolidFireUtil {
|
|||||||
return accountAddResult.result.accountID;
|
return accountAddResult.result.accountID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId) {
|
public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
|
||||||
final Gson gson = new GsonBuilder().create();
|
long lSfAccountId)
|
||||||
|
{
|
||||||
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) {
|
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
AccountToGetById accountToGetById = new AccountToGetById(lSfAccountId);
|
AccountToGetById accountToGetById = new AccountToGetById(lSfAccountId);
|
||||||
@ -307,7 +325,20 @@ public class SolidFireUtil {
|
|||||||
return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
|
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 long _id;
|
||||||
private final String _name;
|
private final String _name;
|
||||||
private final String _initiatorSecret;
|
private final String _initiatorSecret;
|
||||||
@ -358,7 +389,9 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
SolidFireAccount sfa = (SolidFireAccount)obj;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,32 +399,12 @@ public class SolidFireUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SolidFireVolume> 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();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
ListDeletedVolumes listDeletedVolumes = new ListDeletedVolumes();
|
VagToCreate vagToCreate = new VagToCreate(strVagName, iqns, volumeIds);
|
||||||
|
|
||||||
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<SolidFireVolume> deletedVolumes = new ArrayList<SolidFireVolume>();
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
String strVagCreateJson = gson.toJson(vagToCreate);
|
String strVagCreateJson = gson.toJson(vagToCreate);
|
||||||
|
|
||||||
@ -404,6 +417,38 @@ public class SolidFireUtil {
|
|||||||
return vagCreateResult.result.volumeAccessGroupID;
|
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) {
|
public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId) {
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -414,6 +459,64 @@ public class SolidFireUtil {
|
|||||||
executeJsonRpc(strVagToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
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")
|
@SuppressWarnings("unused")
|
||||||
private static final class VolumeToCreate {
|
private static final class VolumeToCreate {
|
||||||
private final String method = "CreateVolume";
|
private final String method = "CreateVolume";
|
||||||
@ -466,7 +569,59 @@ public class SolidFireUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@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 String method = "DeleteVolume";
|
||||||
private final VolumeToDeleteParams params;
|
private final VolumeToDeleteParams params;
|
||||||
|
|
||||||
@ -484,12 +639,8 @@ public class SolidFireUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static final class ListDeletedVolumes {
|
private static final class VolumeToPurge
|
||||||
private final String method = "ListDeletedVolumes";
|
{
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final class VolumeToPurge {
|
|
||||||
private final String method = "PurgeDeletedVolume";
|
private final String method = "PurgeDeletedVolume";
|
||||||
private final VolumeToPurgeParams params;
|
private final VolumeToPurgeParams params;
|
||||||
|
|
||||||
@ -507,56 +658,67 @@ public class SolidFireUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static final class VolumeToGet {
|
private static final class AccountToAdd
|
||||||
private final String method = "ListActiveVolumes";
|
{
|
||||||
private final VolumeToGetParams params;
|
private final String method = "AddAccount";
|
||||||
|
private final AccountToAddParams params;
|
||||||
|
|
||||||
private VolumeToGet(final long lVolumeId) {
|
private AccountToAdd(final String strAccountName)
|
||||||
params = new VolumeToGetParams(lVolumeId);
|
{
|
||||||
|
params = new AccountToAddParams(strAccountName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class VolumeToGetParams {
|
private static final class AccountToAddParams
|
||||||
private final long startVolumeID;
|
{
|
||||||
private final long limit = 1;
|
private final String username;
|
||||||
|
|
||||||
private VolumeToGetParams(final long lVolumeId) {
|
private AccountToAddParams(final String strAccountName)
|
||||||
startVolumeID = lVolumeId;
|
{
|
||||||
|
username = strAccountName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static final class VolumesToGetForAccount {
|
private static final class AccountToGetById
|
||||||
private final String method = "ListVolumesForAccount";
|
{
|
||||||
private final VolumesToGetForAccountParams params;
|
private final String method = "GetAccountByID";
|
||||||
|
private final AccountToGetByIdParams params;
|
||||||
|
|
||||||
private VolumesToGetForAccount(final long lAccountId) {
|
private AccountToGetById(final long lAccountId)
|
||||||
params = new VolumesToGetForAccountParams(lAccountId);
|
{
|
||||||
|
params = new AccountToGetByIdParams(lAccountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class VolumesToGetForAccountParams {
|
private static final class AccountToGetByIdParams
|
||||||
|
{
|
||||||
private final long accountID;
|
private final long accountID;
|
||||||
|
|
||||||
private VolumesToGetForAccountParams(final long lAccountId) {
|
private AccountToGetByIdParams(final long lAccountId)
|
||||||
|
{
|
||||||
accountID = lAccountId;
|
accountID = lAccountId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static final class AccountToAdd {
|
private static final class AccountToGetByName
|
||||||
private final String method = "AddAccount";
|
{
|
||||||
private final AccountToAddParams params;
|
private final String method = "GetAccountByName";
|
||||||
|
private final AccountToGetByNameParams params;
|
||||||
|
|
||||||
private AccountToAdd(final String strAccountName) {
|
private AccountToGetByName(final String strUsername)
|
||||||
params = new AccountToAddParams(strAccountName);
|
{
|
||||||
|
params = new AccountToGetByNameParams(strUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class AccountToAddParams {
|
private static final class AccountToGetByNameParams
|
||||||
|
{
|
||||||
private final String username;
|
private final String username;
|
||||||
|
|
||||||
private AccountToAddParams(final String strAccountName) {
|
private AccountToGetByNameParams(final String strUsername)
|
||||||
username = strAccountName;
|
{
|
||||||
|
username = strUsername;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -580,55 +742,76 @@ public class SolidFireUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static final class AccountToGetById {
|
private static final class VagToCreate
|
||||||
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 final String method = "CreateVolumeAccessGroup";
|
private final String method = "CreateVolumeAccessGroup";
|
||||||
private final VagToCreateParams params;
|
private final VagToCreateParams params;
|
||||||
|
|
||||||
private VagToCreate(final String strVagName) {
|
private VagToCreate(final String strVagName, final String[] iqns, final long[] volumeIds)
|
||||||
params = new VagToCreateParams(strVagName);
|
{
|
||||||
|
params = new VagToCreateParams(strVagName, iqns, volumeIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class VagToCreateParams {
|
private static final class VagToCreateParams
|
||||||
|
{
|
||||||
private final String name;
|
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;
|
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 Error error;
|
||||||
|
|
||||||
private static final class Error {
|
private static final class Error {
|
||||||
@ -762,7 +963,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
httpClient = getHttpClient(iPort);
|
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);
|
AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME);
|
||||||
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(strAdmin, strPassword);
|
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 + ".");
|
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 + ".");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1434,8 +1434,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
Volume volume = _volumeDao.findById(volumeId);
|
Volume volume = _volumeDao.findById(volumeId);
|
||||||
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
|
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
|
||||||
|
|
||||||
String errorMsg = "Failed to detach volume: " + volume.getName() + " from VM: " + vm.getHostName();
|
String errorMsg = "Failed to detach volume " + volume.getName() + " from VM " + vm.getHostName();
|
||||||
boolean sendCommand = (vm.getState() == State.Running);
|
boolean sendCommand = vm.getState() == State.Running;
|
||||||
|
|
||||||
Long hostId = vm.getHostId();
|
Long hostId = vm.getHostId();
|
||||||
|
|
||||||
@ -1449,10 +1449,11 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HostVO host = null;
|
||||||
StoragePoolVO volumePool = _storagePoolDao.findById(volume.getPoolId());
|
StoragePoolVO volumePool = _storagePoolDao.findById(volume.getPoolId());
|
||||||
|
|
||||||
if (hostId != null) {
|
if (hostId != null) {
|
||||||
HostVO host = _hostDao.findById(hostId);
|
host = _hostDao.findById(hostId);
|
||||||
|
|
||||||
if (host != null && host.getHypervisorType() == HypervisorType.XenServer && volumePool.isManaged()) {
|
if (host != null && host.getHypervisorType() == HypervisorType.XenServer && volumePool.isManaged()) {
|
||||||
sendCommand = true;
|
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())) {
|
if (!sendCommand || (answer != null && answer.getResult())) {
|
||||||
// Mark the volume as detached
|
// Mark the volume as detached
|
||||||
_volsDao.detachVolume(volume.getId());
|
_volsDao.detachVolume(volume.getId());
|
||||||
|
|
||||||
|
volService.disconnectVolumeFromHost(volFactory.getVolume(volume.getId()), host, dataStore);
|
||||||
|
|
||||||
return _volsDao.findById(volumeId);
|
return _volsDao.findById(volumeId);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -1924,13 +1929,14 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, Long deviceId) {
|
private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, Long deviceId) {
|
||||||
String errorMsg = "Failed to attach volume: " + volumeToAttach.getName() + " to VM: " + vm.getHostName();
|
String errorMsg = "Failed to attach volume " + volumeToAttach.getName() + " to VM " + vm.getHostName();
|
||||||
boolean sendCommand = (vm.getState() == State.Running);
|
boolean sendCommand = vm.getState() == State.Running;
|
||||||
AttachAnswer answer = null;
|
AttachAnswer answer = null;
|
||||||
Long hostId = vm.getHostId();
|
Long hostId = vm.getHostId();
|
||||||
|
|
||||||
if (hostId == null) {
|
if (hostId == null) {
|
||||||
hostId = vm.getLastHostId();
|
hostId = vm.getLastHostId();
|
||||||
|
|
||||||
HostVO host = _hostDao.findById(hostId);
|
HostVO host = _hostDao.findById(hostId);
|
||||||
|
|
||||||
if (host != null && host.getHypervisorType() == HypervisorType.VMware) {
|
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 (sendCommand) {
|
||||||
if (host.getHypervisorType() == HypervisorType.KVM &&
|
if (host.getHypervisorType() == HypervisorType.KVM &&
|
||||||
volumeToAttachStoragePool.isManaged() &&
|
volumeToAttachStoragePool.isManaged() &&
|
||||||
@ -1963,9 +1985,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
|
|
||||||
AttachCommand cmd = new AttachCommand(disk, vm.getInstanceName());
|
AttachCommand cmd = new AttachCommand(disk, vm.getInstanceName());
|
||||||
|
|
||||||
VolumeInfo volumeInfo = volFactory.getVolume(volumeToAttach.getId());
|
ChapInfo chapInfo = queryForChap ? volService.getChapInfo(volFactory.getVolume(volumeToAttach.getId()), dataStore) : null;
|
||||||
DataStore dataStore = dataStoreMgr.getDataStore(volumeToAttachStoragePool.getId(), DataStoreRole.Primary);
|
|
||||||
ChapInfo chapInfo = volService.getChapInfo(volumeInfo, dataStore);
|
|
||||||
|
|
||||||
Map<String, String> details = new HashMap<String, String>();
|
Map<String, String> details = new HashMap<String, String>();
|
||||||
|
|
||||||
@ -1987,6 +2007,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
try {
|
try {
|
||||||
answer = (AttachAnswer)_agentMgr.send(hostId, cmd);
|
answer = (AttachAnswer)_agentMgr.send(hostId, cmd);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
volService.disconnectVolumeFromHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore);
|
||||||
|
|
||||||
throw new CloudRuntimeException(errorMsg + " due to: " + e.getMessage());
|
throw new CloudRuntimeException(errorMsg + " due to: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2023,6 +2045,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
errorMsg += "; " + details;
|
errorMsg += "; " + details;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
volService.disconnectVolumeFromHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore);
|
||||||
|
|
||||||
throw new CloudRuntimeException(errorMsg);
|
throw new CloudRuntimeException(errorMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -698,7 +698,9 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost {
|
|||||||
ManagedObjectReference morDs = oc.getObj();
|
ManagedObjectReference morDs = oc.getObj();
|
||||||
String name = (String)VmwareHelper.getPropValue(oc, "name");
|
String name = (String)VmwareHelper.getPropValue(oc, "name");
|
||||||
|
|
||||||
dsList.add(new Pair<ManagedObjectReference, String>(morDs, name));
|
if (!name.startsWith("-iqn.")) {
|
||||||
|
dsList.add(new Pair<ManagedObjectReference, String>(morDs, name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user