CLOUDSTACK-2029 zone wide primary storage support for cloudstack over vmware deployments

Added hypervisor type to CreateStoragePoolCmd & Storage pool responses.
DatastoreLifeCycle would consider hypervisor type while attaching datastore to zone.
ZoneWideStoragePoolAllocator would filter zone wide primary storage pools by hypervisor type along with tags in disk profile.
hypervisor type is mandatory parameter if scope is specified as ZONE while creating primary storage pool.
As of now KVM, VMware are allowed to use ZoneWideStoragePoolAllocator.

Signed-off-by: Sateesh Chodapuneedi <sateesh@apache.org>
This commit is contained in:
Sateesh Chodapuneedi 2013-05-29 01:20:05 +05:30
parent e7d468e221
commit 7998413f48
11 changed files with 138 additions and 82 deletions

View File

@ -71,15 +71,19 @@ public class CreateStoragePoolCmd extends BaseCmd {
@Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class,
required=true, description="the Zone ID for the storage pool")
private Long zoneId;
@Parameter(name=ApiConstants.PROVIDER, type=CommandType.STRING,
required=false, description="the storage provider name")
private String storageProviderName;
@Parameter(name=ApiConstants.SCOPE, type=CommandType.STRING,
required=false, description="the scope of the storage: cluster or zone")
private String scope;
@Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, required=false,
description="hypervisor type of the hosts in zone that will be attached to this storage pool. KVM, VMware supported as of now.")
private String hypervisor;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -111,18 +115,18 @@ public class CreateStoragePoolCmd extends BaseCmd {
public Long getZoneId() {
return zoneId;
}
public String getStorageProviderName() {
return this.storageProviderName;
}
public String getScope() {
return this.scope;
return this.scope;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
public String getHypervisor() {
return hypervisor;
}
@Override
public String getCommandName() {

View File

@ -83,6 +83,9 @@ public class StoragePoolForMigrationResponse extends BaseResponse {
@SerializedName(ApiConstants.SCOPE) @Param(description="the scope of the storage pool")
private String scope;
@SerializedName(ApiConstants.HYPERVISOR) @Param(description="the hypervisor type of the storage pool")
private String hypervisor;
@SerializedName("suitableformigration") @Param(description="true if this pool is suitable to migrate a volume," +
" false otherwise")
private Boolean suitableForMigration;
@ -101,6 +104,14 @@ public class StoragePoolForMigrationResponse extends BaseResponse {
this.scope = scope;
}
public String getHypervisor() {
return hypervisor;
}
public void setHypervisor(String hypervisor) {
this.hypervisor = hypervisor;
}
@Override
public String getObjectId() {
return this.getId();

View File

@ -40,13 +40,13 @@ public class StoragePoolResponse extends BaseResponse {
@SerializedName(ApiConstants.ZONE_TYPE) @Param(description = "network type of the availability zone")
private String zoneType;
@SerializedName("podid") @Param(description="the Pod ID of the storage pool")
private String podId;
@SerializedName("podname") @Param(description="the Pod name of the storage pool")
private String podName;
@SerializedName("name") @Param(description="the name of the storage pool")
private String name;
@ -82,10 +82,13 @@ public class StoragePoolResponse extends BaseResponse {
@SerializedName(ApiConstants.STATE) @Param(description="the state of the storage pool")
private StoragePoolStatus state;
@SerializedName(ApiConstants.SCOPE) @Param(description="the scope of the storage pool")
private String scope;
@SerializedName(ApiConstants.HYPERVISOR) @Param(description="the hypervisor type of the storage pool")
private String hypervisor;
/**
* @return the scope
*/
@ -100,6 +103,14 @@ public class StoragePoolResponse extends BaseResponse {
this.scope = scope;
}
public String getHypervisor() {
return hypervisor;
}
public void setHypervisor(String hypervisor) {
this.hypervisor = hypervisor;
}
@Override
public String getObjectId() {
return this.getId();
@ -132,11 +143,11 @@ public class StoragePoolResponse extends BaseResponse {
public String getZoneType() {
return zoneType;
}
public void setZoneType(String zoneType) {
this.zoneType = zoneType;
}
public String getPodId() {
return podId;
}

View File

@ -21,6 +21,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
import java.util.Map;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
public interface DataStoreLifeCycle {
@ -28,8 +29,8 @@ public interface DataStoreLifeCycle {
public boolean attachCluster(DataStore store, ClusterScope scope);
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo);
boolean attachZone(DataStore dataStore, ZoneScope scope);
boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType);
public boolean dettach();
public boolean unmanaged();

View File

@ -30,6 +30,7 @@ import org.apache.cloudstack.storage.image.db.ImageDataStoreDao;
import org.apache.cloudstack.storage.image.db.ImageDataStoreVO;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle {
@Inject
@ -65,7 +66,7 @@ public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle {
@Override
public boolean attachZone(DataStore dataStore, ZoneScope scope) {
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisor) {
// TODO Auto-generated method stub
return false;
}

View File

@ -38,34 +38,36 @@ import com.cloud.vm.VirtualMachineProfile;
@Component
public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator {
private static final Logger s_logger = Logger.getLogger(ZoneWideStoragePoolAllocator.class);
@Inject PrimaryDataStoreDao _storagePoolDao;
@Inject DataStoreManager dataStoreMgr;
private static final Logger s_logger = Logger.getLogger(ZoneWideStoragePoolAllocator.class);
@Inject PrimaryDataStoreDao _storagePoolDao;
@Inject DataStoreManager dataStoreMgr;
@Override
protected boolean filter(ExcludeList avoid, StoragePool pool, DiskProfile dskCh,
DeploymentPlan plan) {
@Override
protected boolean filter(ExcludeList avoid, StoragePool pool, DiskProfile dskCh,
DeploymentPlan plan) {
Volume volume = _volumeDao.findById(dskCh.getVolumeId());
List<Volume> requestVolumes = new ArrayList<Volume>();
requestVolumes.add(volume);
return storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool);
}
}
@Override
protected List<StoragePool> select(DiskProfile dskCh,
VirtualMachineProfile<? extends VirtualMachine> vmProfile,
DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
s_logger.debug("ZoneWideStoragePoolAllocator to find storage pool");
List<StoragePool> suitablePools = new ArrayList<StoragePool>();
HypervisorType hypervisor = dskCh.getHypervisorType();
if (hypervisor != null) {
if (hypervisor != HypervisorType.KVM) {
s_logger.debug("Only kvm supports zone wide storage");
return suitablePools;
}
}
@Override
protected List<StoragePool> select(DiskProfile dskCh,
VirtualMachineProfile<? extends VirtualMachine> vmProfile,
DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
s_logger.debug("ZoneWideStoragePoolAllocator to find storage pool");
List<StoragePool> suitablePools = new ArrayList<StoragePool>();
HypervisorType hypervisor = dskCh.getHypervisorType();
if (hypervisor != null) {
if (hypervisor != HypervisorType.KVM && hypervisor != HypervisorType.VMware) {
s_logger.debug("Only kvm, VMware hypervisors are enabled to support zone wide storage");
return suitablePools;
}
}
List<StoragePoolVO> storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags());
List<StoragePoolVO> storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags());
List<StoragePoolVO> storagePoolsByHypervisor = _storagePoolDao.findZoneWideStoragePoolsByHypervisor(plan.getDataCenterId(), dskCh.getHypervisorType());
storagePools.retainAll(storagePoolsByHypervisor);
// add remaining pools in zone, that did not match tags, to avoid set
List<StoragePoolVO> allPools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), null);
@ -74,17 +76,17 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator {
avoid.addPool(pool.getId());
}
for (StoragePoolVO storage : storagePools) {
if (suitablePools.size() == returnUpTo) {
break;
}
StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(storage.getId());
if (filter(avoid, pol, dskCh, plan)) {
suitablePools.add(pol);
for (StoragePoolVO storage : storagePools) {
if (suitablePools.size() == returnUpTo) {
break;
}
StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(storage.getId());
if (filter(avoid, pol, dskCh, plan)) {
suitablePools.add(pol);
} else {
avoid.addPool(pol.getId());
}
}
return suitablePools;
}
}
return suitablePools;
}
}

View File

@ -29,25 +29,20 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole;
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType;
import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.DeleteStoragePoolCommand;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.alert.AlertManager;
import com.cloud.capacity.Capacity;
import com.cloud.capacity.CapacityVO;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.StoragePoolStatus;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
@ -70,7 +65,7 @@ public class PrimaryDataStoreHelper {
if (dataStoreVO != null) {
throw new CloudRuntimeException("duplicate uuid: " + params.getUuid());
}
dataStoreVO = new StoragePoolVO();
dataStoreVO.setStorageProviderName(params.getProviderName());
dataStoreVO.setHostAddress(params.getHost());
@ -84,7 +79,7 @@ public class PrimaryDataStoreHelper {
dataStoreVO.setClusterId(params.getClusterId());
dataStoreVO.setStatus(StoragePoolStatus.Initialized);
dataStoreVO.setUserInfo(params.getUserInfo());
Map<String, String> details = params.getDetails();
String tags = params.getTags();
if (tags != null) {
@ -98,19 +93,19 @@ public class PrimaryDataStoreHelper {
details.put(tag, "true");
}
}
dataStoreVO = dataStoreDao.persist(dataStoreVO, details);
return dataStoreMgr.getDataStore(dataStoreVO.getId(), DataStoreRole.Primary);
}
public DataStore attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
StoragePoolHostVO poolHost = storagePoolHostDao.findByPoolHost(store.getId(), scope.getScopeId());
if (poolHost == null) {
poolHost = new StoragePoolHostVO(store.getId(), scope.getScopeId(), existingInfo.getLocalPath());
storagePoolHostDao.persist(poolHost);
}
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
pool.setScope(scope.getScopeType());
pool.setAvailableBytes(existingInfo.getAvailableBytes());
@ -120,18 +115,18 @@ public class PrimaryDataStoreHelper {
this.storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getCapacityBytes() - pool.getAvailableBytes());
return dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary);
}
public DataStore attachCluster(DataStore store) {
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
storageMgr.createCapacityEntry(pool.getId());
pool.setScope(ScopeType.CLUSTER);
pool.setStatus(StoragePoolStatus.Up);
this.dataStoreDao.update(pool.getId(), pool);
return dataStoreMgr.getDataStore(store.getId(), DataStoreRole.Primary);
}
public DataStore attachZone(DataStore store) {
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
pool.setScope(ScopeType.ZONE);
@ -139,21 +134,30 @@ public class PrimaryDataStoreHelper {
this.dataStoreDao.update(pool.getId(), pool);
return dataStoreMgr.getDataStore(store.getId(), DataStoreRole.Primary);
}
public DataStore attachZone(DataStore store, HypervisorType hypervisor) {
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
pool.setScope(ScopeType.ZONE);
pool.setHypervisor(hypervisor);
pool.setStatus(StoragePoolStatus.Up);
this.dataStoreDao.update(pool.getId(), pool);
return dataStoreMgr.getDataStore(store.getId(), DataStoreRole.Primary);
}
public boolean maintain(DataStore store) {
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
pool.setStatus(StoragePoolStatus.Maintenance);
this.dataStoreDao.update(pool.getId(), pool);
return true;
}
public boolean cancelMaintain(DataStore store) {
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
pool.setStatus(StoragePoolStatus.Up);
dataStoreDao.update(store.getId(), pool);
return true;
}
protected boolean deletePoolStats(Long poolId) {
CapacityVO capacity1 = _capacityDao.findByHostIdType(poolId,
@ -167,10 +171,10 @@ public class PrimaryDataStoreHelper {
if (capacity2 != null) {
_capacityDao.remove(capacity2.getId());
}
return true;
}
public boolean deletePrimaryDataStore(DataStore store) {
List<StoragePoolHostVO> hostPoolRecords = this.storagePoolHostDao
.listByPoolId(store.getId());

View File

@ -114,7 +114,7 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif
}
@Override
public boolean attachZone(DataStore dataStore, ZoneScope scope) {
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
// TODO Auto-generated method stub
return false;
}

View File

@ -441,18 +441,18 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements
}
@Override
public boolean attachZone(DataStore dataStore, ZoneScope scope) {
List<HostVO> hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.KVM, scope.getScopeId());
for (HostVO host : hosts) {
try {
this.storageMgr.connectHostToSharedPool(host.getId(),
dataStore.getId());
} catch (Exception e) {
s_logger.warn("Unable to establish a connection between " + host
+ " and " + dataStore, e);
}
}
this.dataStoreHelper.attachZone(dataStore);
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
List<HostVO> hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(hypervisorType, scope.getScopeId());
for (HostVO host : hosts) {
try {
this.storageMgr.connectHostToSharedPool(host.getId(),
dataStore.getId());
} catch (Exception e) {
s_logger.warn("Unable to establish a connection between " + host
+ " and " + dataStore, e);
}
}
this.dataStoreHelper.attachZone(dataStore, hypervisorType);
return true;
}

View File

@ -775,6 +775,25 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
"zone id can't be null, if scope is zone");
}
String hypervisor = cmd.getHypervisor();
HypervisorType hypervisorType;
if (hypervisor != null) {
try {
hypervisorType = HypervisorType.getType(hypervisor);
} catch (Exception e) {
throw new InvalidParameterValueException("invalid hypervisor type" + hypervisor);
}
} else {
throw new InvalidParameterValueException(
"Missing parameter hypervisor. Hypervisor type is required to create zone wide primary storage.");
}
if (scopeType == ScopeType.ZONE &&
(hypervisorType != HypervisorType.KVM && hypervisorType != HypervisorType.VMware)) {
throw new InvalidParameterValueException(
"zone wide storage pool is not suported for hypervisor type " + hypervisor);
}
Map ds = cmd.getDetails();
Map<String, String> details = new HashMap<String, String>();
if (ds != null) {
@ -826,7 +845,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
lifeCycle.attachCluster(store, clusterScope);
} else if (scopeType == ScopeType.ZONE) {
ZoneScope zoneScope = new ZoneScope(zoneId);
lifeCycle.attachZone(store, zoneScope);
lifeCycle.attachZone(store, zoneScope, hypervisorType);
}
} catch (Exception e) {
s_logger.debug("Failed to add data store", e);

View File

@ -77,7 +77,10 @@ public class StoragePoolMonitor implements Listener {
if (scCmd.getHypervisorType() == HypervisorType.XenServer || scCmd.getHypervisorType() == HypervisorType.KVM ||
scCmd.getHypervisorType() == HypervisorType.VMware || scCmd.getHypervisorType() == HypervisorType.Simulator || scCmd.getHypervisorType() == HypervisorType.Ovm) {
List<StoragePoolVO> pools = _poolDao.listBy(host.getDataCenterId(), host.getPodId(), host.getClusterId(), ScopeType.CLUSTER);
pools.addAll(_poolDao.findZoneWideStoragePoolsByTags(host.getDataCenterId(), null));
List<StoragePoolVO> zoneStoragePoolsByTags = _poolDao.findZoneWideStoragePoolsByTags(host.getDataCenterId(), null);
List<StoragePoolVO> zoneStoragePoolsByHypervisor = _poolDao.findZoneWideStoragePoolsByHypervisor(host.getDataCenterId(), scCmd.getHypervisorType());
zoneStoragePoolsByTags.retainAll(zoneStoragePoolsByHypervisor);
pools.addAll(zoneStoragePoolsByTags);
for (StoragePoolVO pool : pools) {
if (pool.getStatus() != StoragePoolStatus.Up) {
continue;