mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-03 04:12:31 +01:00
[PowerFlex] Add & Remove PowerFlex/ScaleIO MDMs for the storage SDC connections (#9903)
* Add & Remove PowerFlex/ScaleIO MDMs while preparing & unpreparing the storage SDC connections (instead of start & stop scini) * Add/Remove MDM IP addresses during Host connection/disconnection to/from storage pool when powerflex.connect.on.demand is false * unit test fixes * Don't remove MDM IPs from SDC when any volumes mapped to SDC * Don't remove MDM IPs when other pools of same ScaleIO/PowerFlex cluster are connected * rebase fixes * update changes, to not remove/disconnect MDMs on maintenance * import fixes after rebase
This commit is contained in:
parent
64828f66e8
commit
572fc11a64
@ -46,6 +46,10 @@ public class ModifyStoragePoolAnswer extends Answer {
|
||||
templateInfo = tInfo;
|
||||
}
|
||||
|
||||
public ModifyStoragePoolAnswer(ModifyStoragePoolCommand cmd, boolean success, String details) {
|
||||
super(cmd, success, details);
|
||||
}
|
||||
|
||||
public void setPoolInfo(StoragePoolInfo poolInfo) {
|
||||
this.poolInfo = poolInfo;
|
||||
}
|
||||
|
||||
@ -19,18 +19,22 @@
|
||||
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
|
||||
public class UnprepareStorageClientCommand extends Command {
|
||||
private StoragePoolType poolType;
|
||||
private String poolUuid;
|
||||
private Map<String, String> details;
|
||||
|
||||
public UnprepareStorageClientCommand() {
|
||||
}
|
||||
|
||||
public UnprepareStorageClientCommand(StoragePoolType poolType, String poolUuid) {
|
||||
public UnprepareStorageClientCommand(StoragePoolType poolType, String poolUuid, Map<String, String> details) {
|
||||
this.poolType = poolType;
|
||||
this.poolUuid = poolUuid;
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -45,4 +49,8 @@ public class UnprepareStorageClientCommand extends Command {
|
||||
public String getPoolUuid() {
|
||||
return poolUuid;
|
||||
}
|
||||
|
||||
public Map<String, String> getDetails() {
|
||||
return details;
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,4 +45,8 @@ public interface DataStoreDriver {
|
||||
boolean canCopy(DataObject srcData, DataObject destData);
|
||||
|
||||
void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||
|
||||
default boolean canDisplayDetails() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,6 +145,14 @@ public interface PrimaryDataStoreDriver extends DataStoreDriver {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* intended for managed storage
|
||||
* returns true if the host can be disconnected from storage pool
|
||||
*/
|
||||
default boolean canDisconnectHostFromStoragePool(Host host, StoragePool pool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by storage pools which want to keep VMs' information
|
||||
* @return true if additional VM info is needed (intended for storage pools).
|
||||
|
||||
@ -314,6 +314,8 @@ public interface StorageManager extends StorageService {
|
||||
|
||||
boolean canHostPrepareStoragePoolAccess(Host host, StoragePool pool);
|
||||
|
||||
boolean canDisconnectHostFromStoragePool(Host host, StoragePool pool);
|
||||
|
||||
Host getHost(long hostId);
|
||||
|
||||
Host updateSecondaryStorage(long secStorageId, String newUrl);
|
||||
|
||||
@ -30,6 +30,8 @@ public interface StoragePoolHostDao extends GenericDao<StoragePoolHostVO, Long>
|
||||
|
||||
public StoragePoolHostVO findByPoolHost(long poolId, long hostId);
|
||||
|
||||
List<StoragePoolHostVO> findByLocalPath(String path);
|
||||
|
||||
List<StoragePoolHostVO> listByHostStatus(long poolId, Status hostStatus);
|
||||
|
||||
List<Long> findHostsConnectedToPools(List<Long> poolIds);
|
||||
|
||||
@ -45,6 +45,7 @@ public class StoragePoolHostDaoImpl extends GenericDaoBase<StoragePoolHostVO, Lo
|
||||
protected final SearchBuilder<StoragePoolHostVO> PoolSearch;
|
||||
protected final SearchBuilder<StoragePoolHostVO> HostSearch;
|
||||
protected final SearchBuilder<StoragePoolHostVO> PoolHostSearch;
|
||||
protected final SearchBuilder<StoragePoolHostVO> LocalPathSearch;
|
||||
|
||||
protected SearchBuilder<StoragePoolHostVO> poolNotInClusterSearch;
|
||||
|
||||
@ -77,6 +78,9 @@ public class StoragePoolHostDaoImpl extends GenericDaoBase<StoragePoolHostVO, Lo
|
||||
PoolHostSearch.and("host_id", PoolHostSearch.entity().getHostId(), SearchCriteria.Op.EQ);
|
||||
PoolHostSearch.done();
|
||||
|
||||
LocalPathSearch = createSearchBuilder();
|
||||
LocalPathSearch.and("local_path", LocalPathSearch.entity().getLocalPath(), SearchCriteria.Op.EQ);
|
||||
LocalPathSearch.done();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@ -117,6 +121,13 @@ public class StoragePoolHostDaoImpl extends GenericDaoBase<StoragePoolHostVO, Lo
|
||||
return findOneIncludingRemovedBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StoragePoolHostVO> findByLocalPath(String path) {
|
||||
SearchCriteria<StoragePoolHostVO> sc = LocalPathSearch.create();
|
||||
sc.setParameters("local_path", path);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StoragePoolHostVO> listByHostStatus(long poolId, Status hostStatus) {
|
||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||
|
||||
@ -60,6 +60,8 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
||||
|
||||
StoragePoolVO persist(StoragePoolVO pool, Map<String, String> details, List<String> tags, Boolean isTagARule);
|
||||
|
||||
StoragePoolVO persist(StoragePoolVO pool, Map<String, String> details, List<String> tags, Boolean isTagARule, boolean displayDetails);
|
||||
|
||||
/**
|
||||
* Find pool by name.
|
||||
*
|
||||
@ -103,6 +105,8 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
||||
|
||||
void updateDetails(long poolId, Map<String, String> details);
|
||||
|
||||
void removeDetails(long poolId);
|
||||
|
||||
Map<String, String> getDetails(long poolId);
|
||||
|
||||
List<String> searchForStoragePoolTags(long poolId);
|
||||
|
||||
@ -296,14 +296,19 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public StoragePoolVO persist(StoragePoolVO pool, Map<String, String> details, List<String> tags, Boolean isTagARule) {
|
||||
return persist(pool, details, tags, isTagARule, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public StoragePoolVO persist(StoragePoolVO pool, Map<String, String> details, List<String> tags, Boolean isTagARule, boolean displayDetails) {
|
||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||
txn.start();
|
||||
pool = super.persist(pool);
|
||||
if (details != null) {
|
||||
for (Map.Entry<String, String> detail : details.entrySet()) {
|
||||
StoragePoolDetailVO vo = new StoragePoolDetailVO(pool.getId(), detail.getKey(), detail.getValue(), true);
|
||||
StoragePoolDetailVO vo = new StoragePoolDetailVO(pool.getId(), detail.getKey(), detail.getValue(), displayDetails);
|
||||
_detailsDao.persist(vo);
|
||||
}
|
||||
}
|
||||
@ -570,6 +575,11 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDetails(long poolId) {
|
||||
_detailsDao.removeDetails(poolId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getDetails(long poolId) {
|
||||
return _detailsDao.listDetailsKeyPairs(poolId);
|
||||
|
||||
@ -34,6 +34,7 @@ import org.apache.cloudstack.storage.datastore.api.SnapshotGroup;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClientConnectionPool;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.storage.datastore.util.ScaleIOUtil;
|
||||
@ -301,7 +302,11 @@ public class ScaleIOVMSnapshotStrategy extends ManagerBase implements VMSnapshot
|
||||
srcSnapshotDestVolumeMap.put(srcSnapshotVolumeId, destVolumeId);
|
||||
}
|
||||
|
||||
String systemId = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID).getValue();
|
||||
String systemId = null;
|
||||
StoragePoolDetailVO systemIdDetail = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID);
|
||||
if (systemIdDetail != null) {
|
||||
systemId = systemIdDetail.getValue();
|
||||
}
|
||||
if (systemId == null) {
|
||||
throw new CloudRuntimeException("Failed to get the system id for PowerFlex storage pool for reverting VM snapshot: " + vmSnapshot.getName());
|
||||
}
|
||||
@ -380,7 +385,11 @@ public class ScaleIOVMSnapshotStrategy extends ManagerBase implements VMSnapshot
|
||||
try {
|
||||
List<VolumeObjectTO> volumeTOs = vmSnapshotHelper.getVolumeTOList(vmSnapshot.getVmId());
|
||||
StoragePoolVO storagePool = vmSnapshotHelper.getStoragePoolForVM(userVm);
|
||||
String systemId = storagePoolDetailsDao.findDetail(storagePool.getId(), ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID).getValue();
|
||||
String systemId = null;
|
||||
StoragePoolDetailVO systemIdDetail = storagePoolDetailsDao.findDetail(storagePool.getId(), ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID);
|
||||
if (systemIdDetail != null) {
|
||||
systemId = systemIdDetail.getValue();
|
||||
}
|
||||
if (systemId == null) {
|
||||
throw new CloudRuntimeException("Failed to get the system id for PowerFlex storage pool for deleting VM snapshot: " + vmSnapshot.getName());
|
||||
}
|
||||
|
||||
@ -29,13 +29,16 @@ import javax.inject.Inject;
|
||||
import com.cloud.dc.dao.ClusterDao;
|
||||
import org.apache.cloudstack.annotation.AnnotationService;
|
||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
@ -78,6 +81,8 @@ public class PrimaryDataStoreHelper {
|
||||
protected ClusterDao clusterDao;
|
||||
@Inject
|
||||
private AnnotationDao annotationDao;
|
||||
@Inject
|
||||
DataStoreProviderManager dataStoreProviderMgr;
|
||||
|
||||
public DataStore createPrimaryDataStore(PrimaryDataStoreParameters params) {
|
||||
if(params == null)
|
||||
@ -144,7 +149,17 @@ public class PrimaryDataStoreHelper {
|
||||
storageTags.add(tag);
|
||||
}
|
||||
}
|
||||
dataStoreVO = dataStoreDao.persist(dataStoreVO, details, storageTags, params.isTagARule());
|
||||
|
||||
boolean displayDetails = true;
|
||||
DataStoreProvider storeProvider = dataStoreProviderMgr.getDataStoreProvider(params.getProviderName());
|
||||
if (storeProvider != null) {
|
||||
DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
|
||||
if (storeDriver != null) {
|
||||
displayDetails = storeDriver.canDisplayDetails();
|
||||
}
|
||||
}
|
||||
|
||||
dataStoreVO = dataStoreDao.persist(dataStoreVO, details, storageTags, params.isTagARule(), displayDetails);
|
||||
return dataStoreMgr.getDataStore(dataStoreVO.getId(), DataStoreRole.Primary);
|
||||
}
|
||||
|
||||
|
||||
@ -38,6 +38,17 @@ public final class LibvirtModifyStoragePoolCommandWrapper extends CommandWrapper
|
||||
@Override
|
||||
public Answer execute(final ModifyStoragePoolCommand command, final LibvirtComputingResource libvirtComputingResource) {
|
||||
final KVMStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr();
|
||||
if (!command.getAdd()) {
|
||||
boolean status = storagePoolMgr.deleteStoragePool(command.getPool().getType(), command.getPool().getUuid(), command.getDetails());
|
||||
if (status) {
|
||||
final ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(command, true, null);
|
||||
return answer;
|
||||
}
|
||||
|
||||
final ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(command, false, "Failed to delete storage pool");
|
||||
return answer;
|
||||
}
|
||||
|
||||
final KVMStoragePool storagepool =
|
||||
storagePoolMgr.createStoragePool(command.getPool().getUuid(), command.getPool().getHost(), command.getPool().getPort(), command.getPool().getPath(), command.getPool()
|
||||
.getUserInfo(), command.getPool().getType(), command.getDetails());
|
||||
@ -47,7 +58,6 @@ public final class LibvirtModifyStoragePoolCommandWrapper extends CommandWrapper
|
||||
|
||||
final Map<String, TemplateProp> tInfo = new HashMap<String, TemplateProp>();
|
||||
final ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(command, storagepool.getCapacity(), storagepool.getAvailable(), tInfo, storagepool.getDetails());
|
||||
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ public class LibvirtUnprepareStorageClientCommandWrapper extends CommandWrapper<
|
||||
@Override
|
||||
public Answer execute(UnprepareStorageClientCommand cmd, LibvirtComputingResource libvirtComputingResource) {
|
||||
final KVMStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr();
|
||||
Pair<Boolean, String> unprepareStorageClientResult = storagePoolMgr.unprepareStorageClient(cmd.getPoolType(), cmd.getPoolUuid());
|
||||
Pair<Boolean, String> unprepareStorageClientResult = storagePoolMgr.unprepareStorageClient(cmd.getPoolType(), cmd.getPoolUuid(), cmd.getDetails());
|
||||
if (!unprepareStorageClientResult.first()) {
|
||||
String msg = unprepareStorageClientResult.second();
|
||||
logger.debug("Couldn't unprepare storage client, due to: " + msg);
|
||||
|
||||
@ -408,12 +408,26 @@ public class KVMStoragePoolManager {
|
||||
|
||||
public boolean deleteStoragePool(StoragePoolType type, String uuid) {
|
||||
StorageAdaptor adaptor = getStorageAdaptor(type);
|
||||
_haMonitor.removeStoragePool(uuid);
|
||||
adaptor.deleteStoragePool(uuid);
|
||||
if (type == StoragePoolType.NetworkFilesystem) {
|
||||
_haMonitor.removeStoragePool(uuid);
|
||||
}
|
||||
boolean deleteStatus = adaptor.deleteStoragePool(uuid);;
|
||||
synchronized (_storagePools) {
|
||||
_storagePools.remove(uuid);
|
||||
}
|
||||
return true;
|
||||
return deleteStatus;
|
||||
}
|
||||
|
||||
public boolean deleteStoragePool(StoragePoolType type, String uuid, Map<String, String> details) {
|
||||
StorageAdaptor adaptor = getStorageAdaptor(type);
|
||||
if (type == StoragePoolType.NetworkFilesystem) {
|
||||
_haMonitor.removeStoragePool(uuid);
|
||||
}
|
||||
boolean deleteStatus = adaptor.deleteStoragePool(uuid, details);
|
||||
synchronized (_storagePools) {
|
||||
_storagePools.remove(uuid);
|
||||
}
|
||||
return deleteStatus;
|
||||
}
|
||||
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, Storage.ProvisioningType provisioningType,
|
||||
@ -477,11 +491,11 @@ public class KVMStoragePoolManager {
|
||||
|
||||
public Ternary<Boolean, Map<String, String>, String> prepareStorageClient(StoragePoolType type, String uuid, Map<String, String> details) {
|
||||
StorageAdaptor adaptor = getStorageAdaptor(type);
|
||||
return adaptor.prepareStorageClient(type, uuid, details);
|
||||
return adaptor.prepareStorageClient(uuid, details);
|
||||
}
|
||||
|
||||
public Pair<Boolean, String> unprepareStorageClient(StoragePoolType type, String uuid) {
|
||||
public Pair<Boolean, String> unprepareStorageClient(StoragePoolType type, String uuid, Map<String, String> details) {
|
||||
StorageAdaptor adaptor = getStorageAdaptor(type);
|
||||
return adaptor.unprepareStorageClient(type, uuid);
|
||||
return adaptor.unprepareStorageClient(uuid, details);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient;
|
||||
import org.apache.cloudstack.storage.datastore.manager.ScaleIOSDCManager;
|
||||
import org.apache.cloudstack.storage.datastore.util.ScaleIOUtil;
|
||||
import org.apache.cloudstack.utils.cryptsetup.CryptSetup;
|
||||
import org.apache.cloudstack.utils.cryptsetup.CryptSetupException;
|
||||
@ -148,12 +149,37 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor {
|
||||
@Override
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
|
||||
ScaleIOStoragePool storagePool = new ScaleIOStoragePool(uuid, host, port, path, type, details, this);
|
||||
if (details != null && details.containsKey(ScaleIOSDCManager.ConnectOnDemand.key())) {
|
||||
String connectOnDemand = details.get(ScaleIOSDCManager.ConnectOnDemand.key());
|
||||
if (connectOnDemand != null && !Boolean.parseBoolean(connectOnDemand)) {
|
||||
Ternary<Boolean, Map<String, String>, String> prepareStorageClientStatus = prepareStorageClient(uuid, details);
|
||||
if (prepareStorageClientStatus.first()) {
|
||||
details.putAll(prepareStorageClientStatus.second());
|
||||
}
|
||||
}
|
||||
}
|
||||
MapStorageUuidToStoragePool.put(uuid, storagePool);
|
||||
return storagePool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteStoragePool(String uuid) {
|
||||
ScaleIOStoragePool storagePool = (ScaleIOStoragePool) MapStorageUuidToStoragePool.get(uuid);
|
||||
if (storagePool != null) {
|
||||
unprepareStorageClient(uuid, storagePool.getDetails());
|
||||
}
|
||||
return MapStorageUuidToStoragePool.remove(uuid) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteStoragePool(String uuid, Map<String, String> details) {
|
||||
if (details != null && details.containsKey(ScaleIOSDCManager.ConnectOnDemand.key())) {
|
||||
String connectOnDemand = details.get(ScaleIOSDCManager.ConnectOnDemand.key());
|
||||
if (connectOnDemand != null && !Boolean.parseBoolean(connectOnDemand)) {
|
||||
Pair<Boolean, String> unprepareStorageClientStatus = unprepareStorageClient(uuid, details);
|
||||
return MapStorageUuidToStoragePool.remove(uuid) != null && unprepareStorageClientStatus.first();
|
||||
}
|
||||
}
|
||||
return MapStorageUuidToStoragePool.remove(uuid) != null;
|
||||
}
|
||||
|
||||
@ -567,7 +593,7 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor {
|
||||
qemu.resize(options, objects, usableSizeBytes);
|
||||
}
|
||||
|
||||
public Ternary<Boolean, Map<String, String>, String> prepareStorageClient(Storage.StoragePoolType type, String uuid, Map<String, String> details) {
|
||||
public Ternary<Boolean, Map<String, String>, String> prepareStorageClient(String uuid, Map<String, String> details) {
|
||||
if (!ScaleIOUtil.isSDCServiceInstalled()) {
|
||||
logger.debug("SDC service not installed on host, preparing the SDC client not possible");
|
||||
return new Ternary<>(false, null, "SDC service not installed on host");
|
||||
@ -584,14 +610,28 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor {
|
||||
if (!ScaleIOUtil.startSDCService()) {
|
||||
return new Ternary<>(false, null, "Couldn't start SDC service on host");
|
||||
}
|
||||
} else if (!ScaleIOUtil.restartSDCService()) {
|
||||
return new Ternary<>(false, null, "Couldn't restart SDC service on host");
|
||||
}
|
||||
|
||||
if (details != null && details.containsKey(ScaleIOGatewayClient.STORAGE_POOL_MDMS)) {
|
||||
// Assuming SDC service is started, add mdms
|
||||
String mdms = details.get(ScaleIOGatewayClient.STORAGE_POOL_MDMS);
|
||||
String[] mdmAddresses = mdms.split(",");
|
||||
if (mdmAddresses.length > 0) {
|
||||
if (ScaleIOUtil.mdmAdded(mdmAddresses[0])) {
|
||||
return new Ternary<>(true, getSDCDetails(details), "MDM added, no need to prepare the SDC client");
|
||||
}
|
||||
|
||||
ScaleIOUtil.addMdms(Arrays.asList(mdmAddresses));
|
||||
if (!ScaleIOUtil.mdmAdded(mdmAddresses[0])) {
|
||||
return new Ternary<>(false, null, "Failed to add MDMs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Ternary<>( true, getSDCDetails(details), "Prepared client successfully");
|
||||
}
|
||||
|
||||
public Pair<Boolean, String> unprepareStorageClient(Storage.StoragePoolType type, String uuid) {
|
||||
public Pair<Boolean, String> unprepareStorageClient(String uuid, Map<String, String> details) {
|
||||
if (!ScaleIOUtil.isSDCServiceInstalled()) {
|
||||
logger.debug("SDC service not installed on host, no need to unprepare the SDC client");
|
||||
return new Pair<>(true, "SDC service not installed on host, no need to unprepare the SDC client");
|
||||
@ -602,8 +642,19 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor {
|
||||
return new Pair<>(true, "SDC service not enabled on host, no need to unprepare the SDC client");
|
||||
}
|
||||
|
||||
if (!ScaleIOUtil.stopSDCService()) {
|
||||
return new Pair<>(false, "Couldn't stop SDC service on host");
|
||||
if (details != null && details.containsKey(ScaleIOGatewayClient.STORAGE_POOL_MDMS)) {
|
||||
String mdms = details.get(ScaleIOGatewayClient.STORAGE_POOL_MDMS);
|
||||
String[] mdmAddresses = mdms.split(",");
|
||||
if (mdmAddresses.length > 0) {
|
||||
if (!ScaleIOUtil.mdmAdded(mdmAddresses[0])) {
|
||||
return new Pair<>(true, "MDM not added, no need to unprepare the SDC client");
|
||||
}
|
||||
|
||||
ScaleIOUtil.removeMdms(Arrays.asList(mdmAddresses));
|
||||
if (ScaleIOUtil.mdmAdded(mdmAddresses[0])) {
|
||||
return new Pair<>(false, "Failed to remove MDMs, unable to unprepare the SDC client");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Pair<>(true, "Unprepared SDC client successfully");
|
||||
|
||||
@ -44,6 +44,10 @@ public interface StorageAdaptor {
|
||||
|
||||
public boolean deleteStoragePool(String uuid);
|
||||
|
||||
public default boolean deleteStoragePool(String uuid, Map<String, String> details) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public default KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool,
|
||||
PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, Long usableSize, byte[] passphrase) {
|
||||
return createPhysicalDisk(name, pool, format, provisioningType, size, passphrase);
|
||||
@ -127,22 +131,21 @@ public interface StorageAdaptor {
|
||||
|
||||
/**
|
||||
* Prepares the storage client.
|
||||
* @param type type of the storage pool
|
||||
* @param uuid uuid of the storage pool
|
||||
* @param details any details of the storage pool that are required for client preparation
|
||||
* @return status, client details, & message in case failed
|
||||
*/
|
||||
default Ternary<Boolean, Map<String, String>, String> prepareStorageClient(StoragePoolType type, String uuid, Map<String, String> details) {
|
||||
default Ternary<Boolean, Map<String, String>, String> prepareStorageClient(String uuid, Map<String, String> details) {
|
||||
return new Ternary<>(true, new HashMap<>(), "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unprepares the storage client.
|
||||
* @param type type of the storage pool
|
||||
* @param uuid uuid of the storage pool
|
||||
* @param details any details of the storage pool that are required for client unpreparation
|
||||
* @return status, & message in case failed
|
||||
*/
|
||||
default Pair<Boolean, String> unprepareStorageClient(StoragePoolType type, String uuid) {
|
||||
default Pair<Boolean, String> unprepareStorageClient(String uuid, Map<String, String> details) {
|
||||
return new Pair<>(true, "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,10 @@
|
||||
|
||||
package com.cloud.hypervisor.kvm.resource.wrapper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -45,10 +49,13 @@ public class LibvirtUnprepareStorageClientCommandWrapperTest {
|
||||
UnprepareStorageClientCommand cmd = Mockito.mock(UnprepareStorageClientCommand.class);
|
||||
Mockito.when(cmd.getPoolType()).thenReturn(Storage.StoragePoolType.PowerFlex);
|
||||
Mockito.when(cmd.getPoolUuid()).thenReturn(poolUuid);
|
||||
Map<String, String> details = new HashMap<>();
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, "1.1.1.1,2.2.2.2");
|
||||
Mockito.when(cmd.getDetails()).thenReturn(details);
|
||||
|
||||
KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class);
|
||||
Mockito.when(libvirtComputingResourceMock.getStoragePoolMgr()).thenReturn(storagePoolMgr);
|
||||
Mockito.when(storagePoolMgr.unprepareStorageClient(cmd.getPoolType(), cmd.getPoolUuid())).thenReturn(new Pair<>(true, ""));
|
||||
Mockito.when(storagePoolMgr.unprepareStorageClient(cmd.getPoolType(), cmd.getPoolUuid(), cmd.getDetails())).thenReturn(new Pair<>(true, ""));
|
||||
|
||||
UnprepareStorageClientAnswer result = (UnprepareStorageClientAnswer) libvirtUnprepareStorageClientCommandWrapperSpy.execute(cmd, libvirtComputingResourceMock);
|
||||
|
||||
@ -60,10 +67,13 @@ public class LibvirtUnprepareStorageClientCommandWrapperTest {
|
||||
UnprepareStorageClientCommand cmd = Mockito.mock(UnprepareStorageClientCommand.class);
|
||||
Mockito.when(cmd.getPoolType()).thenReturn(Storage.StoragePoolType.PowerFlex);
|
||||
Mockito.when(cmd.getPoolUuid()).thenReturn(poolUuid);
|
||||
Map<String, String> details = new HashMap<>();
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, "1.1.1.1,2.2.2.2");
|
||||
Mockito.when(cmd.getDetails()).thenReturn(details);
|
||||
|
||||
KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class);
|
||||
Mockito.when(libvirtComputingResourceMock.getStoragePoolMgr()).thenReturn(storagePoolMgr);
|
||||
Mockito.when(storagePoolMgr.unprepareStorageClient(cmd.getPoolType(), cmd.getPoolUuid())).thenReturn(new Pair<>(false, "Unprepare storage client failed"));
|
||||
Mockito.when(storagePoolMgr.unprepareStorageClient(cmd.getPoolType(), cmd.getPoolUuid(), cmd.getDetails())).thenReturn(new Pair<>(false, "Unprepare storage client failed"));
|
||||
|
||||
UnprepareStorageClientAnswer result = (UnprepareStorageClientAnswer) libvirtUnprepareStorageClientCommandWrapperSpy.execute(cmd, libvirtComputingResourceMock);
|
||||
|
||||
|
||||
@ -34,7 +34,6 @@ import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.storage.StorageLayer;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.Ternary;
|
||||
@ -73,7 +72,7 @@ public class ScaleIOStorageAdaptorTest {
|
||||
public void testPrepareStorageClient_SDCServiceNotInstalled() {
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl status scini"))).thenReturn(4);
|
||||
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid, new HashMap<>());
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(poolUuid, new HashMap<>());
|
||||
|
||||
Assert.assertFalse(result.first());
|
||||
Assert.assertNull(result.second());
|
||||
@ -86,41 +85,13 @@ public class ScaleIOStorageAdaptorTest {
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl is-enabled scini"))).thenReturn(1);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl enable scini"))).thenReturn(1);
|
||||
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid, new HashMap<>());
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(poolUuid, new HashMap<>());
|
||||
|
||||
Assert.assertFalse(result.first());
|
||||
Assert.assertNull(result.second());
|
||||
Assert.assertEquals("SDC service not enabled on host", result.third());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrepareStorageClient_SDCServiceNotRestarted() {
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl status scini"))).thenReturn(3);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl is-enabled scini"))).thenReturn(0);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl is-active scini"))).thenReturn(0);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl restart scini"))).thenReturn(1);
|
||||
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid, new HashMap<>());
|
||||
|
||||
Assert.assertFalse(result.first());
|
||||
Assert.assertNull(result.second());
|
||||
Assert.assertEquals("Couldn't restart SDC service on host", result.third());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrepareStorageClient_SDCServiceRestarted() {
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl status scini"))).thenReturn(3);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl is-enabled scini"))).thenReturn(0);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl is-active scini"))).thenReturn(0);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl restart scini"))).thenReturn(0);
|
||||
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid, new HashMap<>());
|
||||
|
||||
Assert.assertTrue(result.first());
|
||||
Assert.assertNotNull(result.second());
|
||||
Assert.assertTrue(result.second().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrepareStorageClient_SDCServiceNotStarted() {
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl status scini"))).thenReturn(3);
|
||||
@ -128,7 +99,7 @@ public class ScaleIOStorageAdaptorTest {
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl is-active scini"))).thenReturn(1);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl start scini"))).thenReturn(1);
|
||||
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid, new HashMap<>());
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(poolUuid, new HashMap<>());
|
||||
|
||||
Assert.assertFalse(result.first());
|
||||
Assert.assertNull(result.second());
|
||||
@ -149,7 +120,7 @@ public class ScaleIOStorageAdaptorTest {
|
||||
String sdcId = "301b852c00000003";
|
||||
when(ScaleIOUtil.getSdcId(systemId)).thenReturn(sdcId);
|
||||
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid, details);
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(poolUuid, details);
|
||||
|
||||
Assert.assertTrue(result.first());
|
||||
Assert.assertNotNull(result.second());
|
||||
@ -172,7 +143,8 @@ public class ScaleIOStorageAdaptorTest {
|
||||
when(ScaleIOUtil.getSdcId(systemId)).thenReturn(null);
|
||||
when(ScaleIOUtil.getSdcGuid()).thenReturn(sdcGuid);
|
||||
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid, details);
|
||||
Ternary<Boolean, Map<String, String>, String> result = scaleIOStorageAdaptor.prepareStorageClient(poolUuid, details);
|
||||
|
||||
Assert.assertTrue(result.first());
|
||||
Assert.assertNotNull(result.second());
|
||||
Assert.assertEquals(sdcGuid, result.second().get(ScaleIOGatewayClient.SDC_GUID));
|
||||
@ -181,9 +153,10 @@ public class ScaleIOStorageAdaptorTest {
|
||||
|
||||
@Test
|
||||
public void testUnprepareStorageClient_SDCServiceNotInstalled() {
|
||||
Map<String, String> details = new HashMap<>();
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl status scini"))).thenReturn(4);
|
||||
|
||||
Pair<Boolean, String> result = scaleIOStorageAdaptor.unprepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid);
|
||||
Pair<Boolean, String> result = scaleIOStorageAdaptor.unprepareStorageClient(poolUuid, details);
|
||||
|
||||
Assert.assertTrue(result.first());
|
||||
Assert.assertEquals("SDC service not installed on host, no need to unprepare the SDC client", result.second());
|
||||
@ -191,35 +164,42 @@ public class ScaleIOStorageAdaptorTest {
|
||||
|
||||
@Test
|
||||
public void testUnprepareStorageClient_SDCServiceNotEnabled() {
|
||||
Map<String, String> details = new HashMap<>();
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl status scini"))).thenReturn(3);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl is-enabled scini"))).thenReturn(1);
|
||||
|
||||
Pair<Boolean, String> result = scaleIOStorageAdaptor.unprepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid);
|
||||
Pair<Boolean, String> result = scaleIOStorageAdaptor.unprepareStorageClient(poolUuid, details);
|
||||
|
||||
Assert.assertTrue(result.first());
|
||||
Assert.assertEquals("SDC service not enabled on host, no need to unprepare the SDC client", result.second());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnprepareStorageClient_SDCServiceNotStopped() {
|
||||
public void testUnprepareStorageClient_MDMNotAdded() {
|
||||
Map<String, String> details = new HashMap<>();
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, "1.1.1.1,2.2.2.2");
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl status scini"))).thenReturn(3);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl is-enabled scini"))).thenReturn(0);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl stop scini"))).thenReturn(1);
|
||||
when(Script.runSimpleBashScript(Mockito.eq("/opt/emc/scaleio/sdc/bin/drv_cfg --query_mdms|grep 1.1.1.1"))).thenReturn("MDM-ID 71fd458f0775010f SDC ID 4421a91a00000000 INSTALLATION ID 204930df2cbcaf8e IPs [0]-3.3.3.3 [1]-4.4.4.4");
|
||||
|
||||
Pair<Boolean, String> result = scaleIOStorageAdaptor.unprepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid);
|
||||
Pair<Boolean, String> result = scaleIOStorageAdaptor.unprepareStorageClient(poolUuid, details);
|
||||
|
||||
Assert.assertFalse(result.first());
|
||||
Assert.assertEquals("Couldn't stop SDC service on host", result.second());
|
||||
Assert.assertTrue(result.first());
|
||||
Assert.assertEquals("MDM not added, no need to unprepare the SDC client", result.second());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnprepareStorageClient_SDCServiceStopped() {
|
||||
public void testUnprepareStorageClient_RemoveMDMFailed() {
|
||||
Map<String, String> details = new HashMap<>();
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, "1.1.1.1,2.2.2.2");
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl status scini"))).thenReturn(3);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl is-enabled scini"))).thenReturn(0);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl stop scini"))).thenReturn(0);
|
||||
when(Script.runSimpleBashScriptForExitValue(Mockito.eq("systemctl restart scini"))).thenReturn(0);
|
||||
when(Script.runSimpleBashScript(Mockito.eq("/opt/emc/scaleio/sdc/bin/drv_cfg --query_mdms|grep 1.1.1.1"))).thenReturn("MDM-ID 71fd458f0775010f SDC ID 4421a91a00000000 INSTALLATION ID 204930df2cbcaf8e IPs [0]-1.1.1.1 [1]-2.2.2.2");
|
||||
|
||||
Pair<Boolean, String> result = scaleIOStorageAdaptor.unprepareStorageClient(Storage.StoragePoolType.PowerFlex, poolUuid);
|
||||
Pair<Boolean, String> result = scaleIOStorageAdaptor.unprepareStorageClient(poolUuid, details);
|
||||
|
||||
Assert.assertTrue(result.first());
|
||||
Assert.assertFalse(result.first());
|
||||
Assert.assertEquals("Failed to remove MDMs, unable to unprepare the SDC client", result.second());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.storage.datastore.api;
|
||||
|
||||
public class StorageConfiguration {
|
||||
String systemId;
|
||||
Long mdmPort;
|
||||
String[] mdmAddresses;
|
||||
|
||||
public String getSystemId() {
|
||||
return systemId;
|
||||
}
|
||||
|
||||
public void setSystemId(String systemId) {
|
||||
this.systemId = systemId;
|
||||
}
|
||||
|
||||
public Long getMdmPort() {
|
||||
return mdmPort;
|
||||
}
|
||||
|
||||
public void setMdmPort(Long mdmPort) {
|
||||
this.mdmPort = mdmPort;
|
||||
}
|
||||
|
||||
public String[] getMdmAddresses() {
|
||||
return mdmAddresses;
|
||||
}
|
||||
|
||||
public void setMdmAddresses(String[] mdmAddresses) {
|
||||
this.mdmAddresses = mdmAddresses;
|
||||
}
|
||||
}
|
||||
@ -17,12 +17,15 @@
|
||||
|
||||
package org.apache.cloudstack.storage.datastore.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StoragePool {
|
||||
String id;
|
||||
String name;
|
||||
String mediaType;
|
||||
String protectionDomainId;
|
||||
String systemId;
|
||||
List<String> mdmAddresses;
|
||||
StoragePoolStatistics statistics;
|
||||
|
||||
public String getId() {
|
||||
@ -65,6 +68,14 @@ public class StoragePool {
|
||||
this.systemId = systemId;
|
||||
}
|
||||
|
||||
public List<String> getMdmAddresses() {
|
||||
return mdmAddresses;
|
||||
}
|
||||
|
||||
public void setMdmAddresses(List<String> mdmAddresses) {
|
||||
this.mdmAddresses = mdmAddresses;
|
||||
}
|
||||
|
||||
public StoragePoolStatistics getStatistics() {
|
||||
return statistics;
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ public interface ScaleIOGatewayClient {
|
||||
String GATEWAY_API_PASSWORD = "powerflex.gw.password";
|
||||
String STORAGE_POOL_NAME = "powerflex.storagepool.name";
|
||||
String STORAGE_POOL_SYSTEM_ID = "powerflex.storagepool.system.id";
|
||||
String STORAGE_POOL_MDMS = "powerflex.storagepool.mdms";
|
||||
String SDC_ID = "powerflex.sdc.id";
|
||||
String SDC_GUID = "powerflex.sdc.guid";
|
||||
|
||||
@ -91,4 +92,6 @@ public interface ScaleIOGatewayClient {
|
||||
boolean haveConnectedSdcs();
|
||||
boolean isSdcConnected(String sdcId);
|
||||
boolean isSdcConnectedByIP(String ipAddress);
|
||||
|
||||
List<String> getMdmAddresses();
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.cloud.storage.StoragePool;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -76,11 +77,23 @@ public class ScaleIOGatewayClientConnectionPool {
|
||||
synchronized (gatewayClients) {
|
||||
client = gatewayClients.get(storagePoolId);
|
||||
if (client == null) {
|
||||
final String url = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_ENDPOINT).getValue();
|
||||
final String encryptedUsername = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_USERNAME).getValue();
|
||||
final String username = DBEncryptionUtil.decrypt(encryptedUsername);
|
||||
final String encryptedPassword = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_PASSWORD).getValue();
|
||||
final String password = DBEncryptionUtil.decrypt(encryptedPassword);
|
||||
String url = null;
|
||||
StoragePoolDetailVO urlDetail = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_ENDPOINT);
|
||||
if (urlDetail != null) {
|
||||
url = urlDetail.getValue();
|
||||
}
|
||||
String username = null;
|
||||
StoragePoolDetailVO encryptedUsernameDetail = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_USERNAME);
|
||||
if (encryptedUsernameDetail != null) {
|
||||
final String encryptedUsername = encryptedUsernameDetail.getValue();
|
||||
username = DBEncryptionUtil.decrypt(encryptedUsername);
|
||||
}
|
||||
String password = null;
|
||||
StoragePoolDetailVO encryptedPasswordDetail = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_PASSWORD);
|
||||
if (encryptedPasswordDetail != null) {
|
||||
final String encryptedPassword = encryptedPasswordDetail.getValue();
|
||||
password = DBEncryptionUtil.decrypt(encryptedPassword);
|
||||
}
|
||||
final int clientTimeout = StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.valueIn(storagePoolId);
|
||||
final int clientMaxConnections = StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.valueIn(storagePoolId);
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ import java.util.Map;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.apache.cloudstack.storage.datastore.api.StorageConfiguration;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
@ -1126,6 +1127,15 @@ public class ScaleIOGatewayClientImpl implements ScaleIOGatewayClient {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMdmAddresses() {
|
||||
StorageConfiguration storageConfiguration = get("/Configuration", StorageConfiguration.class);
|
||||
if (storageConfiguration != null && storageConfiguration.getMdmAddresses().length > 0) {
|
||||
return Arrays.asList(storageConfiguration.getMdmAddresses());
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private String getConnectionManagerStats() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n").append("Client Connection Manager Stats => ");
|
||||
|
||||
@ -268,7 +268,7 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
}
|
||||
if (client.listVolumesMappedToSdc(sdcId).isEmpty()) {
|
||||
sdcManager = ComponentContext.inject(sdcManager);
|
||||
sdcManager.stopSDC(host, dataStore);
|
||||
sdcManager.unprepareSDC(host, dataStore);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to revoke access due to: " + e.getMessage(), e);
|
||||
@ -296,7 +296,7 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
client.unmapVolumeFromSdc(ScaleIOUtil.getVolumePath(volumePath), sdcId);
|
||||
if (client.listVolumesMappedToSdc(sdcId).isEmpty()) {
|
||||
sdcManager = ComponentContext.inject(sdcManager);
|
||||
sdcManager.stopSDC(host, dataStore);
|
||||
sdcManager.unprepareSDC(host, dataStore);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to revoke access due to: " + e.getMessage(), e);
|
||||
@ -1112,7 +1112,11 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
volumeDetails.put(DiskTO.CHAP_TARGET_SECRET, chapInfo.getTargetSecret());
|
||||
}
|
||||
|
||||
String systemId = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID).getValue();
|
||||
String systemId = null;
|
||||
StoragePoolDetailVO systemIdDetail = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID);
|
||||
if (systemIdDetail != null) {
|
||||
systemId = systemIdDetail.getValue();
|
||||
}
|
||||
volumeDetails.put(ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID, systemId);
|
||||
|
||||
return volumeDetails;
|
||||
@ -1522,6 +1526,37 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
return sdcManager.areSDCConnectionsWithinLimit(pool.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDisconnectHostFromStoragePool(Host host, StoragePool pool) {
|
||||
if (host == null || pool == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
StoragePoolHostVO poolHostVO = storagePoolHostDao.findByPoolHost(pool.getId(), host.getId());
|
||||
if (poolHostVO == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String sdcId = poolHostVO.getLocalPath();
|
||||
if (StringUtils.isBlank(sdcId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<StoragePoolHostVO> poolHostVOsBySdc = storagePoolHostDao.findByLocalPath(sdcId);
|
||||
if (CollectionUtils.isNotEmpty(poolHostVOsBySdc) && poolHostVOsBySdc.size() > 1) {
|
||||
logger.debug(String.format("There are other connected pools with the same SDC of the host %s, shouldn't disconnect SDC", host));
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final ScaleIOGatewayClient client = getScaleIOClient(pool);
|
||||
return client.listVolumesMappedToSdc(sdcId).isEmpty();
|
||||
} catch (Exception e) {
|
||||
logger.warn("Unable to check whether the host: " + host.getId() + " can be disconnected from storage pool: " + pool.getId() + ", due to " + e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void alertHostSdcDisconnection(Host host) {
|
||||
if (host == null) {
|
||||
return;
|
||||
@ -1591,4 +1626,9 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
public boolean zoneWideVolumesAvailableWithoutClusterMotion() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDisplayDetails() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,35 +18,6 @@
|
||||
*/
|
||||
package org.apache.cloudstack.storage.datastore.lifecycle;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.utils.StringUtils;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
||||
import org.apache.cloudstack.storage.datastore.api.StoragePoolStatistics;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClientConnectionPool;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.storage.datastore.util.ScaleIOUtil;
|
||||
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.api.StoragePoolInfo;
|
||||
import com.cloud.capacity.CapacityManager;
|
||||
@ -63,9 +34,41 @@ import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.StoragePoolAutomation;
|
||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||
import com.cloud.template.TemplateManager;
|
||||
import com.cloud.utils.StringUtils;
|
||||
import com.cloud.utils.UriUtils;
|
||||
import com.cloud.utils.component.ComponentContext;
|
||||
import com.cloud.utils.crypt.DBEncryptionUtil;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
||||
import org.apache.cloudstack.storage.datastore.api.StoragePoolStatistics;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClientConnectionPool;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.storage.datastore.manager.ScaleIOSDCManager;
|
||||
import org.apache.cloudstack.storage.datastore.manager.ScaleIOSDCManagerImpl;
|
||||
import org.apache.cloudstack.storage.datastore.util.ScaleIOUtil;
|
||||
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
|
||||
@Inject
|
||||
@ -94,8 +97,10 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
|
||||
private TemplateManager templateMgr;
|
||||
@Inject
|
||||
private AgentManager agentMgr;
|
||||
private ScaleIOSDCManager sdcManager;
|
||||
|
||||
public ScaleIOPrimaryDataStoreLifeCycle() {
|
||||
sdcManager = new ScaleIOSDCManagerImpl();
|
||||
}
|
||||
|
||||
private org.apache.cloudstack.storage.datastore.api.StoragePool findStoragePool(String url, String username, String password, String storagePoolName) {
|
||||
@ -112,6 +117,8 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
|
||||
|
||||
String systemId = client.getSystemId(pool.getProtectionDomainId());
|
||||
pool.setSystemId(systemId);
|
||||
List<String> mdmAddresses = client.getMdmAddresses();
|
||||
pool.setMdmAddresses(mdmAddresses);
|
||||
return pool;
|
||||
}
|
||||
}
|
||||
@ -239,6 +246,7 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
|
||||
details.put(ScaleIOGatewayClient.GATEWAY_API_PASSWORD, DBEncryptionUtil.encrypt(gatewayPassword));
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_NAME, storagePoolName);
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID, scaleIOPool.getSystemId());
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, org.apache.commons.lang3.StringUtils.join(scaleIOPool.getMdmAddresses(), ","));
|
||||
parameters.setDetails(details);
|
||||
|
||||
return dataStoreHelper.createPrimaryDataStore(parameters);
|
||||
@ -288,15 +296,43 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
|
||||
|
||||
@Override
|
||||
public boolean maintain(DataStore store) {
|
||||
storagePoolAutomation.maintain(store);
|
||||
Map<String,String> details = new HashMap<>();
|
||||
StoragePoolDetailVO systemIdDetail = storagePoolDetailsDao.findDetail(store.getId(), ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID);
|
||||
if (systemIdDetail != null) {
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID, systemIdDetail.getValue());
|
||||
StoragePoolDetailVO mdmsDetail = storagePoolDetailsDao.findDetail(store.getId(), ScaleIOGatewayClient.STORAGE_POOL_MDMS);
|
||||
if (mdmsDetail != null) {
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, mdmsDetail.getValue());
|
||||
details.put(ScaleIOSDCManager.ConnectOnDemand.key(), "false");
|
||||
}
|
||||
}
|
||||
|
||||
storagePoolAutomation.maintain(store, details);
|
||||
dataStoreHelper.maintain(store);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancelMaintain(DataStore store) {
|
||||
Map<String,String> details = new HashMap<>();
|
||||
StoragePoolDetailVO systemIdDetail = storagePoolDetailsDao.findDetail(store.getId(), ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID);
|
||||
if (systemIdDetail != null) {
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID, systemIdDetail.getValue());
|
||||
sdcManager = ComponentContext.inject(sdcManager);
|
||||
if (sdcManager.areSDCConnectionsWithinLimit(store.getId())) {
|
||||
StoragePoolVO storagePoolVO = primaryDataStoreDao.findById(store.getId());
|
||||
if (storagePoolVO != null) {
|
||||
details.put(ScaleIOSDCManager.ConnectOnDemand.key(), String.valueOf(ScaleIOSDCManager.ConnectOnDemand.valueIn(storagePoolVO.getDataCenterId())));
|
||||
StoragePoolDetailVO mdmsDetail = storagePoolDetailsDao.findDetail(store.getId(), ScaleIOGatewayClient.STORAGE_POOL_MDMS);
|
||||
if (mdmsDetail != null) {
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, mdmsDetail.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dataStoreHelper.cancelMaintain(store);
|
||||
storagePoolAutomation.cancelMaintain(store);
|
||||
storagePoolAutomation.cancelMaintain(store, details);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -314,7 +350,12 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
|
||||
public boolean deleteDataStore(DataStore dataStore) {
|
||||
if (cleanupDatastore(dataStore)) {
|
||||
ScaleIOGatewayClientConnectionPool.getInstance().removeClient(dataStore);
|
||||
return dataStoreHelper.deletePrimaryDataStore(dataStore);
|
||||
|
||||
boolean isDeleted = dataStoreHelper.deletePrimaryDataStore(dataStore);
|
||||
if (isDeleted) {
|
||||
primaryDataStoreDao.removeDetails(dataStore.getId());
|
||||
}
|
||||
return isDeleted;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -18,10 +18,20 @@
|
||||
package org.apache.cloudstack.storage.datastore.manager;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
|
||||
import com.cloud.host.Host;
|
||||
|
||||
public interface ScaleIOSDCManager {
|
||||
ConfigKey<Boolean> ConnectOnDemand = new ConfigKey<>("Storage",
|
||||
Boolean.class,
|
||||
"powerflex.connect.on.demand",
|
||||
Boolean.FALSE.toString(),
|
||||
"When true, connects PowerFlex client on Host when first Volume is mapped to SDC & client connections configured 'storage.pool.connected.clients.limit' are within the limit and disconnects when last Volume is unmapped from SDC; " +
|
||||
"and When false, connects PowerFlex client on Host when host connects to storage pool & client connections configured 'storage.pool.connected.clients.limit' are within the limit and disconnects when host disconnects from storage pool & no volumes mapped to SDC.",
|
||||
Boolean.TRUE,
|
||||
ConfigKey.Scope.Zone);
|
||||
|
||||
/**
|
||||
* Checks SDC connections limit.
|
||||
* @param storagePoolId the storage pool id
|
||||
@ -30,18 +40,57 @@ public interface ScaleIOSDCManager {
|
||||
boolean areSDCConnectionsWithinLimit(Long storagePoolId);
|
||||
|
||||
/**
|
||||
* Prepares/starts the SDC on the host.
|
||||
* Returns connected SDC Id.
|
||||
* @param host the host
|
||||
* @param dataStore the datastore
|
||||
* @return SDC Id of the host
|
||||
*/
|
||||
String getConnectedSdc(Host host, DataStore dataStore);
|
||||
|
||||
/**
|
||||
* Prepares the SDC on the host (adds the MDM IPs to SDC, starts scini service if required).
|
||||
* @param host the host
|
||||
* @param dataStore the datastore
|
||||
* @return SDC Id of the host if SDC is successfully prepared-ed on the host
|
||||
*/
|
||||
String prepareSDC(Host host, DataStore dataStore);
|
||||
|
||||
/**
|
||||
* Stops the SDC on the host.
|
||||
* Unprepares the SDC on the host (removes the MDM IPs from SDC, restarts scini service).
|
||||
* @param host the host
|
||||
* @param dataStore the datastore
|
||||
* @return true if SDC stopped on the host
|
||||
* @return true if SDC is successfully unprepared-ed on the host
|
||||
*/
|
||||
boolean stopSDC(Host host, DataStore dataStore);
|
||||
boolean unprepareSDC(Host host, DataStore dataStore);
|
||||
|
||||
/**
|
||||
* Checks if the SDC can be unprepared on the host (don't remove MDM IPs from SDC if any volumes mapped to SDC).
|
||||
* @param host the host
|
||||
* @param dataStore the datastore
|
||||
* @return true if SDC can be unprepared on the host
|
||||
*/
|
||||
boolean canUnprepareSDC(Host host, DataStore dataStore);
|
||||
|
||||
/**
|
||||
* Returns the SDC Id of the host for the pool.
|
||||
* @param sdcGuid the SDC GUID
|
||||
* @param dataStore the datastore
|
||||
* @return SDC Id of the host for the pool
|
||||
*/
|
||||
String getHostSdcId(String sdcGuid, DataStore dataStore);
|
||||
|
||||
/**
|
||||
* Returns the connection status of host SDC of the pool.
|
||||
* @param sdcId the SDC id
|
||||
* @param dataStore the datastore
|
||||
* @return true if Host SDC is connected to the pool
|
||||
*/
|
||||
boolean isHostSdcConnected(String sdcId, DataStore dataStore, int waitTimeInSecs);
|
||||
|
||||
/**
|
||||
* Returns the comma-separated list of MDM IPs of the pool.
|
||||
* @param poolId the pool id
|
||||
* @return Comma-separated list of MDM IPs of the pool
|
||||
*/
|
||||
String getMdms(long poolId);
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package org.apache.cloudstack.storage.datastore.manager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -30,8 +31,10 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClientConnectionPool;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -58,15 +61,6 @@ import com.cloud.utils.exception.CloudRuntimeException;
|
||||
public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
private Logger logger = LogManager.getLogger(getClass());
|
||||
|
||||
static ConfigKey<Boolean> ConnectOnDemand = new ConfigKey<>("Storage",
|
||||
Boolean.class,
|
||||
"powerflex.connect.on.demand",
|
||||
Boolean.FALSE.toString(),
|
||||
"Connect PowerFlex client on Host when first Volume is mapped to SDC and disconnect when last Volume is unmapped from SDC," +
|
||||
" otherwise no action (that is connection remains in the same state whichever it is, connected or disconnected).",
|
||||
Boolean.TRUE,
|
||||
ConfigKey.Scope.Zone);
|
||||
|
||||
@Inject
|
||||
AgentManager agentManager;
|
||||
@Inject
|
||||
@ -91,6 +85,7 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
try {
|
||||
int connectedClientsLimit = StorageManager.STORAGE_POOL_CONNECTED_CLIENTS_LIMIT.valueIn(storagePoolId);
|
||||
if (connectedClientsLimit <= 0) {
|
||||
logger.debug(String.format("SDC connections limit (unlimited) on PowerFlex Storage with pool id: %d", storagePoolId));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -121,7 +116,11 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
return getConnectedSdc(host, dataStore);
|
||||
}
|
||||
|
||||
String systemId = storagePoolDetailsDao.findDetail(dataStore.getId(), ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID).getValue();
|
||||
String systemId = null;
|
||||
StoragePoolDetailVO systemIdDetail = storagePoolDetailsDao.findDetail(dataStore.getId(), ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID);
|
||||
if (systemIdDetail != null) {
|
||||
systemId = systemIdDetail.getValue();
|
||||
}
|
||||
if (systemId == null) {
|
||||
throw new CloudRuntimeException("Unable to prepare SDC, failed to get the system id for PowerFlex storage pool: " + dataStore.getName());
|
||||
}
|
||||
@ -168,7 +167,8 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
throw new CloudRuntimeException(errorMsg);
|
||||
}
|
||||
|
||||
sdcId = prepareSDCOnHost(host, dataStore, systemId);
|
||||
String mdms = getMdms(dataStore.getId());
|
||||
sdcId = prepareSDCOnHost(host, dataStore, systemId, mdms);
|
||||
StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(poolId, hostId);
|
||||
|
||||
if (StringUtils.isBlank(sdcId)) {
|
||||
@ -186,7 +186,7 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
}
|
||||
|
||||
int waitTimeInSecs = 15; // Wait for 15 secs (usual tests with SDC service start took 10-15 secs)
|
||||
if (hostSdcConnected(sdcId, dataStore, waitTimeInSecs)) {
|
||||
if (isHostSdcConnected(sdcId, dataStore, waitTimeInSecs)) {
|
||||
return sdcId;
|
||||
}
|
||||
return null;
|
||||
@ -202,10 +202,11 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
}
|
||||
}
|
||||
|
||||
private String prepareSDCOnHost(Host host, DataStore dataStore, String systemId) {
|
||||
private String prepareSDCOnHost(Host host, DataStore dataStore, String systemId, String mdms) {
|
||||
logger.debug("Preparing SDC on the host {}", host);
|
||||
Map<String,String> details = new HashMap<>();
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID, systemId);
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, mdms);
|
||||
PrepareStorageClientCommand cmd = new PrepareStorageClientCommand(((PrimaryDataStore) dataStore).getPoolType(), dataStore.getUuid(), details);
|
||||
int timeoutSeconds = 60;
|
||||
cmd.setWait(timeoutSeconds);
|
||||
@ -254,13 +255,17 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stopSDC(Host host, DataStore dataStore) {
|
||||
public boolean unprepareSDC(Host host, DataStore dataStore) {
|
||||
if (Boolean.FALSE.equals(ConnectOnDemand.valueIn(host.getDataCenterId()))) {
|
||||
logger.debug(String.format("On-demand connect/disconnect config %s disabled in the zone %d, no need to unprepare SDC", ConnectOnDemand.key(), host.getDataCenterId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
String systemId = storagePoolDetailsDao.findDetail(dataStore.getId(), ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID).getValue();
|
||||
String systemId = null;
|
||||
StoragePoolDetailVO systemIdDetail = storagePoolDetailsDao.findDetail(dataStore.getId(), ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID);
|
||||
if (systemIdDetail != null) {
|
||||
systemId = systemIdDetail.getValue();
|
||||
}
|
||||
if (systemId == null) {
|
||||
throw new CloudRuntimeException("Unable to unprepare SDC, failed to get the system id for PowerFlex storage pool: " + dataStore);
|
||||
}
|
||||
@ -284,10 +289,29 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
String sdcId = getConnectedSdc(host, dataStore);
|
||||
if (StringUtils.isBlank(sdcId)) {
|
||||
logger.debug("SDC not connected, no need to unprepare it");
|
||||
StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(dataStore.getId(), host.getId());
|
||||
if (storagePoolHost != null) {
|
||||
storagePoolHostDao.deleteStoragePoolHostDetails(host.getId(), dataStore.getId());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return unprepareSDCOnHost(host, dataStore);
|
||||
if (!canUnprepareSDC(host, dataStore)) {
|
||||
logger.debug("Cannot unprepare SDC, there might be other connected pools of same PowerFlex storage cluster," +
|
||||
"or some volumes mapped to the SDC that belongs to any of the storage pools of the PowerFlex storage cluster");
|
||||
return false;
|
||||
}
|
||||
|
||||
String mdms = getMdms(dataStore.getId());;
|
||||
boolean unprepareSDCStatus = unprepareSDCOnHost(host, dataStore, mdms);
|
||||
if (unprepareSDCStatus) {
|
||||
StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(dataStore.getId(), host.getId());
|
||||
if (storagePoolHost != null) {
|
||||
storagePoolHostDao.deleteStoragePoolHostDetails(host.getId(), dataStore.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return unprepareSDCStatus;
|
||||
} finally {
|
||||
if (lock != null) {
|
||||
lock.unlock();
|
||||
@ -296,9 +320,11 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean unprepareSDCOnHost(Host host, DataStore dataStore) {
|
||||
private boolean unprepareSDCOnHost(Host host, DataStore dataStore, String mdms) {
|
||||
logger.debug(String.format("Unpreparing SDC on the host %s (%s)", host.getId(), host.getName()));
|
||||
UnprepareStorageClientCommand cmd = new UnprepareStorageClientCommand(((PrimaryDataStore) dataStore).getPoolType(), dataStore.getUuid());
|
||||
Map<String,String> details = new HashMap<>();
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, mdms);
|
||||
UnprepareStorageClientCommand cmd = new UnprepareStorageClientCommand(((PrimaryDataStore) dataStore).getPoolType(), dataStore.getUuid(), details);
|
||||
int timeoutSeconds = 60;
|
||||
cmd.setWait(timeoutSeconds);
|
||||
|
||||
@ -317,7 +343,39 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getHostSdcId(String sdcGuid, DataStore dataStore ) {
|
||||
@Override
|
||||
public boolean canUnprepareSDC(Host host, DataStore dataStore) {
|
||||
if (host == null || dataStore == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
StoragePoolHostVO poolHostVO = storagePoolHostDao.findByPoolHost(dataStore.getId(), host.getId());
|
||||
if (poolHostVO == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String sdcId = poolHostVO.getLocalPath();
|
||||
if (StringUtils.isBlank(sdcId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<StoragePoolHostVO> poolHostVOsBySdc = storagePoolHostDao.findByLocalPath(sdcId);
|
||||
if (CollectionUtils.isNotEmpty(poolHostVOsBySdc) && poolHostVOsBySdc.size() > 1) {
|
||||
logger.debug(String.format("There are other connected pools with the same SDC of the host %s, shouldn't unprepare SDC", host));
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final ScaleIOGatewayClient client = getScaleIOClient(dataStore.getId());
|
||||
return client.listVolumesMappedToSdc(sdcId).isEmpty();
|
||||
} catch (Exception e) {
|
||||
logger.warn("Unable to check whether the SDC of the pool: " + dataStore.getId() + " can be unprepared on the host: " + host.getId() + ", due to " + e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHostSdcId(String sdcGuid, DataStore dataStore) {
|
||||
try {
|
||||
logger.debug("Try to get host SDC Id for pool: {}, with SDC guid {}", dataStore, sdcGuid);
|
||||
ScaleIOGatewayClient client = getScaleIOClient(dataStore.getId());
|
||||
@ -328,7 +386,8 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
}
|
||||
}
|
||||
|
||||
private String getConnectedSdc(Host host, DataStore dataStore) {
|
||||
@Override
|
||||
public String getConnectedSdc(Host host, DataStore dataStore) {
|
||||
long poolId = dataStore.getId();
|
||||
long hostId = host.getId();
|
||||
|
||||
@ -351,7 +410,8 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean hostSdcConnected(String sdcId, DataStore dataStore, int waitTimeInSecs) {
|
||||
@Override
|
||||
public boolean isHostSdcConnected(String sdcId, DataStore dataStore, int waitTimeInSecs) {
|
||||
long poolId = dataStore.getId();
|
||||
logger.debug(String.format("Waiting (for %d secs) for the SDC %s of the pool %s to connect",
|
||||
waitTimeInSecs, sdcId, dataStore));
|
||||
@ -369,6 +429,32 @@ public class ScaleIOSDCManagerImpl implements ScaleIOSDCManager, Configurable {
|
||||
return isHostSdcConnected(sdcId, poolId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMdms(long poolId) {
|
||||
String mdms = null;
|
||||
StoragePoolDetailVO mdmsDetail = storagePoolDetailsDao.findDetail(poolId, ScaleIOGatewayClient.STORAGE_POOL_MDMS);
|
||||
if (mdmsDetail != null) {
|
||||
mdms = mdmsDetail.getValue();
|
||||
}
|
||||
if (StringUtils.isNotBlank(mdms)) {
|
||||
return mdms;
|
||||
}
|
||||
|
||||
try {
|
||||
final ScaleIOGatewayClient client = getScaleIOClient(poolId);
|
||||
List<String> mdmAddresses = client.getMdmAddresses();
|
||||
if (CollectionUtils.isNotEmpty(mdmAddresses)) {
|
||||
mdms = StringUtils.join(mdmAddresses, ",");
|
||||
StoragePoolDetailVO storagePoolDetailVO = new StoragePoolDetailVO(poolId, ScaleIOGatewayClient.STORAGE_POOL_MDMS, mdms, false);
|
||||
storagePoolDetailsDao.persist(storagePoolDetailVO);
|
||||
}
|
||||
return mdms;
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to get MDMs", e);
|
||||
throw new CloudRuntimeException("Failed to fetch PowerFlex MDM details");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isHostSdcConnected(String sdcId, long poolId) {
|
||||
try {
|
||||
final ScaleIOGatewayClient client = getScaleIOClient(poolId);
|
||||
|
||||
@ -18,21 +18,20 @@
|
||||
*/
|
||||
package org.apache.cloudstack.storage.datastore.provider;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient;
|
||||
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClientConnectionPool;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.storage.datastore.manager.ScaleIOSDCManager;
|
||||
import org.apache.cloudstack.storage.datastore.manager.ScaleIOSDCManagerImpl;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -49,6 +48,7 @@ import com.cloud.storage.DataStoreRole;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.StoragePoolHostVO;
|
||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||
import com.cloud.utils.component.ComponentContext;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
public class ScaleIOHostListener implements HypervisorHostListener {
|
||||
@ -61,6 +61,7 @@ public class ScaleIOHostListener implements HypervisorHostListener {
|
||||
@Inject private StoragePoolHostDao _storagePoolHostDao;
|
||||
@Inject private PrimaryDataStoreDao _primaryDataStoreDao;
|
||||
@Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
|
||||
private ScaleIOSDCManager _sdcManager = new ScaleIOSDCManagerImpl();
|
||||
|
||||
@Override
|
||||
public boolean hostAdded(long hostId) {
|
||||
@ -75,9 +76,10 @@ public class ScaleIOHostListener implements HypervisorHostListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary);
|
||||
DataStore dataStore = _dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary);
|
||||
StoragePool storagePool = (StoragePool) dataStore;
|
||||
StoragePoolHostVO storagePoolHost = _storagePoolHostDao.findByPoolHost(poolId, hostId);
|
||||
String sdcId = getSdcIdOfHost(host, storagePool);
|
||||
String sdcId = getSdcIdOfHost(host, dataStore);
|
||||
if (StringUtils.isBlank(sdcId)) {
|
||||
if (storagePoolHost != null) {
|
||||
_storagePoolHostDao.deleteStoragePoolHostDetails(hostId, poolId);
|
||||
@ -95,15 +97,26 @@ public class ScaleIOHostListener implements HypervisorHostListener {
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getSdcIdOfHost(HostVO host, StoragePool storagePool) {
|
||||
private String getSdcIdOfHost(HostVO host, DataStore dataStore) {
|
||||
StoragePool storagePool = (StoragePool) dataStore;
|
||||
long hostId = host.getId();
|
||||
long poolId = storagePool.getId();
|
||||
String systemId = _storagePoolDetailsDao.findDetail(poolId, ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID).getValue();
|
||||
String systemId = null;
|
||||
StoragePoolDetailVO systemIdDetail = _storagePoolDetailsDao.findDetail(poolId, ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID);
|
||||
if (systemIdDetail != null) {
|
||||
systemId = systemIdDetail.getValue();
|
||||
}
|
||||
if (systemId == null) {
|
||||
throw new CloudRuntimeException("Failed to get the system id for PowerFlex storage pool " + storagePool.getName());
|
||||
}
|
||||
Map<String,String> details = new HashMap<>();
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID, systemId);
|
||||
_sdcManager = ComponentContext.inject(_sdcManager);
|
||||
if (_sdcManager.areSDCConnectionsWithinLimit(poolId)) {
|
||||
details.put(ScaleIOSDCManager.ConnectOnDemand.key(), String.valueOf(ScaleIOSDCManager.ConnectOnDemand.valueIn(host.getDataCenterId())));
|
||||
String mdms = _sdcManager.getMdms(poolId);
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, mdms);
|
||||
}
|
||||
|
||||
ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool, storagePool.getPath(), details);
|
||||
ModifyStoragePoolAnswer answer = sendModifyStoragePoolCommand(cmd, storagePool, host);
|
||||
@ -111,7 +124,7 @@ public class ScaleIOHostListener implements HypervisorHostListener {
|
||||
if (MapUtils.isEmpty(poolDetails)) {
|
||||
String msg = String.format("PowerFlex storage SDC details not found on the host: %s, (re)install SDC and restart agent", host);
|
||||
logger.warn(msg);
|
||||
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "SDC not found on host: " + host.getUuid(), msg);
|
||||
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "SDC details not found on host: " + host.getUuid(), msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -120,7 +133,7 @@ public class ScaleIOHostListener implements HypervisorHostListener {
|
||||
sdcId = poolDetails.get(ScaleIOGatewayClient.SDC_ID);
|
||||
} else if (poolDetails.containsKey(ScaleIOGatewayClient.SDC_GUID)) {
|
||||
String sdcGuid = poolDetails.get(ScaleIOGatewayClient.SDC_GUID);
|
||||
sdcId = getHostSdcId(sdcGuid, poolId);
|
||||
sdcId = _sdcManager.getHostSdcId(sdcGuid, dataStore);
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(sdcId)) {
|
||||
@ -130,47 +143,85 @@ public class ScaleIOHostListener implements HypervisorHostListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sdcId;
|
||||
}
|
||||
|
||||
private String getHostSdcId(String sdcGuid, long poolId) {
|
||||
StoragePoolVO storagePool = _primaryDataStoreDao.findById(poolId);
|
||||
try {
|
||||
logger.debug(String.format("Try to get host SDC Id for pool: %s, with SDC guid %s", storagePool, sdcGuid));
|
||||
ScaleIOGatewayClient client = ScaleIOGatewayClientConnectionPool.getInstance().getClient(storagePool, _storagePoolDetailsDao);
|
||||
return client.getSdcIdByGuid(sdcGuid);
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException | URISyntaxException e) {
|
||||
logger.error(String.format("Failed to get host SDC Id for pool: %s", storagePool), e);
|
||||
throw new CloudRuntimeException(String.format(
|
||||
"Failed to establish connection with PowerFlex Gateway to get host SDC Id for pool: %s",
|
||||
storagePool));
|
||||
if (details.containsKey(ScaleIOSDCManager.ConnectOnDemand.key())) {
|
||||
String connectOnDemand = details.get(ScaleIOSDCManager.ConnectOnDemand.key());
|
||||
if (connectOnDemand != null && !Boolean.parseBoolean(connectOnDemand) && !_sdcManager.isHostSdcConnected(sdcId, dataStore, 15)) {
|
||||
logger.warn("SDC not connected on the host: " + hostId);
|
||||
String msg = "SDC not connected on the host: " + hostId + ", reconnect the SDC to MDM and restart agent";
|
||||
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "SDC not connected on host: " + host.getUuid(), msg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return sdcId;
|
||||
}
|
||||
|
||||
private ModifyStoragePoolAnswer sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, HostVO host) {
|
||||
Answer answer = _agentMgr.easySend(host.getId(), cmd);
|
||||
|
||||
if (answer == null) {
|
||||
throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command (" + storagePool.getName() + ")");
|
||||
throw new CloudRuntimeException(String.format("Unable to get an answer to the modify storage pool command (add: %s) for PowerFlex storage pool %s, sent to host %s",
|
||||
cmd.getAdd(), getStoragePoolDetails(storagePool), host));
|
||||
}
|
||||
|
||||
if (!answer.getResult()) {
|
||||
String msg = "Unable to attach PowerFlex storage pool " + storagePool + " to host " + host.getUuid();
|
||||
if (cmd.getAdd()) {
|
||||
String msg = "Unable to attach PowerFlex storage pool " + getStoragePoolDetails(storagePool) + " to the host " + host;
|
||||
|
||||
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg);
|
||||
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg);
|
||||
|
||||
throw new CloudRuntimeException("Unable to establish a connection from agent to PowerFlex storage pool " + storagePool + " due to " + answer.getDetails() +
|
||||
" (" + storagePool.getId() + ")");
|
||||
throw new CloudRuntimeException("Unable to connect to PowerFlex storage pool " + getStoragePoolDetails(storagePool) + " due to " + answer.getDetails());
|
||||
} else {
|
||||
String msg = "Unable to detach PowerFlex storage pool " + getStoragePoolDetails(storagePool) + " from the host " + host;
|
||||
|
||||
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg);
|
||||
}
|
||||
}
|
||||
|
||||
assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer expected ; PowerFlex Storage Pool = " + storagePool.getId() + " Host = " + host;
|
||||
assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer expected ; PowerFlex Storage Pool = " + storagePool + " Host = " + host;
|
||||
|
||||
return (ModifyStoragePoolAnswer) answer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hostDisconnected(long hostId, long poolId) {
|
||||
// SDC ID is getting updated upon host connect, no need to delete the storage_pool_host_ref entry
|
||||
HostVO host = _hostDao.findById(hostId);
|
||||
if (host == null) {
|
||||
logger.error("Failed to disconnect host by HostListener as host was not found with id : " + hostId);
|
||||
return false;
|
||||
}
|
||||
|
||||
DataStore dataStore = _dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary);
|
||||
StoragePool storagePool = (StoragePool) dataStore;
|
||||
String systemId = null;
|
||||
StoragePoolDetailVO systemIdDetail = _storagePoolDetailsDao.findDetail(poolId, ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID);
|
||||
if (systemIdDetail != null) {
|
||||
systemId = systemIdDetail.getValue();
|
||||
}
|
||||
if (systemId == null) {
|
||||
throw new CloudRuntimeException("Failed to get the system id for PowerFlex storage pool " + storagePool.getName());
|
||||
}
|
||||
Map<String,String> details = new HashMap<>();
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID, systemId);
|
||||
_sdcManager = ComponentContext.inject(_sdcManager);
|
||||
if (_sdcManager.canUnprepareSDC(host, dataStore)) {
|
||||
details.put(ScaleIOSDCManager.ConnectOnDemand.key(), String.valueOf(ScaleIOSDCManager.ConnectOnDemand.valueIn(host.getDataCenterId())));
|
||||
String mdms = _sdcManager.getMdms(poolId);
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_MDMS, mdms);
|
||||
}
|
||||
|
||||
ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(false, storagePool, storagePool.getPath(), details);
|
||||
ModifyStoragePoolAnswer answer = sendModifyStoragePoolCommand(cmd, storagePool, host);
|
||||
if (!answer.getResult()) {
|
||||
logger.error("Failed to disconnect storage pool: " + storagePool + " and host: " + hostId);
|
||||
return false;
|
||||
}
|
||||
|
||||
StoragePoolHostVO storagePoolHost = _storagePoolHostDao.findByPoolHost(poolId, hostId);
|
||||
if (storagePoolHost != null) {
|
||||
_storagePoolHostDao.deleteStoragePoolHostDetails(hostId, poolId);
|
||||
}
|
||||
logger.info("Connection removed between storage pool: " + storagePool + " and host: " + hostId);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -188,4 +239,12 @@ public class ScaleIOHostListener implements HypervisorHostListener {
|
||||
public boolean hostEnabled(long hostId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getStoragePoolDetails(StoragePool storagePool) {
|
||||
String poolDetails = "";
|
||||
if (storagePool != null) {
|
||||
poolDetails = String.format("%s (id: %d, uuid: %s)", storagePool.getName(), storagePool.getId(), storagePool.getUuid());
|
||||
}
|
||||
return poolDetails;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,9 @@
|
||||
|
||||
package org.apache.cloudstack.storage.datastore.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@ -85,6 +88,54 @@ public class ScaleIOUtil {
|
||||
*/
|
||||
private static final String QUERY_MDMS_CMD = "drv_cfg --query_mdms";
|
||||
|
||||
private static final String ADD_MDMS_CMD = "drv_cfg --add_mdm";
|
||||
private static final String DRV_CFG_FILE = "/etc/emc/scaleio/drv_cfg.txt";
|
||||
|
||||
public static void addMdms(List<String> mdmAddresses) {
|
||||
if (CollectionUtils.isEmpty(mdmAddresses)) {
|
||||
return;
|
||||
}
|
||||
// Sample Cmd - /opt/emc/scaleio/sdc/bin/drv_cfg --add_mdm --ip x.x.x.x,x.x.x.x --file /etc/emc/scaleio/drv_cfg.txt
|
||||
String addMdmsCmd = ScaleIOUtil.SDC_HOME_PATH + "/bin/" + ScaleIOUtil.ADD_MDMS_CMD;
|
||||
addMdmsCmd += " --ip " + String.join(",", mdmAddresses);
|
||||
addMdmsCmd += " --file " + DRV_CFG_FILE;
|
||||
String result = Script.runSimpleBashScript(addMdmsCmd);
|
||||
if (result == null) {
|
||||
LOGGER.warn("Failed to add mdms");
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeMdms(List<String> mdmAddresses) {
|
||||
if (CollectionUtils.isEmpty(mdmAddresses)) {
|
||||
return;
|
||||
}
|
||||
// (i) Remove MDMs from config file (ii) Restart scini
|
||||
// Sample Cmd - sed -i '/x.x.x.x\,/d' /etc/emc/scaleio/drv_cfg.txt
|
||||
boolean restartSDC = false;
|
||||
String removeMdmsCmdFormat = "sed -i '/%s\\,/d' %s";
|
||||
for (String mdmAddress : mdmAddresses) {
|
||||
if (mdmAdded(mdmAddress)) {
|
||||
restartSDC = true;
|
||||
}
|
||||
String removeMdmsCmd = String.format(removeMdmsCmdFormat, mdmAddress, DRV_CFG_FILE);
|
||||
Script.runSimpleBashScript(removeMdmsCmd);
|
||||
}
|
||||
if (restartSDC) {
|
||||
restartSDCService();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean mdmAdded(String mdmAddress) {
|
||||
//query_mdms outputs "MDM-ID <System/MDM-Id> SDC ID <SDC-Id> INSTALLATION ID <Installation-Id> IPs [0]-x.x.x.x [1]-x.x.x.x" for a MDM with ID: <MDM-Id>
|
||||
String queryMdmsCmd = ScaleIOUtil.SDC_HOME_PATH + "/bin/" + ScaleIOUtil.QUERY_MDMS_CMD;
|
||||
queryMdmsCmd += "|grep " + mdmAddress;
|
||||
String result = Script.runSimpleBashScript(queryMdmsCmd);
|
||||
if (StringUtils.isNotBlank(result) && result.contains(mdmAddress)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getSdcHomePath() {
|
||||
String sdcHomePath = DEFAULT_SDC_HOME_PATH;
|
||||
String sdcHomePropertyCmdFormat = "sed -n '/%s/p' '%s' 2>/dev/null | sed 's/%s=//g' 2>/dev/null";
|
||||
|
||||
@ -22,6 +22,7 @@ package org.apache.cloudstack.storage.datastore.lifecycle;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@ -163,7 +164,7 @@ public class ScaleIOPrimaryDataStoreLifeCycleTest {
|
||||
@Test
|
||||
public void testMaintain() {
|
||||
final DataStore store = mock(DataStore.class);
|
||||
when(storagePoolAutomation.maintain(any(DataStore.class))).thenReturn(true);
|
||||
when(storagePoolAutomation.maintain(any(DataStore.class), anyMap())).thenReturn(true);
|
||||
when(dataStoreHelper.maintain(any(DataStore.class))).thenReturn(true);
|
||||
final boolean result = scaleIOPrimaryDataStoreLifeCycleTest.maintain(store);
|
||||
assertThat(result).isTrue();
|
||||
@ -173,7 +174,7 @@ public class ScaleIOPrimaryDataStoreLifeCycleTest {
|
||||
public void testCancelMaintain() {
|
||||
final DataStore store = mock(DataStore.class);
|
||||
when(dataStoreHelper.cancelMaintain(any(DataStore.class))).thenReturn(true);
|
||||
when(storagePoolAutomation.cancelMaintain(any(DataStore.class))).thenReturn(true);
|
||||
when(storagePoolAutomation.cancelMaintain(any(DataStore.class), anyMap())).thenReturn(true);
|
||||
final boolean result = scaleIOPrimaryDataStoreLifeCycleTest.cancelMaintain(store);
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
@ -2923,6 +2923,17 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
||||
return storeDriver instanceof PrimaryDataStoreDriver && ((PrimaryDataStoreDriver)storeDriver).canHostPrepareStoragePoolAccess(host, pool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDisconnectHostFromStoragePool(Host host, StoragePool pool) {
|
||||
if (pool == null || !pool.isManaged()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName());
|
||||
DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
|
||||
return storeDriver instanceof PrimaryDataStoreDriver && ((PrimaryDataStoreDriver)storeDriver).canDisconnectHostFromStoragePool(host, pool);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public Host getHost(long hostId) {
|
||||
|
||||
@ -18,10 +18,16 @@
|
||||
*/
|
||||
package com.cloud.storage;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
|
||||
public interface StoragePoolAutomation {
|
||||
public boolean maintain(DataStore store);
|
||||
boolean maintain(DataStore store);
|
||||
|
||||
public boolean cancelMaintain(DataStore store);
|
||||
boolean maintain(DataStore store, Map<String,String> details);
|
||||
|
||||
boolean cancelMaintain(DataStore store);
|
||||
|
||||
boolean cancelMaintain(DataStore store, Map<String,String> details);
|
||||
}
|
||||
|
||||
@ -31,14 +31,15 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManag
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.ModifyStoragePoolCommand;
|
||||
import com.cloud.agent.api.ModifyStoragePoolAnswer;
|
||||
import com.cloud.agent.api.ModifyStoragePoolCommand;
|
||||
import com.cloud.alert.AlertManager;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.Status;
|
||||
@ -112,6 +113,11 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation {
|
||||
|
||||
@Override
|
||||
public boolean maintain(DataStore store) {
|
||||
return maintain(store, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean maintain(DataStore store, Map<String,String> details) {
|
||||
Long userId = CallContext.current().getCallingUserId();
|
||||
User user = _userDao.findById(userId);
|
||||
Account account = CallContext.current().getCallingAccount();
|
||||
@ -161,6 +167,9 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation {
|
||||
// remove heartbeat
|
||||
for (HostVO host : hosts) {
|
||||
ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(false, storagePool);
|
||||
if (MapUtils.isNotEmpty(details) && storageManager.canDisconnectHostFromStoragePool(host, storagePool)) {
|
||||
cmd.setDetails(details);
|
||||
}
|
||||
final Answer answer = agentMgr.easySend(host.getId(), cmd);
|
||||
if (answer == null || !answer.getResult()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
@ -299,6 +308,11 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation {
|
||||
|
||||
@Override
|
||||
public boolean cancelMaintain(DataStore store) {
|
||||
return cancelMaintain(store, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancelMaintain(DataStore store, Map<String,String> details) {
|
||||
// Change the storage state back to up
|
||||
Long userId = CallContext.current().getCallingUserId();
|
||||
User user = _userDao.findById(userId);
|
||||
@ -327,7 +341,10 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation {
|
||||
Pair<Map<String, String>, Boolean> nfsMountOpts = storageManager.getStoragePoolNFSMountOpts(pool, null);
|
||||
// add heartbeat
|
||||
for (HostVO host : hosts) {
|
||||
ModifyStoragePoolCommand msPoolCmd = new ModifyStoragePoolCommand(true, pool, nfsMountOpts.first());
|
||||
ModifyStoragePoolCommand msPoolCmd = new ModifyStoragePoolCommand(true, pool);
|
||||
if (MapUtils.isNotEmpty(details)) {
|
||||
msPoolCmd.setDetails(details);
|
||||
}
|
||||
final Answer answer = agentMgr.easySend(host.getId(), msPoolCmd);
|
||||
if (answer == null || !answer.getResult()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user