diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java index 5178d685889..74eb2b9bf8f 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java @@ -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() { diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolForMigrationResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolForMigrationResponse.java index f0bbcb19136..2cfc8d03c3c 100644 --- a/api/src/org/apache/cloudstack/api/response/StoragePoolForMigrationResponse.java +++ b/api/src/org/apache/cloudstack/api/response/StoragePoolForMigrationResponse.java @@ -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(); diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java index 4411ddcb112..57a5ea14840 100644 --- a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java +++ b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java @@ -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; } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java index 280e02e2a32..cb467093955 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java @@ -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(); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java index ba29c1a14b0..fef97671961 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java @@ -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; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java index e9769802a37..d8d413283ad 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java @@ -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 requestVolumes = new ArrayList(); requestVolumes.add(volume); return storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool); - } + } - @Override - protected List select(DiskProfile dskCh, - VirtualMachineProfile vmProfile, - DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { - s_logger.debug("ZoneWideStoragePoolAllocator to find storage pool"); - List suitablePools = new ArrayList(); - 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 select(DiskProfile dskCh, + VirtualMachineProfile vmProfile, + DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { + s_logger.debug("ZoneWideStoragePoolAllocator to find storage pool"); + List suitablePools = new ArrayList(); + 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 storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags()); + List storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags()); + List storagePoolsByHypervisor = _storagePoolDao.findZoneWideStoragePoolsByHypervisor(plan.getDataCenterId(), dskCh.getHypervisorType()); + storagePools.retainAll(storagePoolsByHypervisor); // add remaining pools in zone, that did not match tags, to avoid set List 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; + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java index 5f8daf42bb3..349f6ba9079 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java @@ -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 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 hostPoolRecords = this.storagePoolHostDao .listByPoolId(store.getId()); diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java index fea02e8d1ed..cffa1cee4dc 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java @@ -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; } diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java index 7153282a2aa..fb37e8f4b10 100644 --- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java +++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java @@ -441,18 +441,18 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements } @Override - public boolean attachZone(DataStore dataStore, ZoneScope scope) { - List 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 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; } diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index a67397ec460..956aa87f0d5 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -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 details = new HashMap(); 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); diff --git a/server/src/com/cloud/storage/listener/StoragePoolMonitor.java b/server/src/com/cloud/storage/listener/StoragePoolMonitor.java index f957ca31ada..4848d446d21 100755 --- a/server/src/com/cloud/storage/listener/StoragePoolMonitor.java +++ b/server/src/com/cloud/storage/listener/StoragePoolMonitor.java @@ -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 pools = _poolDao.listBy(host.getDataCenterId(), host.getPodId(), host.getClusterId(), ScopeType.CLUSTER); - pools.addAll(_poolDao.findZoneWideStoragePoolsByTags(host.getDataCenterId(), null)); + List zoneStoragePoolsByTags = _poolDao.findZoneWideStoragePoolsByTags(host.getDataCenterId(), null); + List zoneStoragePoolsByHypervisor = _poolDao.findZoneWideStoragePoolsByHypervisor(host.getDataCenterId(), scCmd.getHypervisorType()); + zoneStoragePoolsByTags.retainAll(zoneStoragePoolsByHypervisor); + pools.addAll(zoneStoragePoolsByTags); for (StoragePoolVO pool : pools) { if (pool.getStatus() != StoragePoolStatus.Up) { continue;