mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-6170
This commit is contained in:
parent
bbaec7bae8
commit
b06e66c50a
@ -27,6 +27,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.BaseCmd.CommandType;
|
||||
import org.apache.cloudstack.api.response.DomainResponse;
|
||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||
|
||||
@ -117,6 +118,21 @@ public class CreateServiceOfferingCmd extends BaseCmd {
|
||||
@Parameter(name = ApiConstants.IOPS_WRITE_RATE, type = CommandType.LONG, required = false, description = "io requests write rate of the disk offering")
|
||||
private Long iopsWriteRate;
|
||||
|
||||
@Parameter(name = ApiConstants.CUSTOMIZED_IOPS, type = CommandType.BOOLEAN, required = false, description = "whether compute offering iops is custom or not")
|
||||
private Boolean customizedIops;
|
||||
|
||||
@Parameter(name = ApiConstants.MIN_IOPS, type = CommandType.LONG, required = false, description = "min iops of the compute offering")
|
||||
private Long minIops;
|
||||
|
||||
@Parameter(name = ApiConstants.MAX_IOPS, type = CommandType.LONG, required = false, description = "max iops of the compute offering")
|
||||
private Long maxIops;
|
||||
|
||||
@Parameter(name = ApiConstants.HYPERVISOR_SNAPSHOT_RESERVE,
|
||||
type = CommandType.INTEGER,
|
||||
required = false,
|
||||
description = "Hypervisor snapshot reserve space as a percent of a volume (for managed storage using Xen or VMware)")
|
||||
private Integer hypervisorSnapshotReserve;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -215,6 +231,22 @@ public class CreateServiceOfferingCmd extends BaseCmd {
|
||||
return iopsWriteRate;
|
||||
}
|
||||
|
||||
public Boolean isCustomizedIops() {
|
||||
return customizedIops;
|
||||
}
|
||||
|
||||
public Long getMinIops() {
|
||||
return minIops;
|
||||
}
|
||||
|
||||
public Long getMaxIops() {
|
||||
return maxIops;
|
||||
}
|
||||
|
||||
public Integer getHypervisorSnapshotReserve() {
|
||||
return hypervisorSnapshotReserve;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.storage.to;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
|
||||
|
||||
import com.cloud.agent.api.to.DataStoreTO;
|
||||
@ -23,6 +25,16 @@ import com.cloud.storage.DataStoreRole;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
|
||||
public class PrimaryDataStoreTO implements DataStoreTO {
|
||||
public static final String MANAGED = PrimaryDataStore.MANAGED;
|
||||
public static final String STORAGE_HOST = PrimaryDataStore.STORAGE_HOST;
|
||||
public static final String MANAGED_STORE_TARGET = PrimaryDataStore.MANAGED_STORE_TARGET;
|
||||
public static final String MANAGED_STORE_TARGET_ROOT_VOLUME = PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME;
|
||||
public static final String CHAP_INITIATOR_USERNAME = PrimaryDataStore.CHAP_INITIATOR_USERNAME;
|
||||
public static final String CHAP_INITIATOR_SECRET = PrimaryDataStore.CHAP_INITIATOR_SECRET;
|
||||
public static final String CHAP_TARGET_USERNAME = PrimaryDataStore.CHAP_TARGET_USERNAME;
|
||||
public static final String CHAP_TARGET_SECRET = PrimaryDataStore.CHAP_TARGET_SECRET;
|
||||
public static final String VOLUME_SIZE = PrimaryDataStore.VOLUME_SIZE;
|
||||
|
||||
private final String uuid;
|
||||
private final String name;
|
||||
private String type;
|
||||
@ -32,6 +44,7 @@ public class PrimaryDataStoreTO implements DataStoreTO {
|
||||
private String path;
|
||||
private int port;
|
||||
private final String url;
|
||||
private Map<String, String> details;
|
||||
|
||||
public PrimaryDataStoreTO(PrimaryDataStore dataStore) {
|
||||
this.uuid = dataStore.getUuid();
|
||||
@ -42,6 +55,7 @@ public class PrimaryDataStoreTO implements DataStoreTO {
|
||||
this.setPath(dataStore.getPath());
|
||||
this.setPort(dataStore.getPort());
|
||||
this.url = dataStore.getUri();
|
||||
this.details = dataStore.getDetails();
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
@ -58,6 +72,10 @@ public class PrimaryDataStoreTO implements DataStoreTO {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
public Map<String, String> getDetails() {
|
||||
return this.details;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@ -26,6 +26,8 @@ import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.host.Host;
|
||||
|
||||
public interface DataMotionService {
|
||||
void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
|
||||
|
||||
void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback);
|
||||
|
||||
void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
|
||||
|
||||
@ -30,6 +30,8 @@ public interface DataMotionStrategy {
|
||||
|
||||
StrategyPriority canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost);
|
||||
|
||||
Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
|
||||
|
||||
Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback);
|
||||
|
||||
Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
|
||||
|
||||
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.apache.cloudstack.engine.subsystem.api.storage;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
|
||||
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
@ -25,6 +27,16 @@ import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.StoragePool;
|
||||
|
||||
public interface PrimaryDataStoreInfo extends StoragePool {
|
||||
static final String MANAGED = "managed";
|
||||
static final String STORAGE_HOST= "storageHost";
|
||||
static final String MANAGED_STORE_TARGET = "managedStoreTarget";
|
||||
static final String MANAGED_STORE_TARGET_ROOT_VOLUME = "managedStoreTargetRootVolume";
|
||||
static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername";
|
||||
static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";
|
||||
static final String CHAP_TARGET_USERNAME = "chapTargetUsername";
|
||||
static final String CHAP_TARGET_SECRET = "chapTargetSecret";
|
||||
static final String VOLUME_SIZE = "volumeSize";
|
||||
|
||||
boolean isHypervisorSupported(HypervisorType hypervisor);
|
||||
|
||||
boolean isLocalStorageSupported();
|
||||
@ -37,5 +49,11 @@ public interface PrimaryDataStoreInfo extends StoragePool {
|
||||
@Override
|
||||
StoragePoolType getPoolType();
|
||||
|
||||
boolean isManaged();
|
||||
|
||||
void setDetails(Map<String, String> details);
|
||||
|
||||
Map<String, String> getDetails();
|
||||
|
||||
PrimaryDataStoreLifeCycle getLifeCycle();
|
||||
}
|
||||
|
||||
@ -78,7 +78,11 @@ public interface VolumeService {
|
||||
|
||||
VolumeEntity getVolumeEntity(long volumeId);
|
||||
|
||||
AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template);
|
||||
AsyncCallFuture<VolumeApiResult> createManagedStorageAndVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId,
|
||||
TemplateInfo srcTemplateInfo, long destHostId);
|
||||
|
||||
AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId,
|
||||
TemplateInfo template);
|
||||
|
||||
AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume, DataStore destStore);
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@ import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationSer
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
|
||||
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.PrimaryDataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
|
||||
@ -1113,8 +1114,24 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
||||
future = volService.createVolumeAsync(volume, destPool);
|
||||
} else {
|
||||
TemplateInfo templ = tmplFactory.getTemplate(templateId, DataStoreRole.Image);
|
||||
|
||||
PrimaryDataStore primaryDataStore = (PrimaryDataStore)destPool;
|
||||
|
||||
if (primaryDataStore.isManaged()) {
|
||||
DiskOffering diskOffering = _entityMgr.findById(DiskOffering.class, volume.getDiskOfferingId());
|
||||
HypervisorType hyperType = vm.getVirtualMachine().getHypervisorType();
|
||||
|
||||
// update the volume's hypervisor_ss_reserve from its disk offering (used for managed storage)
|
||||
updateHypervisorSnapshotReserveForVolume(diskOffering, volume, hyperType);
|
||||
|
||||
long hostId = vm.getVirtualMachine().getHostId();
|
||||
|
||||
future = volService.createManagedStorageAndVolumeFromTemplateAsync(volume, destPool.getId(), templ, hostId);
|
||||
}
|
||||
else {
|
||||
future = volService.createVolumeFromTemplateAsync(volume, destPool.getId(), templ);
|
||||
}
|
||||
}
|
||||
VolumeApiResult result = null;
|
||||
try {
|
||||
result = future.get();
|
||||
|
||||
@ -46,6 +46,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
||||
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||
import org.apache.cloudstack.storage.RemoteHostEndPoint;
|
||||
import org.apache.cloudstack.storage.command.CopyCommand;
|
||||
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
|
||||
|
||||
@ -94,15 +95,17 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
|
||||
protected boolean needCacheStorage(DataObject srcData, DataObject destData) {
|
||||
DataTO srcTO = srcData.getTO();
|
||||
DataTO destTO = destData.getTO();
|
||||
DataStoreTO srcStoreTO = srcTO.getDataStore();
|
||||
DataStoreTO destStoreTO = destTO.getDataStore();
|
||||
|
||||
if (srcStoreTO instanceof NfsTO || srcStoreTO.getRole() == DataStoreRole.ImageCache) {
|
||||
//||
|
||||
// (srcStoreTO instanceof PrimaryDataStoreTO && ((PrimaryDataStoreTO)srcStoreTO).getPoolType() == StoragePoolType.NetworkFilesystem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DataTO destTO = destData.getTO();
|
||||
DataStoreTO destStoreTO = destTO.getDataStore();
|
||||
|
||||
if (destStoreTO instanceof NfsTO || destStoreTO.getRole() == DataStoreRole.ImageCache) {
|
||||
return false;
|
||||
}
|
||||
@ -147,7 +150,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
return selectedScope;
|
||||
}
|
||||
|
||||
protected Answer copyObject(DataObject srcData, DataObject destData) {
|
||||
protected Answer copyObject(DataObject srcData, DataObject destData, Host destHost) {
|
||||
String value = configDao.getValue(Config.PrimaryStorageDownloadWait.toString());
|
||||
int _primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue()));
|
||||
Answer answer = null;
|
||||
@ -160,7 +163,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
}
|
||||
|
||||
CopyCommand cmd = new CopyCommand(srcForCopy.getTO(), destData.getTO(), _primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value());
|
||||
EndPoint ep = selector.select(srcForCopy, destData);
|
||||
EndPoint ep = destHost != null ? RemoteHostEndPoint.getHypervisorHostEndPoint(destHost) : selector.select(srcForCopy, destData);
|
||||
if (ep == null) {
|
||||
String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
|
||||
s_logger.error(errMsg);
|
||||
@ -193,6 +196,10 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
protected Answer copyObject(DataObject srcData, DataObject destData) {
|
||||
return copyObject(srcData, destData, null);
|
||||
}
|
||||
|
||||
protected DataObject cacheSnapshotChain(SnapshotInfo snapshot, Scope scope) {
|
||||
DataObject leafData = null;
|
||||
DataStore store = cacheMgr.getCacheStorage(snapshot, scope);
|
||||
@ -392,8 +399,9 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
return answer;
|
||||
}
|
||||
|
||||
// Note: destHost is currently only used if the copyObject method is invoked
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
Answer answer = null;
|
||||
String errMsg = null;
|
||||
try {
|
||||
@ -416,7 +424,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
} else if (srcData.getType() == DataObjectType.SNAPSHOT && destData.getType() == DataObjectType.SNAPSHOT) {
|
||||
answer = copySnapshot(srcData, destData);
|
||||
} else {
|
||||
answer = copyObject(srcData, destData);
|
||||
answer = copyObject(srcData, destData, destHost);
|
||||
}
|
||||
|
||||
if (answer != null && !answer.getResult()) {
|
||||
@ -432,6 +440,11 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
return copyAsync(srcData, destData, null, callback);
|
||||
}
|
||||
|
||||
@DB
|
||||
protected Answer createTemplateFromSnapshot(DataObject srcData, DataObject destData) {
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ public class DataMotionServiceImpl implements DataMotionService {
|
||||
StorageStrategyFactory storageStrategyFactory;
|
||||
|
||||
@Override
|
||||
public void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
if (srcData.getDataStore() == null || destData.getDataStore() == null) {
|
||||
throw new CloudRuntimeException("can't find data store");
|
||||
}
|
||||
@ -65,7 +65,12 @@ public class DataMotionServiceImpl implements DataMotionService {
|
||||
destData.getType().name() + " '" + destData.getUuid() + "'");
|
||||
}
|
||||
|
||||
strategy.copyAsync(srcData, destData, callback);
|
||||
strategy.copyAsync(srcData, destData, destHost, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
copyAsync(srcData, destData, null, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -30,6 +30,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
||||
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
|
||||
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
|
||||
@ -299,6 +300,20 @@ public class TemplateObject implements TemplateInfo {
|
||||
if (dataStore == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// managed primary data stores should not have an install path
|
||||
if (dataStore instanceof PrimaryDataStore) {
|
||||
PrimaryDataStore primaryDataStore = (PrimaryDataStore)dataStore;
|
||||
|
||||
Map<String, String> details = primaryDataStore.getDetails();
|
||||
|
||||
boolean managed = details != null && Boolean.parseBoolean(details.get(PrimaryDataStore.MANAGED));
|
||||
|
||||
if (managed) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
DataObjectInStore obj = objectInStoreMgr.findObject(this, dataStore);
|
||||
return obj.getInstallPath();
|
||||
}
|
||||
|
||||
@ -57,6 +57,11 @@ public class MockStorageMotionStrategy implements DataMotionStrategy {
|
||||
return StrategyPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
CopyCmdAnswer answer = null;
|
||||
|
||||
@ -20,6 +20,7 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -67,6 +68,7 @@ import com.cloud.utils.storage.encoding.EncodingType;
|
||||
|
||||
public class PrimaryDataStoreImpl implements PrimaryDataStore {
|
||||
private static final Logger s_logger = Logger.getLogger(PrimaryDataStoreImpl.class);
|
||||
|
||||
protected PrimaryDataStoreDriver driver;
|
||||
protected StoragePoolVO pdsv;
|
||||
@Inject
|
||||
@ -86,6 +88,7 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
|
||||
|
||||
@Inject
|
||||
private VolumeDao volumeDao;
|
||||
private Map<String, String> _details;
|
||||
|
||||
public PrimaryDataStoreImpl() {
|
||||
|
||||
@ -135,6 +138,16 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
|
||||
return pdsv.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDetails(Map<String, String> details) {
|
||||
_details = details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getDetails() {
|
||||
return _details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUri() {
|
||||
String path = pdsv.getPath().replaceFirst("/*", "");
|
||||
@ -222,10 +235,15 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isManaged() {
|
||||
return pdsv.isManaged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataObject create(DataObject obj) {
|
||||
// create template on primary storage
|
||||
if (obj.getType() == DataObjectType.TEMPLATE) {
|
||||
if (obj.getType() == DataObjectType.TEMPLATE && !isManaged()) {
|
||||
try {
|
||||
String templateIdPoolIdString = "templateId:" + obj.getId() + "poolId:" + getId();
|
||||
VMTemplateStoragePoolVO templateStoragePoolRef;
|
||||
|
||||
@ -85,7 +85,7 @@ public class DefaultHostListener implements HypervisorHostListener {
|
||||
poolVO.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes());
|
||||
primaryStoreDao.update(pool.getId(), poolVO);
|
||||
|
||||
s_logger.info("Connection established between " + pool + " host + " + hostId);
|
||||
s_logger.info("Connection established between storage pool " + pool + " and host " + hostId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ package org.apache.cloudstack.storage.volume;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -40,6 +41,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
|
||||
@ -60,6 +62,7 @@ import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager;
|
||||
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
|
||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.storage.ListVolumeAnswer;
|
||||
@ -72,6 +75,7 @@ import com.cloud.event.EventTypes;
|
||||
import com.cloud.event.UsageEventUtils;
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.storage.DataStoreRole;
|
||||
import com.cloud.storage.ScopeType;
|
||||
@ -122,6 +126,8 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
VolumeDao _volumeDao;
|
||||
@Inject
|
||||
EndPointSelector _epSelector;
|
||||
@Inject
|
||||
HostDao _hostDao;
|
||||
|
||||
public VolumeServiceImpl() {
|
||||
}
|
||||
@ -349,6 +355,39 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
return null;
|
||||
}
|
||||
|
||||
private class ManagedCreateBaseImageContext<T> extends AsyncRpcContext<T> {
|
||||
private final VolumeInfo _volumeInfo;
|
||||
private final PrimaryDataStore _primaryDataStore;
|
||||
private final TemplateInfo _templateInfo;
|
||||
private final AsyncCallFuture<VolumeApiResult> _future;
|
||||
|
||||
public ManagedCreateBaseImageContext(AsyncCompletionCallback<T> callback, VolumeInfo volumeInfo,
|
||||
PrimaryDataStore primaryDatastore, TemplateInfo templateInfo, AsyncCallFuture<VolumeApiResult> future) {
|
||||
super(callback);
|
||||
|
||||
_volumeInfo = volumeInfo;
|
||||
_primaryDataStore = primaryDatastore;
|
||||
_templateInfo = templateInfo;
|
||||
_future = future;
|
||||
}
|
||||
|
||||
public VolumeInfo getVolumeInfo() {
|
||||
return _volumeInfo;
|
||||
}
|
||||
|
||||
public PrimaryDataStore getPrimaryDataStore() {
|
||||
return _primaryDataStore;
|
||||
}
|
||||
|
||||
public TemplateInfo getTemplateInfo() {
|
||||
return _templateInfo;
|
||||
}
|
||||
|
||||
public AsyncCallFuture<VolumeApiResult> getFuture() {
|
||||
return _future;
|
||||
}
|
||||
}
|
||||
|
||||
class CreateBaseImageContext<T> extends AsyncRpcContext<T> {
|
||||
private final VolumeInfo volume;
|
||||
private final PrimaryDataStore dataStore;
|
||||
@ -411,7 +450,6 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
|
||||
@DB
|
||||
protected void createBaseImageAsync(VolumeInfo volume, PrimaryDataStore dataStore, TemplateInfo template, AsyncCallFuture<VolumeApiResult> future) {
|
||||
|
||||
DataObject templateOnPrimaryStoreObj = dataStore.create(template);
|
||||
|
||||
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(dataStore.getId(), template.getId());
|
||||
@ -476,6 +514,37 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
return;
|
||||
}
|
||||
|
||||
protected Void managedCopyBaseImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
|
||||
ManagedCreateBaseImageContext<VolumeApiResult> context) {
|
||||
CopyCommandResult result = callback.getResult();
|
||||
VolumeInfo volumeInfo = context.getVolumeInfo();
|
||||
VolumeApiResult res = new VolumeApiResult(volumeInfo);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
// volumeInfo.processEvent(Event.OperationSuccessed, result.getAnswer());
|
||||
|
||||
VolumeVO volume = volDao.findById(volumeInfo.getId());
|
||||
CopyCmdAnswer answer = (CopyCmdAnswer)result.getAnswer();
|
||||
TemplateObjectTO templateObjectTo = (TemplateObjectTO)answer.getNewData();
|
||||
|
||||
volume.setPath(templateObjectTo.getPath());
|
||||
volume.setFormat(templateObjectTo.getFormat());
|
||||
|
||||
volDao.update(volume.getId(), volume);
|
||||
}
|
||||
else {
|
||||
volumeInfo.processEvent(Event.DestroyRequested);
|
||||
|
||||
res.setResult(result.getResult());
|
||||
}
|
||||
|
||||
AsyncCallFuture<VolumeApiResult> future = context.getFuture();
|
||||
|
||||
future.complete(res);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@DB
|
||||
protected Void copyBaseImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CreateBaseImageContext<VolumeApiResult> context) {
|
||||
CopyCommandResult result = callback.getResult();
|
||||
@ -577,6 +646,91 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncCallFuture<VolumeApiResult> createManagedStorageAndVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId,
|
||||
TemplateInfo srcTemplateInfo, long destHostId) {
|
||||
PrimaryDataStore destPrimaryDataStore = dataStoreMgr.getPrimaryDataStore(destDataStoreId);
|
||||
TemplateInfo destTemplateInfo = (TemplateInfo)destPrimaryDataStore.create(srcTemplateInfo);
|
||||
Host destHost = _hostDao.findById(destHostId);
|
||||
|
||||
if (destHost == null) {
|
||||
throw new CloudRuntimeException("Destinatin host should not be null.");
|
||||
}
|
||||
|
||||
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
|
||||
|
||||
try {
|
||||
// must call driver to have a volume created
|
||||
AsyncCallFuture<VolumeApiResult> createVolumeFuture = createVolumeAsync(volumeInfo, destPrimaryDataStore);
|
||||
|
||||
VolumeApiResult createVolumeResult = createVolumeFuture.get();
|
||||
|
||||
if (createVolumeResult.isFailed()) {
|
||||
throw new CloudRuntimeException("Creation of a volume failed: " + createVolumeResult.getResult());
|
||||
}
|
||||
|
||||
// refresh the volume from the DB
|
||||
volumeInfo = volFactory.getVolume(volumeInfo.getId(), destPrimaryDataStore);
|
||||
|
||||
connectVolumeToHost(volumeInfo, destHost, destPrimaryDataStore);
|
||||
|
||||
ManagedCreateBaseImageContext<CreateCmdResult> context = new ManagedCreateBaseImageContext<CreateCmdResult>(null, volumeInfo,
|
||||
destPrimaryDataStore, srcTemplateInfo, future);
|
||||
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().managedCopyBaseImageCallback(null, null)).setContext(context);
|
||||
|
||||
Map<String, String> details = new HashMap<String, String>();
|
||||
|
||||
details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString());
|
||||
details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress());
|
||||
// for managed storage, the storage repository (XenServer) or datastore (ESX) name is based off of the iScsiName property of a volume
|
||||
details.put(PrimaryDataStore.MANAGED_STORE_TARGET, volumeInfo.get_iScsiName());
|
||||
details.put(PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME, volumeInfo.getName());
|
||||
details.put(PrimaryDataStore.VOLUME_SIZE, String.valueOf(volumeInfo.getSize()));
|
||||
|
||||
ChapInfo chapInfo = getChapInfo(volumeInfo, destPrimaryDataStore);
|
||||
|
||||
if (chapInfo != null) {
|
||||
details.put(PrimaryDataStore.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername());
|
||||
details.put(PrimaryDataStore.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret());
|
||||
details.put(PrimaryDataStore.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername());
|
||||
details.put(PrimaryDataStore.CHAP_TARGET_SECRET, chapInfo.getTargetSecret());
|
||||
}
|
||||
|
||||
destPrimaryDataStore.setDetails(details);
|
||||
|
||||
motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
String errMsg = t.toString();
|
||||
|
||||
volumeInfo.processEvent(Event.DestroyRequested);
|
||||
|
||||
disconnectVolumeFromHost(volumeInfo, destHost, destPrimaryDataStore);
|
||||
|
||||
try {
|
||||
AsyncCallFuture<VolumeApiResult> expungeVolumeFuture = expungeVolumeAsync(volumeInfo);
|
||||
|
||||
VolumeApiResult expungeVolumeResult = expungeVolumeFuture.get();
|
||||
|
||||
if (expungeVolumeResult.isFailed()) {
|
||||
errMsg += " : Failed to expunge a volume that was created";
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
errMsg += " : " + ex.getMessage();
|
||||
}
|
||||
|
||||
VolumeApiResult result = new VolumeApiResult(volumeInfo);
|
||||
|
||||
result.setResult(errMsg);
|
||||
|
||||
future.complete(result);
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@DB
|
||||
@Override
|
||||
public AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template) {
|
||||
|
||||
@ -42,6 +42,11 @@ public class SimulatorDataMotionStrategy implements DataMotionStrategy {
|
||||
return StrategyPriority.HYPERVISOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
CopyCommandResult result = new CopyCommandResult("something", null);
|
||||
|
||||
@ -85,6 +85,11 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy {
|
||||
return StrategyPriority.CANT_HANDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
CopyCommandResult result = new CopyCommandResult(null, null);
|
||||
|
||||
@ -1869,18 +1869,23 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
return prepareManagedStorage(conn, details, null, vdiNameLabel);
|
||||
}
|
||||
|
||||
protected VDI prepareManagedStorage(Connection conn, Map<String, String> details, String path, String vdiNameLabel) throws Exception {
|
||||
protected SR prepareManagedSr(Connection conn, Map<String, String> details) {
|
||||
String iScsiName = details.get(DiskTO.IQN);
|
||||
String storageHost = details.get(DiskTO.STORAGE_HOST);
|
||||
String chapInitiatorUsername = details.get(DiskTO.CHAP_INITIATOR_USERNAME);
|
||||
String chapInitiatorSecret = details.get(DiskTO.CHAP_INITIATOR_SECRET);
|
||||
Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE));
|
||||
|
||||
SR sr = getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, true);
|
||||
return getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, true);
|
||||
}
|
||||
|
||||
protected VDI prepareManagedStorage(Connection conn, Map<String, String> details, String path, String vdiNameLabel) throws Exception {
|
||||
SR sr = prepareManagedSr(conn, details);
|
||||
|
||||
VDI vdi = getVDIbyUuid(conn, path, false);
|
||||
|
||||
if (vdi == null) {
|
||||
Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE));
|
||||
|
||||
vdi = createVdi(sr, vdiNameLabel, volumeSize);
|
||||
}
|
||||
|
||||
|
||||
@ -59,6 +59,7 @@ import org.apache.cloudstack.storage.command.ForgetObjectCmd;
|
||||
import org.apache.cloudstack.storage.command.IntroduceObjectAnswer;
|
||||
import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
|
||||
import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol;
|
||||
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||
@ -887,58 +888,121 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
||||
|
||||
@Override
|
||||
public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) {
|
||||
DataTO srcData = cmd.getSrcTO();
|
||||
DataTO destData = cmd.getDestTO();
|
||||
DataTO srcDataTo = cmd.getSrcTO();
|
||||
DataTO destDataTo = cmd.getDestTO();
|
||||
int wait = cmd.getWait();
|
||||
DataStoreTO srcStore = srcData.getDataStore();
|
||||
try {
|
||||
if ((srcStore instanceof NfsTO) && (srcData.getObjectType() == DataObjectType.TEMPLATE)) {
|
||||
NfsTO srcImageStore = (NfsTO)srcStore;
|
||||
TemplateObjectTO srcTemplate = (TemplateObjectTO)srcData;
|
||||
String storeUrl = srcImageStore.getUrl();
|
||||
DataStoreTO srcDataStoreTo = srcDataTo.getDataStore();
|
||||
|
||||
try {
|
||||
if ((srcDataStoreTo instanceof NfsTO) && (srcDataTo.getObjectType() == DataObjectType.TEMPLATE)) {
|
||||
NfsTO srcImageStore = (NfsTO)srcDataStoreTo;
|
||||
TemplateObjectTO srcTemplateObjectTo = (TemplateObjectTO)srcDataTo;
|
||||
String storeUrl = srcImageStore.getUrl();
|
||||
URI uri = new URI(storeUrl);
|
||||
String tmplpath = uri.getHost() + ":" + uri.getPath() + "/" + srcData.getPath();
|
||||
String poolName = destData.getDataStore().getUuid();
|
||||
String tmplPath = uri.getHost() + ":" + uri.getPath() + "/" + srcDataTo.getPath();
|
||||
DataStoreTO destDataStoreTo = destDataTo.getDataStore();
|
||||
|
||||
boolean managed = false;
|
||||
String storageHost = null;
|
||||
String managedStoragePoolName = null;
|
||||
String managedStoragePoolRootVolumeName = null;
|
||||
String managedStoragePoolRootVolumeSize = null;
|
||||
String chapInitiatorUsername = null;
|
||||
String chapInitiatorSecret = null;
|
||||
|
||||
if (destDataStoreTo instanceof PrimaryDataStoreTO) {
|
||||
PrimaryDataStoreTO destPrimaryDataStoreTo = (PrimaryDataStoreTO)destDataStoreTo;
|
||||
|
||||
Map<String, String> details = destPrimaryDataStoreTo.getDetails();
|
||||
|
||||
if (details != null) {
|
||||
managed = Boolean.parseBoolean(details.get(PrimaryDataStoreTO.MANAGED));
|
||||
|
||||
if (managed) {
|
||||
storageHost = details.get(PrimaryDataStoreTO.STORAGE_HOST);
|
||||
managedStoragePoolName = details.get(PrimaryDataStoreTO.MANAGED_STORE_TARGET);
|
||||
managedStoragePoolRootVolumeName = details.get(PrimaryDataStoreTO.MANAGED_STORE_TARGET_ROOT_VOLUME);
|
||||
managedStoragePoolRootVolumeSize = details.get(PrimaryDataStoreTO.VOLUME_SIZE);
|
||||
chapInitiatorUsername = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_USERNAME);
|
||||
chapInitiatorSecret = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_SECRET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connection conn = hypervisorResource.getConnection();
|
||||
|
||||
SR poolsr = null;
|
||||
Set<SR> srs = SR.getByNameLabel(conn, poolName);
|
||||
final SR sr;
|
||||
|
||||
if (managed) {
|
||||
Map<String, String> details = new HashMap<String, String>();
|
||||
|
||||
details.put(DiskTO.STORAGE_HOST, storageHost);
|
||||
details.put(DiskTO.IQN, managedStoragePoolName);
|
||||
details.put(DiskTO.VOLUME_SIZE, managedStoragePoolRootVolumeSize);
|
||||
details.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInitiatorUsername);
|
||||
details.put(DiskTO.CHAP_INITIATOR_SECRET, chapInitiatorSecret);
|
||||
|
||||
sr = hypervisorResource.prepareManagedSr(conn, details);
|
||||
}
|
||||
else {
|
||||
String srName = destDataStoreTo.getUuid();
|
||||
Set<SR> srs = SR.getByNameLabel(conn, srName);
|
||||
|
||||
if (srs.size() != 1) {
|
||||
String msg = "There are " + srs.size() + " SRs with same name: " + poolName;
|
||||
String msg = "There are " + srs.size() + " SRs with same name: " + srName;
|
||||
|
||||
s_logger.warn(msg);
|
||||
|
||||
return new CopyCmdAnswer(msg);
|
||||
} else {
|
||||
poolsr = srs.iterator().next();
|
||||
sr = srs.iterator().next();
|
||||
}
|
||||
String pUuid = poolsr.getUuid(conn);
|
||||
boolean isISCSI = IsISCSI(poolsr.getType(conn));
|
||||
String uuid = copy_vhd_from_secondarystorage(conn, tmplpath, pUuid, wait);
|
||||
VDI tmpl = getVDIbyUuid(conn, uuid);
|
||||
VDI snapshotvdi = tmpl.snapshot(conn, new HashMap<String, String>());
|
||||
String snapshotUuid = snapshotvdi.getUuid(conn);
|
||||
snapshotvdi.setNameLabel(conn, "Template " + srcTemplate.getName());
|
||||
String parentuuid = getVhdParent(conn, pUuid, snapshotUuid, isISCSI);
|
||||
VDI parent = getVDIbyUuid(conn, parentuuid);
|
||||
Long phySize = parent.getPhysicalUtilisation(conn);
|
||||
tmpl.destroy(conn);
|
||||
poolsr.scan(conn);
|
||||
}
|
||||
|
||||
String srUuid = sr.getUuid(conn);
|
||||
String tmplUuid = copy_vhd_from_secondarystorage(conn, tmplPath, srUuid, wait);
|
||||
VDI tmplVdi = getVDIbyUuid(conn, tmplUuid);
|
||||
|
||||
final String uuidToReturn;
|
||||
|
||||
if (managed) {
|
||||
uuidToReturn = tmplUuid;
|
||||
|
||||
tmplVdi.setNameLabel(conn, managedStoragePoolRootVolumeName);
|
||||
}
|
||||
else {
|
||||
VDI snapshotVdi = tmplVdi.snapshot(conn, new HashMap<String, String>());
|
||||
|
||||
uuidToReturn = snapshotVdi.getUuid(conn);
|
||||
|
||||
snapshotVdi.setNameLabel(conn, "Template " + srcTemplateObjectTo.getName());
|
||||
|
||||
tmplVdi.destroy(conn);
|
||||
}
|
||||
|
||||
sr.scan(conn);
|
||||
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
TemplateObjectTO newVol = new TemplateObjectTO();
|
||||
newVol.setUuid(snapshotvdi.getUuid(conn));
|
||||
newVol.setPath(newVol.getUuid());
|
||||
|
||||
newVol.setUuid(uuidToReturn);
|
||||
newVol.setPath(uuidToReturn);
|
||||
newVol.setFormat(ImageFormat.VHD);
|
||||
|
||||
return new CopyCmdAnswer(newVol);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = "Catch Exception " + e.getClass().getName() + " for template + " + " due to " + e.toString();
|
||||
|
||||
s_logger.warn(msg, e);
|
||||
|
||||
return new CopyCmdAnswer(msg);
|
||||
}
|
||||
|
||||
return new CopyCmdAnswer("not implemented yet");
|
||||
}
|
||||
|
||||
|
||||
@ -90,6 +90,11 @@ public class XenServerStorageMotionStrategy implements DataMotionStrategy {
|
||||
return StrategyPriority.CANT_HANDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||
CopyCommandResult result = new CopyCommandResult(null, null);
|
||||
|
||||
@ -2016,15 +2016,54 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
|
||||
return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber, memory, cpuSpeed, cmd.getDisplayText(), localStorageRequired,
|
||||
offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate(), cmd.getDeploymentPlanner(), cmd.getDetails(),
|
||||
cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate());
|
||||
cmd.isCustomizedIops(), cmd.getMinIops(), cmd.getMaxIops(), cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate(),
|
||||
cmd.getHypervisorSnapshotReserve());
|
||||
}
|
||||
|
||||
protected ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vmType, String name, Integer cpu, Integer ramSize, Integer speed,
|
||||
String displayText, boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag,
|
||||
Integer networkRate, String deploymentPlanner, Map<String, String> details, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) {
|
||||
Integer networkRate, String deploymentPlanner, Map<String, String> details, Boolean isCustomizedIops, Long minIops, Long maxIops,
|
||||
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate, Integer hypervisorSnapshotReserve) {
|
||||
tags = StringUtils.cleanupTags(tags);
|
||||
ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, localStorageRequired,
|
||||
false, tags, isSystem, vmType, domainId, hostTag, deploymentPlanner);
|
||||
|
||||
if (isCustomizedIops != null) {
|
||||
bytesReadRate = null;
|
||||
bytesWriteRate = null;
|
||||
iopsReadRate = null;
|
||||
iopsWriteRate = null;
|
||||
|
||||
if (isCustomizedIops) {
|
||||
minIops = null;
|
||||
maxIops = null;
|
||||
} else {
|
||||
if (minIops == null && maxIops == null) {
|
||||
minIops = 0L;
|
||||
maxIops = 0L;
|
||||
} else {
|
||||
if (minIops == null || minIops <= 0) {
|
||||
throw new InvalidParameterValueException("The min IOPS must be greater than 0.");
|
||||
}
|
||||
|
||||
if (maxIops == null) {
|
||||
maxIops = 0L;
|
||||
}
|
||||
|
||||
if (minIops > maxIops) {
|
||||
throw new InvalidParameterValueException("The min IOPS must be less than or equal to the max IOPS.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
minIops = null;
|
||||
maxIops = null;
|
||||
}
|
||||
|
||||
offering.setCustomizedIops(isCustomizedIops);
|
||||
offering.setMinIops(minIops);
|
||||
offering.setMaxIops(maxIops);
|
||||
|
||||
if ((bytesReadRate != null) && (bytesReadRate > 0))
|
||||
offering.setBytesReadRate(bytesReadRate);
|
||||
if ((bytesWriteRate != null) && (bytesWriteRate > 0))
|
||||
@ -2034,6 +2073,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
if ((iopsWriteRate != null) && (iopsWriteRate > 0))
|
||||
offering.setIopsWriteRate(iopsWriteRate);
|
||||
|
||||
if (hypervisorSnapshotReserve != null && hypervisorSnapshotReserve < 0) {
|
||||
throw new InvalidParameterValueException("If provided, Hypervisor Snapshot Reserve must be greater than or equal to 0.");
|
||||
}
|
||||
|
||||
offering.setHypervisorSnapshotReserve(hypervisorSnapshotReserve);
|
||||
|
||||
if ((offering = _serviceOfferingDao.persist(offering)) != null) {
|
||||
if (details != null) {
|
||||
List<ServiceOfferingDetailsVO> detailsVO = new ArrayList<ServiceOfferingDetailsVO>();
|
||||
|
||||
@ -136,6 +136,113 @@
|
||||
number: true
|
||||
}
|
||||
},
|
||||
qosType: {
|
||||
label: 'label.qos.type',
|
||||
docID: 'helpDiskOfferingQoSType',
|
||||
select: function(args) {
|
||||
var items = [];
|
||||
items.push({
|
||||
id: '',
|
||||
description: ''
|
||||
});
|
||||
items.push({
|
||||
id: 'hypervisor',
|
||||
description: 'hypervisor'
|
||||
});
|
||||
items.push({
|
||||
id: 'storage',
|
||||
description: 'storage'
|
||||
});
|
||||
args.response.success({
|
||||
data: items
|
||||
});
|
||||
|
||||
args.$select.change(function() {
|
||||
var $form = $(this).closest('form');
|
||||
var $isCustomizedIops = $form.find('.form-item[rel=isCustomizedIops]');
|
||||
var $minIops = $form.find('.form-item[rel=minIops]');
|
||||
var $maxIops = $form.find('.form-item[rel=maxIops]');
|
||||
var $hypervisorSnapshotReserve = $form.find('.form-item[rel=hypervisorSnapshotReserve]');
|
||||
var $diskBytesReadRate = $form.find('.form-item[rel=diskBytesReadRate]');
|
||||
var $diskBytesWriteRate = $form.find('.form-item[rel=diskBytesWriteRate]');
|
||||
var $diskIopsReadRate = $form.find('.form-item[rel=diskIopsReadRate]');
|
||||
var $diskIopsWriteRate = $form.find('.form-item[rel=diskIopsWriteRate]');
|
||||
|
||||
var qosId = $(this).val();
|
||||
|
||||
if (qosId == 'storage') { // Storage QoS
|
||||
$diskBytesReadRate.hide();
|
||||
$diskBytesWriteRate.hide();
|
||||
$diskIopsReadRate.hide();
|
||||
$diskIopsWriteRate.hide();
|
||||
|
||||
$isCustomizedIops.css('display', 'inline-block');
|
||||
|
||||
if ($isCustomizedIops.find('input[type=checkbox]').is(':checked')) {
|
||||
$minIops.hide();
|
||||
$maxIops.hide();
|
||||
} else {
|
||||
$minIops.css('display', 'inline-block');
|
||||
$maxIops.css('display', 'inline-block');
|
||||
}
|
||||
|
||||
$hypervisorSnapshotReserve.css('display', 'inline-block');
|
||||
} else if (qosId == 'hypervisor') { // Hypervisor Qos
|
||||
$isCustomizedIops.hide();
|
||||
$minIops.hide();
|
||||
$maxIops.hide();
|
||||
$hypervisorSnapshotReserve.hide();
|
||||
|
||||
$diskBytesReadRate.css('display', 'inline-block');
|
||||
$diskBytesWriteRate.css('display', 'inline-block');
|
||||
$diskIopsReadRate.css('display', 'inline-block');
|
||||
$diskIopsWriteRate.css('display', 'inline-block');
|
||||
} else { // No Qos
|
||||
$diskBytesReadRate.hide();
|
||||
$diskBytesWriteRate.hide();
|
||||
$diskIopsReadRate.hide();
|
||||
$diskIopsWriteRate.hide();
|
||||
$isCustomizedIops.hide();
|
||||
$minIops.hide();
|
||||
$maxIops.hide();
|
||||
$hypervisorSnapshotReserve.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
isCustomizedIops: {
|
||||
label: 'label.custom.disk.iops',
|
||||
docID: 'helpDiskOfferingCustomDiskIops',
|
||||
isBoolean: true,
|
||||
isReverse: true,
|
||||
isChecked: false
|
||||
},
|
||||
minIops: {
|
||||
label: 'label.disk.iops.min',
|
||||
docID: 'helpDiskOfferingDiskIopsMin',
|
||||
dependsOn: 'isCustomizedIops',
|
||||
validation: {
|
||||
required: false,
|
||||
number: true
|
||||
}
|
||||
},
|
||||
maxIops: {
|
||||
label: 'label.disk.iops.max',
|
||||
docID: 'helpDiskOfferingDiskIopsMax',
|
||||
dependsOn: 'isCustomizedIops',
|
||||
validation: {
|
||||
required: false,
|
||||
number: true
|
||||
}
|
||||
},
|
||||
hypervisorSnapshotReserve: {
|
||||
label: 'label.hypervisor.snapshot.reserve',
|
||||
docID: 'helpDiskOfferingHypervisorSnapshotReserve',
|
||||
validation: {
|
||||
required: false,
|
||||
number: true
|
||||
}
|
||||
},
|
||||
diskBytesReadRate: {
|
||||
label: 'label.disk.bytes.read.rate',
|
||||
docID: 'helpComputeOfferingDiskBytesReadRate',
|
||||
@ -326,26 +433,59 @@
|
||||
networkrate: args.data.networkRate
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.qosType == 'storage') {
|
||||
var customIops = args.data.isCustomizedIops == "on";
|
||||
|
||||
$.extend(data, {
|
||||
customizediops: customIops
|
||||
});
|
||||
|
||||
if (!customIops) {
|
||||
if (args.data.minIops != null && args.data.minIops.length > 0) {
|
||||
$.extend(data, {
|
||||
miniops: args.data.minIops
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.maxIops != null && args.data.maxIops.length > 0) {
|
||||
$.extend(data, {
|
||||
maxiops: args.data.maxIops
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (args.data.hypervisorSnapshotReserve != null && args.data.hypervisorSnapshotReserve.length > 0) {
|
||||
$.extend(data, {
|
||||
hypervisorsnapshotreserve: args.data.hypervisorSnapshotReserve
|
||||
});
|
||||
}
|
||||
} else if (args.data.qosType == 'hypervisor') {
|
||||
if (args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) {
|
||||
$.extend(data, {
|
||||
bytesreadrate: args.data.diskBytesReadRate
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) {
|
||||
$.extend(data, {
|
||||
byteswriterate: args.data.diskBytesWriteRate
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) {
|
||||
$.extend(data, {
|
||||
iopsreadrate: args.data.diskIopsReadRate
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) {
|
||||
$.extend(data, {
|
||||
iopswriterate: args.data.diskIopsWriteRate
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$.extend(data, {
|
||||
offerha: (args.data.offerHA == "on")
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user