mirror of
https://github.com/apache/cloudstack.git
synced 2025-12-15 18:12:35 +01:00
CLOUDSTACK-6191 Add support for specifying volume provisioning
type (thin, sparse, fat) in disk/compute offerings. Submitted-by: Yoshikazu Nojima <mail@ynojima.net> Reviewed-by: Marcus Sorensen, Mike Tutowski
This commit is contained in:
parent
4ba688f07d
commit
11f5bdd78d
@ -22,6 +22,8 @@ import org.apache.cloudstack.acl.InfrastructureEntity;
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
|
||||
/**
|
||||
* Represents a disk offering that specifies what the end user needs in
|
||||
* the disk offering.
|
||||
@ -61,6 +63,8 @@ public interface DiskOffering extends InfrastructureEntity, Identity, InternalId
|
||||
|
||||
String getDisplayText();
|
||||
|
||||
public ProvisioningType getProvisioningType();
|
||||
|
||||
public String getTags();
|
||||
|
||||
public String[] getTagsArray();
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
// under the License.
|
||||
package com.cloud.storage;
|
||||
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -32,27 +34,27 @@ public class Storage {
|
||||
VDI(true, true, false, "vdi"),
|
||||
TAR(false, false, false, "tar");
|
||||
|
||||
private final boolean thinProvisioned;
|
||||
private final boolean supportThinProvisioning;
|
||||
private final boolean supportSparse;
|
||||
private final boolean supportSnapshot;
|
||||
private final String fileExtension;
|
||||
|
||||
private ImageFormat(boolean thinProvisioned, boolean supportSparse, boolean supportSnapshot) {
|
||||
this.thinProvisioned = thinProvisioned;
|
||||
private ImageFormat(boolean supportThinProvisioning, boolean supportSparse, boolean supportSnapshot) {
|
||||
this.supportThinProvisioning = supportThinProvisioning;
|
||||
this.supportSparse = supportSparse;
|
||||
this.supportSnapshot = supportSnapshot;
|
||||
fileExtension = null;
|
||||
}
|
||||
|
||||
private ImageFormat(boolean thinProvisioned, boolean supportSparse, boolean supportSnapshot, String fileExtension) {
|
||||
this.thinProvisioned = thinProvisioned;
|
||||
private ImageFormat(boolean supportThinProvisioning, boolean supportSparse, boolean supportSnapshot, String fileExtension) {
|
||||
this.supportThinProvisioning = supportThinProvisioning;
|
||||
this.supportSparse = supportSparse;
|
||||
this.supportSnapshot = supportSnapshot;
|
||||
this.fileExtension = fileExtension;
|
||||
}
|
||||
|
||||
public boolean isThinProvisioned() {
|
||||
return thinProvisioned;
|
||||
public boolean supportThinProvisioning() {
|
||||
return supportThinProvisioning;
|
||||
}
|
||||
|
||||
public boolean supportsSparse() {
|
||||
@ -72,6 +74,35 @@ public class Storage {
|
||||
|
||||
}
|
||||
|
||||
public static enum ProvisioningType {
|
||||
THIN("thin"),
|
||||
SPARSE("sparse"),
|
||||
FAT("fat");
|
||||
|
||||
private final String provisionType;
|
||||
|
||||
private ProvisioningType(String provisionType){
|
||||
this.provisionType = provisionType;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return this.provisionType;
|
||||
}
|
||||
|
||||
public static ProvisioningType getProvisioningType(String provisioningType){
|
||||
|
||||
if(provisioningType.equals(THIN.provisionType)){
|
||||
return ProvisioningType.THIN;
|
||||
} else if(provisioningType.equals(SPARSE.provisionType)){
|
||||
return ProvisioningType.SPARSE;
|
||||
} else if (provisioningType.equals(FAT.provisionType)){
|
||||
return ProvisioningType.FAT;
|
||||
} else{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static enum FileSystem {
|
||||
Unknown, ext3, ntfs, fat, fat32, ext2, ext4, cdfs, hpfs, ufs, hfs, hfsp
|
||||
}
|
||||
|
||||
@ -187,6 +187,8 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba
|
||||
|
||||
Storage.ImageFormat getFormat();
|
||||
|
||||
Storage.ProvisioningType getProvisioningType();
|
||||
|
||||
Long getVmSnapshotChainSize();
|
||||
|
||||
Integer getHypervisorSnapshotReserve();
|
||||
|
||||
@ -18,6 +18,7 @@ package com.cloud.vm;
|
||||
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.offering.DiskOffering;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.Volume;
|
||||
|
||||
/**
|
||||
@ -35,6 +36,7 @@ public class DiskProfile {
|
||||
private Long templateId;
|
||||
private long volumeId;
|
||||
private String path;
|
||||
private ProvisioningType provisioningType;
|
||||
private Long bytesReadRate;
|
||||
private Long bytesWriteRate;
|
||||
private Long iopsReadRate;
|
||||
@ -165,6 +167,14 @@ public class DiskProfile {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public void setProvisioningType(ProvisioningType provisioningType){
|
||||
this.provisioningType = provisioningType;
|
||||
}
|
||||
|
||||
public ProvisioningType getProvisioningType(){
|
||||
return this.provisioningType;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@ -195,6 +195,7 @@ public class ApiConstants {
|
||||
public static final String PRIVATE_END_PORT = "privateendport";
|
||||
public static final String PRIVATE_ZONE = "privatezone";
|
||||
public static final String PROTOCOL = "protocol";
|
||||
public static final String PROVISIONINGTYPE = "provisioningtype";
|
||||
public static final String PUBLIC_INTERFACE = "publicinterface";
|
||||
public static final String PUBLIC_IP_ID = "publicipid";
|
||||
public static final String PUBLIC_IP = "publicip";
|
||||
|
||||
@ -27,6 +27,7 @@ import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.DiskOfferingResponse;
|
||||
import org.apache.cloudstack.api.response.DomainResponse;
|
||||
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.offering.DiskOffering;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.user.Account;
|
||||
@ -66,9 +67,14 @@ public class CreateDiskOfferingCmd extends BaseCmd {
|
||||
@Parameter(name = ApiConstants.STORAGE_TYPE, type = CommandType.STRING, description = "the storage type of the disk offering. Values are local and shared.")
|
||||
private String storageType = ServiceOffering.StorageType.shared.toString();
|
||||
|
||||
@Parameter(name = ApiConstants.PROVISIONINGTYPE,
|
||||
type = CommandType.STRING,
|
||||
description = "provisioning type used to create volumes. Valid values are thin, sparse, fat.")
|
||||
private String provisioningType = ProvisioningType.THIN.toString();
|
||||
|
||||
@Parameter(name = ApiConstants.DISPLAY_OFFERING,
|
||||
type = CommandType.BOOLEAN,
|
||||
description = "an optional field, whether to display the offering to the end user or not.")
|
||||
type = CommandType.BOOLEAN,
|
||||
description = "an optional field, whether to display the offering to the end user or not.")
|
||||
private Boolean displayOffering;
|
||||
|
||||
@Parameter(name = ApiConstants.BYTES_READ_RATE, type = CommandType.LONG, required = false, description = "bytes read rate of the disk offering")
|
||||
@ -158,6 +164,10 @@ public class CreateDiskOfferingCmd extends BaseCmd {
|
||||
return storageType;
|
||||
}
|
||||
|
||||
public String getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
public Boolean getDisplayOffering() {
|
||||
return displayOffering;
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
@ -53,6 +54,9 @@ public class CreateServiceOfferingCmd extends BaseCmd {
|
||||
@Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "the display text of the service offering")
|
||||
private String displayText;
|
||||
|
||||
@Parameter(name = ApiConstants.PROVISIONINGTYPE, type = CommandType.STRING, description = "provisioning type used to create volumes. Valid values are thin, sparse, fat.")
|
||||
private String provisioningType = Storage.ProvisioningType.THIN.toString();
|
||||
|
||||
@Parameter(name = ApiConstants.MEMORY, type = CommandType.INTEGER, required = false, description = "the total memory of the service offering in MB")
|
||||
private Integer memory;
|
||||
|
||||
@ -150,6 +154,10 @@ public class CreateServiceOfferingCmd extends BaseCmd {
|
||||
return displayText;
|
||||
}
|
||||
|
||||
public String getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
public Integer getMemory() {
|
||||
return memory;
|
||||
}
|
||||
|
||||
@ -85,6 +85,9 @@ public class DiskOfferingResponse extends BaseResponse {
|
||||
@Param(description = "the storage type for this disk offering")
|
||||
private String storageType;
|
||||
|
||||
@SerializedName("provisioningtype") @Param(description="provisioning type used to create volumes. Valid values are thin, sparse, fat.", since = "4.4.0")
|
||||
private String provisioningType;
|
||||
|
||||
@SerializedName("diskBytesReadRate")
|
||||
@Param(description = "bytes read rate of the disk offering")
|
||||
private Long bytesReadRate;
|
||||
@ -238,6 +241,14 @@ public class DiskOfferingResponse extends BaseResponse {
|
||||
this.storageType = storageType;
|
||||
}
|
||||
|
||||
public String getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
public void setProvisioningType(String provisioningType){
|
||||
this.provisioningType = provisioningType;
|
||||
}
|
||||
|
||||
public void setBytesReadRate(Long bytesReadRate) {
|
||||
this.bytesReadRate = bytesReadRate;
|
||||
}
|
||||
|
||||
@ -62,6 +62,9 @@ public class ServiceOfferingResponse extends BaseResponse {
|
||||
@Param(description = "the storage type for this service offering")
|
||||
private String storageType;
|
||||
|
||||
@SerializedName("provisioningtype") @Param(description="provisioning type used to create volumes. Valid values are thin, sparse, fat.", since = "4.4.0")
|
||||
private String provisioningType;
|
||||
|
||||
@SerializedName("offerha")
|
||||
@Param(description = "the ha support in the service offering")
|
||||
private Boolean offerHa;
|
||||
@ -241,6 +244,14 @@ public class ServiceOfferingResponse extends BaseResponse {
|
||||
this.storageType = storageType;
|
||||
}
|
||||
|
||||
public String getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
public void setProvisioningType(String provisioningType){
|
||||
this.provisioningType = provisioningType;
|
||||
}
|
||||
|
||||
public Boolean getOfferHa() {
|
||||
return offerHa;
|
||||
}
|
||||
|
||||
@ -72,6 +72,10 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity
|
||||
@Param(description = "state of the virtual machine")
|
||||
private String virtualMachineState;
|
||||
|
||||
@SerializedName(ApiConstants.PROVISIONINGTYPE)
|
||||
@Param(description = "provisioning type used to create volumes.")
|
||||
private String provisioningType;
|
||||
|
||||
@SerializedName(ApiConstants.SIZE)
|
||||
@Param(description = "size of the disk volume")
|
||||
private Long size;
|
||||
@ -278,6 +282,10 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity
|
||||
this.virtualMachineState = virtualMachineState;
|
||||
}
|
||||
|
||||
public void setProvisioningType(String provisioningType){
|
||||
this.provisioningType = provisioningType;
|
||||
}
|
||||
|
||||
public void setSize(Long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@ -529,6 +529,7 @@ label.disk.bytes.write.rate=Disk Write Rate (BPS)
|
||||
label.disk.iops.read.rate=Disk Read Rate (IOPS)
|
||||
label.disk.iops.write.rate=Disk Write Rate (IOPS)
|
||||
label.disk.offering=Disk Offering
|
||||
label.disk.provisioningtype=Provisioning Type
|
||||
label.disk.read.bytes=Disk Read (Bytes)
|
||||
label.disk.read.io=Disk Read (IO)
|
||||
label.disk.size.gb=Disk Size (in GB)
|
||||
|
||||
@ -38,6 +38,7 @@ public class VolumeObjectTO implements DataTO {
|
||||
private long accountId;
|
||||
private String chainInfo;
|
||||
private Storage.ImageFormat format;
|
||||
private Storage.ProvisioningType provisioningType;
|
||||
private long id;
|
||||
|
||||
private Long deviceId;
|
||||
@ -69,6 +70,7 @@ public class VolumeObjectTO implements DataTO {
|
||||
name = volume.getName();
|
||||
setId(volume.getId());
|
||||
format = volume.getFormat();
|
||||
provisioningType = volume.getProvisioningType();
|
||||
bytesReadRate = volume.getBytesReadRate();
|
||||
bytesWriteRate = volume.getBytesWriteRate();
|
||||
iopsReadRate = volume.getIopsReadRate();
|
||||
@ -187,6 +189,14 @@ public class VolumeObjectTO implements DataTO {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public Storage.ProvisioningType getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
public void setProvisioningType(Storage.ProvisioningType provisioningType){
|
||||
this.provisioningType = provisioningType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("volumeTO[uuid=").append(uuid).append("|path=").append(path).append("|datastore=").append(dataStore).append("]").toString();
|
||||
|
||||
@ -209,8 +209,17 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
||||
}
|
||||
|
||||
public VolumeVO allocateDuplicateVolumeVO(Volume oldVol, Long templateId) {
|
||||
VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), oldVol.getDiskOfferingId(),
|
||||
oldVol.getSize(), oldVol.getMinIops(), oldVol.getMaxIops(), oldVol.get_iScsiName());
|
||||
VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(),
|
||||
oldVol.getName(),
|
||||
oldVol.getDataCenterId(),
|
||||
oldVol.getDomainId(),
|
||||
oldVol.getAccountId(),
|
||||
oldVol.getDiskOfferingId(),
|
||||
oldVol.getProvisioningType(),
|
||||
oldVol.getSize(),
|
||||
oldVol.getMinIops(),
|
||||
oldVol.getMaxIops(),
|
||||
oldVol.get_iScsiName());
|
||||
if (templateId != null) {
|
||||
newVol.setTemplateId(templateId);
|
||||
} else {
|
||||
@ -584,7 +593,17 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
||||
minIops = minIops != null ? minIops : offering.getMinIops();
|
||||
maxIops = maxIops != null ? maxIops : offering.getMaxIops();
|
||||
|
||||
VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size, minIops, maxIops, null);
|
||||
VolumeVO vol = new VolumeVO(type,
|
||||
name,
|
||||
vm.getDataCenterId(),
|
||||
owner.getDomainId(),
|
||||
owner.getId(),
|
||||
offering.getId(),
|
||||
offering.getProvisioningType(),
|
||||
size,
|
||||
minIops,
|
||||
maxIops,
|
||||
null);
|
||||
if (vm != null) {
|
||||
vol.setInstanceId(vm.getId());
|
||||
}
|
||||
@ -635,8 +654,17 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
||||
minIops = minIops != null ? minIops : offering.getMinIops();
|
||||
maxIops = maxIops != null ? maxIops : offering.getMaxIops();
|
||||
|
||||
VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size, minIops, maxIops, null);
|
||||
|
||||
VolumeVO vol = new VolumeVO(type,
|
||||
name,
|
||||
vm.getDataCenterId(),
|
||||
owner.getDomainId(),
|
||||
owner.getId(),
|
||||
offering.getId(),
|
||||
offering.getProvisioningType(),
|
||||
size,
|
||||
minIops,
|
||||
maxIops,
|
||||
null);
|
||||
vol.setFormat(getSupportedImageFormatForCluster(template.getHypervisorType()));
|
||||
if (vm != null) {
|
||||
vol.setInstanceId(vm.getId());
|
||||
|
||||
@ -83,16 +83,17 @@ import com.cloud.hypervisor.HypervisorGuru;
|
||||
import com.cloud.hypervisor.HypervisorGuruManager;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.StoragePoolHostVO;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.StoragePoolHostVO;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.UserVO;
|
||||
@ -310,7 +311,7 @@ public class VirtualMachineManagerImplTest {
|
||||
boolean useLocalStorage = false;
|
||||
|
||||
ServiceOfferingVO serviceOffering =
|
||||
new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, ha, displayText, useLocalStorage, false, null, false, null, false);
|
||||
new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, ha, displayText, ProvisioningType.THIN, useLocalStorage, false, null, false, null, false);
|
||||
return serviceOffering;
|
||||
}
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ import javax.persistence.Transient;
|
||||
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
|
||||
@Entity
|
||||
@ -89,8 +90,8 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
||||
}
|
||||
|
||||
public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, String displayText,
|
||||
boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) {
|
||||
super(name, displayText, false, tags, recreatable, useLocalStorage, systemUse, true);
|
||||
ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) {
|
||||
super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true);
|
||||
this.cpu = cpu;
|
||||
this.ramSize = ramSize;
|
||||
this.speed = speed;
|
||||
@ -104,9 +105,8 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
||||
}
|
||||
|
||||
public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse,
|
||||
boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType,
|
||||
Long domainId) {
|
||||
super(name, displayText, false, tags, recreatable, useLocalStorage, systemUse, true, domainId);
|
||||
boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, Long domainId) {
|
||||
super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true, domainId);
|
||||
this.cpu = cpu;
|
||||
this.ramSize = ramSize;
|
||||
this.speed = speed;
|
||||
@ -119,7 +119,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
||||
}
|
||||
|
||||
public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA,
|
||||
boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse,
|
||||
boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse,
|
||||
VirtualMachine.Type vmType, Long domainId, String hostTag) {
|
||||
this(name,
|
||||
cpu,
|
||||
@ -131,6 +131,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
||||
limitResourceUse,
|
||||
volatileVm,
|
||||
displayText,
|
||||
provisioningType,
|
||||
useLocalStorage,
|
||||
recreatable,
|
||||
tags,
|
||||
@ -141,7 +142,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
||||
}
|
||||
|
||||
public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA,
|
||||
boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse,
|
||||
boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse,
|
||||
VirtualMachine.Type vmType, Long domainId, String hostTag, String deploymentPlanner) {
|
||||
this(name,
|
||||
cpu,
|
||||
@ -153,6 +154,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
||||
limitResourceUse,
|
||||
volatileVm,
|
||||
displayText,
|
||||
provisioningType,
|
||||
useLocalStorage,
|
||||
recreatable,
|
||||
tags,
|
||||
@ -167,6 +169,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
|
||||
super(offering.getId(),
|
||||
offering.getName(),
|
||||
offering.getDisplayText(),
|
||||
offering.getProvisioningType(),
|
||||
false,
|
||||
offering.getTags(),
|
||||
offering.isRecreatable(),
|
||||
|
||||
@ -124,7 +124,10 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
private DiskCacheMode cacheMode;
|
||||
|
||||
@Column(name = "display_offering")
|
||||
@Column(name="provisioning_type")
|
||||
Storage.ProvisioningType provisioningType;
|
||||
|
||||
@Column(name="display_offering")
|
||||
boolean displayOffering = true;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@ -138,11 +141,12 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags, boolean isCustomized,
|
||||
public DiskOfferingVO(Long domainId, String name, String displayText, Storage.ProvisioningType provisioningType, long diskSize, String tags, boolean isCustomized,
|
||||
Boolean isCustomizedIops, Long minIops, Long maxIops, DiskCacheMode cacheMode) {
|
||||
this.domainId = domainId;
|
||||
this.name = name;
|
||||
this.displayText = displayText;
|
||||
this.provisioningType = provisioningType;
|
||||
this.diskSize = diskSize;
|
||||
this.tags = tags;
|
||||
recreatable = false;
|
||||
@ -156,11 +160,12 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
this.cacheMode = cacheMode;
|
||||
}
|
||||
|
||||
public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags, boolean isCustomized,
|
||||
public DiskOfferingVO(Long domainId, String name, String displayText, Storage.ProvisioningType provisioningType, long diskSize, String tags, boolean isCustomized,
|
||||
Boolean isCustomizedIops, Long minIops, Long maxIops) {
|
||||
this.domainId = domainId;
|
||||
this.name = name;
|
||||
this.displayText = displayText;
|
||||
this.provisioningType = provisioningType;
|
||||
this.diskSize = diskSize;
|
||||
this.tags = tags;
|
||||
recreatable = false;
|
||||
@ -174,12 +179,13 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
state = State.Active;
|
||||
}
|
||||
|
||||
public DiskOfferingVO(String name, String displayText, boolean mirrored, String tags, boolean recreatable, boolean useLocalStorage, boolean systemUse,
|
||||
boolean customized) {
|
||||
public DiskOfferingVO(String name, String displayText, Storage.ProvisioningType provisioningType, boolean mirrored, String tags, boolean recreatable,
|
||||
boolean useLocalStorage, boolean systemUse, boolean customized) {
|
||||
domainId = null;
|
||||
type = Type.Service;
|
||||
this.name = name;
|
||||
this.displayText = displayText;
|
||||
this.provisioningType = provisioningType;
|
||||
this.tags = tags;
|
||||
this.recreatable = recreatable;
|
||||
this.useLocalStorage = useLocalStorage;
|
||||
@ -191,11 +197,12 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
|
||||
// domain specific offerings constructor (null domainId implies public
|
||||
// offering)
|
||||
public DiskOfferingVO(String name, String displayText, boolean mirrored, String tags, boolean recreatable, boolean useLocalStorage, boolean systemUse,
|
||||
boolean customized, Long domainId) {
|
||||
public DiskOfferingVO(String name, String displayText, Storage.ProvisioningType provisioningType, boolean mirrored, String tags, boolean recreatable,
|
||||
boolean useLocalStorage, boolean systemUse, boolean customized, Long domainId) {
|
||||
type = Type.Service;
|
||||
this.name = name;
|
||||
this.displayText = displayText;
|
||||
this.provisioningType = provisioningType;
|
||||
this.tags = tags;
|
||||
this.recreatable = recreatable;
|
||||
this.useLocalStorage = useLocalStorage;
|
||||
@ -206,12 +213,13 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
state = State.Active;
|
||||
}
|
||||
|
||||
public DiskOfferingVO(long id, String name, String displayText, boolean mirrored, String tags, boolean recreatable,
|
||||
public DiskOfferingVO(long id, String name, String displayText, Storage.ProvisioningType provisioningType, boolean mirrored, String tags, boolean recreatable,
|
||||
boolean useLocalStorage, boolean systemUse, boolean customized, boolean customizedIops, Long domainId) {
|
||||
this.id = id;
|
||||
type = Type.Service;
|
||||
this.name = name;
|
||||
this.displayText = displayText;
|
||||
this.provisioningType = provisioningType;
|
||||
this.tags = tags;
|
||||
this.recreatable = recreatable;
|
||||
this.useLocalStorage = useLocalStorage;
|
||||
@ -341,6 +349,11 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
this.displayText = displayText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Storage.ProvisioningType getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDiskSize() {
|
||||
return diskSize;
|
||||
|
||||
@ -32,6 +32,7 @@ import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
@ -143,6 +144,9 @@ public class VolumeVO implements Volume {
|
||||
@Column(name = "format")
|
||||
private Storage.ImageFormat format;
|
||||
|
||||
@Column(name = "provisioning_type")
|
||||
private Storage.ProvisioningType provisioningType;
|
||||
|
||||
@Column(name = "display_volume", updatable = true, nullable = false)
|
||||
protected boolean displayVolume = true;
|
||||
|
||||
@ -163,12 +167,15 @@ public class VolumeVO implements Volume {
|
||||
Integer hypervisorSnapshotReserve;
|
||||
|
||||
// Real Constructor
|
||||
public VolumeVO(Type type, String name, long dcId, long domainId, long accountId, long diskOfferingId, long size, Long minIops, Long maxIops, String iScsiName) {
|
||||
volumeType = type;
|
||||
public VolumeVO(Type type, String name, long dcId, long domainId,
|
||||
long accountId, long diskOfferingId, Storage.ProvisioningType provisioningType, long size,
|
||||
Long minIops, Long maxIops, String iScsiName) {
|
||||
this.volumeType = type;
|
||||
this.name = name;
|
||||
dataCenterId = dcId;
|
||||
this.accountId = accountId;
|
||||
this.domainId = domainId;
|
||||
this.provisioningType = provisioningType;
|
||||
this.size = size;
|
||||
this.minIops = minIops;
|
||||
this.maxIops = maxIops;
|
||||
@ -178,14 +185,17 @@ public class VolumeVO implements Volume {
|
||||
uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public VolumeVO(String name, long dcId, Long podId, long accountId, long domainId, Long instanceId, String folder, String path, long size, Long minIops,
|
||||
Long maxIops, String iScsiName, Volume.Type vType) {
|
||||
public VolumeVO(String name, long dcId, Long podId, long accountId,
|
||||
long domainId, Long instanceId, String folder, String path, Storage.ProvisioningType provisioningType,
|
||||
long size, Long minIops, Long maxIops, String iScsiName,
|
||||
Volume.Type vType) {
|
||||
this.name = name;
|
||||
this.accountId = accountId;
|
||||
this.domainId = domainId;
|
||||
this.instanceId = instanceId;
|
||||
this.folder = folder;
|
||||
this.path = path;
|
||||
this.provisioningType = provisioningType;
|
||||
this.size = size;
|
||||
this.minIops = minIops;
|
||||
this.maxIops = maxIops;
|
||||
@ -198,13 +208,16 @@ public class VolumeVO implements Volume {
|
||||
uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public VolumeVO(String name, long dcId, long podId, long accountId, long domainId, Long instanceId, String folder, String path, long size, Volume.Type vType) {
|
||||
public VolumeVO(String name, long dcId, long podId, long accountId,
|
||||
long domainId, Long instanceId, String folder, String path, Storage.ProvisioningType provisioningType,
|
||||
long size, Volume.Type vType) {
|
||||
this.name = name;
|
||||
this.accountId = accountId;
|
||||
this.domainId = domainId;
|
||||
this.instanceId = instanceId;
|
||||
this.folder = folder;
|
||||
this.path = path;
|
||||
this.provisioningType = provisioningType;
|
||||
this.size = size;
|
||||
minIops = null;
|
||||
maxIops = null;
|
||||
@ -227,6 +240,7 @@ public class VolumeVO implements Volume {
|
||||
that.getInstanceId(),
|
||||
that.getFolder(),
|
||||
that.getPath(),
|
||||
that.getProvisioningType(),
|
||||
that.getSize(),
|
||||
that.getMinIops(),
|
||||
that.getMaxIops(),
|
||||
@ -245,6 +259,7 @@ public class VolumeVO implements Volume {
|
||||
templateId = that.getTemplateId();
|
||||
deviceId = that.getDeviceId();
|
||||
format = that.getFormat();
|
||||
provisioningType = that.getProvisioningType();
|
||||
uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
@ -565,7 +580,16 @@ public class VolumeVO implements Volume {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public void setVmSnapshotChainSize(Long vmSnapshotChainSize) {
|
||||
@Override
|
||||
public ProvisioningType getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
public void setProvisioningType(ProvisioningType provisioningType){
|
||||
this.provisioningType = provisioningType;
|
||||
}
|
||||
|
||||
public void setVmSnapshotChainSize(Long vmSnapshotChainSize){
|
||||
this.vmSnapshotChainSize = vmSnapshotChainSize;
|
||||
}
|
||||
|
||||
|
||||
@ -42,6 +42,7 @@ import com.cloud.offering.DiskOffering.DiskCacheMode;
|
||||
import com.cloud.storage.DataStoreRole;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
@ -655,6 +656,11 @@ public class VolumeObject implements VolumeInfo {
|
||||
return volumeVO.getFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProvisioningType getProvisioningType(){
|
||||
return this.volumeVO.getProvisioningType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
if (dataStore != null) {
|
||||
|
||||
@ -1735,13 +1735,14 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||
vol = templateToPrimaryDownload(cmd.getTemplateUrl(), primaryPool, dskch.getPath());
|
||||
} else {
|
||||
BaseVol = primaryPool.getPhysicalDisk(cmd.getTemplateUrl());
|
||||
vol = _storagePoolMgr.createDiskFromTemplate(BaseVol, dskch.getPath(), primaryPool, 0);
|
||||
vol = _storagePoolMgr.createDiskFromTemplate(BaseVol,
|
||||
dskch.getPath(), dskch.getProvisioningType(), primaryPool, 0);
|
||||
}
|
||||
if (vol == null) {
|
||||
return new Answer(cmd, false, " Can't create storage volume on storage pool");
|
||||
}
|
||||
} else {
|
||||
vol = primaryPool.createPhysicalDisk(dskch.getPath(), dskch.getSize());
|
||||
vol = primaryPool.createPhysicalDisk(dskch.getPath(), dskch.getProvisioningType(), dskch.getSize());
|
||||
}
|
||||
VolumeTO volume =
|
||||
new VolumeTO(cmd.getVolumeId(), dskch.getType(), pool.getType(), pool.getUuid(), pool.getPath(), vol.getName(), vol.getName(), disksize, null);
|
||||
|
||||
@ -16,6 +16,9 @@
|
||||
// under the License.
|
||||
package com.cloud.hypervisor.kvm.resource;
|
||||
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
public class LibvirtStorageVolumeDef {
|
||||
public enum volFormat {
|
||||
RAW("raw"), QCOW2("qcow2"), DIR("dir"), TAR("tar");
|
||||
@ -45,6 +48,21 @@ public class LibvirtStorageVolumeDef {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static volFormat getFormat(QemuImg.PhysicalDiskFormat format){
|
||||
switch (format){
|
||||
case RAW:
|
||||
return RAW;
|
||||
case QCOW2:
|
||||
return QCOW2;
|
||||
case DIR:
|
||||
return DIR;
|
||||
case TAR:
|
||||
return TAR;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String _volName;
|
||||
|
||||
@ -20,11 +20,13 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||
|
||||
import com.cloud.agent.api.to.DiskTO;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.utils.StringUtils;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
@ -63,7 +65,7 @@ public class IscsiAdmStorageAdaptor implements StorageAdaptor {
|
||||
// called from LibvirtComputingResource.execute(CreateCommand)
|
||||
// does not apply for iScsiAdmStorageAdaptor
|
||||
@Override
|
||||
public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, KVMStoragePool pool, PhysicalDiskFormat format, long size) {
|
||||
public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, KVMStoragePool pool, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size) {
|
||||
throw new UnsupportedOperationException("Creating a physical disk is not supported.");
|
||||
}
|
||||
|
||||
@ -336,7 +338,9 @@ public class IscsiAdmStorageAdaptor implements StorageAdaptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool, int timeout) {
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, PhysicalDiskFormat format,
|
||||
ProvisioningType provisioningType, long size,
|
||||
KVMStoragePool destPool, int timeout) {
|
||||
throw new UnsupportedOperationException("Creating a disk from a template is not yet supported for this configuration.");
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ package com.cloud.hypervisor.kvm.storage;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
@ -86,7 +87,7 @@ public class IscsiAdmStoragePool implements KVMStoragePool {
|
||||
// from LibvirtComputingResource.createDiskFromTemplate(KVMPhysicalDisk, String, PhysicalDiskFormat, long, KVMStoragePool)
|
||||
// does not apply for iScsiAdmStoragePool
|
||||
@Override
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, PhysicalDiskFormat format, long size) {
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size) {
|
||||
throw new UnsupportedOperationException("Creating a physical disk is not supported.");
|
||||
}
|
||||
|
||||
@ -94,7 +95,7 @@ public class IscsiAdmStoragePool implements KVMStoragePool {
|
||||
// from KVMStorageProcessor.createVolume(CreateObjectCommand)
|
||||
// does not apply for iScsiAdmStoragePool
|
||||
@Override
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, long size) {
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, Storage.ProvisioningType provisioningType, long size) {
|
||||
throw new UnsupportedOperationException("Creating a physical disk is not supported.");
|
||||
}
|
||||
|
||||
|
||||
@ -19,14 +19,15 @@ package com.cloud.hypervisor.kvm.storage;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
|
||||
public interface KVMStoragePool {
|
||||
public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, PhysicalDiskFormat format, long size);
|
||||
public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size);
|
||||
|
||||
public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, long size);
|
||||
public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, Storage.ProvisioningType provisioningType, long size);
|
||||
|
||||
public boolean connectPhysicalDisk(String volumeUuid, Map<String, String> details);
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@ import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.hypervisor.kvm.resource.KVMHABase;
|
||||
import com.cloud.hypervisor.kvm.resource.KVMHABase.PoolType;
|
||||
import com.cloud.hypervisor.kvm.resource.KVMHAMonitor;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.StorageLayer;
|
||||
import com.cloud.storage.Volume;
|
||||
@ -301,22 +302,32 @@ public class KVMStoragePoolManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, KVMStoragePool destPool, int timeout) {
|
||||
return createDiskFromTemplate(template, name, destPool, template.getSize(), timeout);
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, Storage.ProvisioningType provisioningType,
|
||||
KVMStoragePool destPool, int timeout) {
|
||||
return createDiskFromTemplate(template, name, provisioningType, destPool, template.getSize(), timeout);
|
||||
}
|
||||
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, KVMStoragePool destPool, long size, int timeout) {
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, Storage.ProvisioningType provisioningType,
|
||||
KVMStoragePool destPool, long size, int timeout) {
|
||||
StorageAdaptor adaptor = getStorageAdaptor(destPool.getType());
|
||||
|
||||
// LibvirtStorageAdaptor-specific statement
|
||||
if (destPool.getType() == StoragePoolType.RBD) {
|
||||
return adaptor.createDiskFromTemplate(template, name, PhysicalDiskFormat.RAW, size, destPool, timeout);
|
||||
return adaptor.createDiskFromTemplate(template, name,
|
||||
PhysicalDiskFormat.RAW, provisioningType,
|
||||
size, destPool, timeout);
|
||||
} else if (destPool.getType() == StoragePoolType.CLVM) {
|
||||
return adaptor.createDiskFromTemplate(template, name, PhysicalDiskFormat.RAW, size, destPool, timeout);
|
||||
return adaptor.createDiskFromTemplate(template, name,
|
||||
PhysicalDiskFormat.RAW, provisioningType,
|
||||
size, destPool, timeout);
|
||||
} else if (template.getFormat() == PhysicalDiskFormat.DIR) {
|
||||
return adaptor.createDiskFromTemplate(template, name, PhysicalDiskFormat.DIR, size, destPool, timeout);
|
||||
return adaptor.createDiskFromTemplate(template, name,
|
||||
PhysicalDiskFormat.DIR, provisioningType,
|
||||
size, destPool, timeout);
|
||||
} else {
|
||||
return adaptor.createDiskFromTemplate(template, name, PhysicalDiskFormat.QCOW2, size, destPool, timeout);
|
||||
return adaptor.createDiskFromTemplate(template, name,
|
||||
PhysicalDiskFormat.QCOW2, provisioningType,
|
||||
size, destPool, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -335,7 +335,8 @@ public class KVMStorageProcessor implements StorageProcessor {
|
||||
templatePath = templatePath.substring(templatePath.lastIndexOf(File.separator) + 1);
|
||||
}
|
||||
BaseVol = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), templatePath);
|
||||
vol = storagePoolMgr.createDiskFromTemplate(BaseVol, volume.getUuid(), BaseVol.getPool(), volume.getSize(), cmd.getWaitInMillSeconds());
|
||||
vol = storagePoolMgr.createDiskFromTemplate(BaseVol, volume.getUuid(), volume.getProvisioningType(),
|
||||
BaseVol.getPool(), volume.getSize(), cmd.getWaitInMillSeconds());
|
||||
}
|
||||
if (vol == null) {
|
||||
return new CopyCmdAnswer(" Can't create storage volume on storage pool");
|
||||
@ -1074,7 +1075,7 @@ public class KVMStorageProcessor implements StorageProcessor {
|
||||
primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
|
||||
disksize = volume.getSize();
|
||||
|
||||
vol = primaryPool.createPhysicalDisk(volume.getUuid(), disksize);
|
||||
vol = primaryPool.createPhysicalDisk(volume.getUuid(), volume.getProvisioningType(), disksize);
|
||||
|
||||
VolumeObjectTO newVol = new VolumeObjectTO();
|
||||
newVol.setPath(vol.getName());
|
||||
|
||||
@ -21,6 +21,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.log4j.Logger;
|
||||
@ -55,6 +57,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolXMLParser;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtStorageVolumeDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtStorageVolumeDef.volFormat;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtStorageVolumeXMLParser;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.StorageLayer;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
@ -614,16 +617,103 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, PhysicalDiskFormat format, long size) {
|
||||
LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool;
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool,
|
||||
PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size) {
|
||||
|
||||
switch (pool.getType()){
|
||||
case RBD:
|
||||
return createPhysicalDiskOnRBD(name, pool, format, provisioningType, size);
|
||||
case NetworkFilesystem:
|
||||
case Filesystem:
|
||||
switch (format){
|
||||
case QCOW2:
|
||||
return createPhysicalDiskByQemuImg(name, pool, format, provisioningType, size);
|
||||
case RAW:
|
||||
return createPhysicalDiskByQemuImg(name, pool, format, provisioningType, size);
|
||||
case DIR:
|
||||
return createPhysicalDiskByLibVirt(name, pool, format, provisioningType, size);
|
||||
case TAR:
|
||||
return createPhysicalDiskByLibVirt(name, pool, format, provisioningType, size);
|
||||
default:
|
||||
throw new CloudRuntimeException("Unexpected disk format is specified.");
|
||||
}
|
||||
default:
|
||||
return createPhysicalDiskByLibVirt(name, pool, format, provisioningType, size);
|
||||
}
|
||||
}
|
||||
|
||||
private KVMPhysicalDisk createPhysicalDiskByLibVirt(String name, KVMStoragePool pool,
|
||||
PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size) {
|
||||
LibvirtStoragePool libvirtPool = (LibvirtStoragePool) pool;
|
||||
StoragePool virtPool = libvirtPool.getPool();
|
||||
LibvirtStorageVolumeDef.volFormat libvirtformat = null;
|
||||
LibvirtStorageVolumeDef.volFormat libvirtformat = LibvirtStorageVolumeDef.volFormat.getFormat(format);
|
||||
|
||||
String volPath = null;
|
||||
String volName = null;
|
||||
long volAllocation = 0;
|
||||
long volCapacity = 0;
|
||||
|
||||
LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(name,
|
||||
size, libvirtformat, null, null);
|
||||
s_logger.debug(volDef.toString());
|
||||
try {
|
||||
StorageVol vol = virtPool.storageVolCreateXML(volDef.toString(), 0);
|
||||
volPath = vol.getPath();
|
||||
volName = vol.getName();
|
||||
volAllocation = vol.getInfo().allocation;
|
||||
volCapacity = vol.getInfo().capacity;
|
||||
} catch (LibvirtException e) {
|
||||
throw new CloudRuntimeException(e.toString());
|
||||
}
|
||||
|
||||
KVMPhysicalDisk disk = new KVMPhysicalDisk(volPath, volName, pool);
|
||||
disk.setFormat(format);
|
||||
disk.setSize(volAllocation);
|
||||
disk.setVirtualSize(volCapacity);
|
||||
return disk;
|
||||
}
|
||||
|
||||
|
||||
private KVMPhysicalDisk createPhysicalDiskByQemuImg(String name, KVMStoragePool pool,
|
||||
PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size) {
|
||||
String volPath = pool.getLocalPath() + "/" + name;
|
||||
String volName = name;
|
||||
long volAllocation = 0;
|
||||
long volCapacity = 0;
|
||||
|
||||
final int timeout = 0;
|
||||
|
||||
QemuImgFile destFile = new QemuImgFile(volPath);
|
||||
destFile.setFormat(format);
|
||||
destFile.setSize(size);
|
||||
QemuImg qemu = new QemuImg(timeout);
|
||||
Map<String, String> options = new HashMap<String, String>();
|
||||
if (pool.getType() == StoragePoolType.NetworkFilesystem){
|
||||
options.put("preallocation", QemuImg.PreallocationType.getPreallocationType(provisioningType).toString());
|
||||
}
|
||||
|
||||
try{
|
||||
qemu.create(destFile, options);
|
||||
Map<String, String> info = qemu.info(destFile);
|
||||
volAllocation = Long.parseLong(info.get(new String("virtual-size")));
|
||||
volCapacity = Long.parseLong(info.get(new String("actual-size")));
|
||||
} catch (QemuImgException e) {
|
||||
s_logger.error("Failed to create " + volPath +
|
||||
" due to a failed executing of qemu-img: " + e.getMessage());
|
||||
}
|
||||
|
||||
KVMPhysicalDisk disk = new KVMPhysicalDisk(volPath, volName, pool);
|
||||
disk.setFormat(format);
|
||||
disk.setSize(volAllocation);
|
||||
disk.setVirtualSize(volCapacity);
|
||||
return disk;
|
||||
}
|
||||
|
||||
private KVMPhysicalDisk createPhysicalDiskOnRBD(String name, KVMStoragePool pool,
|
||||
PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size) {
|
||||
LibvirtStoragePool libvirtPool = (LibvirtStoragePool) pool;
|
||||
String volPath = null;
|
||||
|
||||
/**
|
||||
* To have RBD function properly we want RBD images of format 2
|
||||
* libvirt currently defaults to format 1
|
||||
@ -631,63 +721,34 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
* For that reason we use the native RBD bindings to create the
|
||||
* RBD image until libvirt creates RBD format 2 by default
|
||||
*/
|
||||
if (pool.getType() == StoragePoolType.RBD) {
|
||||
format = PhysicalDiskFormat.RAW;
|
||||
format = PhysicalDiskFormat.RAW;
|
||||
|
||||
try {
|
||||
s_logger.info("Creating RBD image " + pool.getSourceDir() + "/" + name + " with size " + size);
|
||||
try {
|
||||
s_logger.info("Creating RBD image " + pool.getSourceDir() + "/" + name + " with size " + size);
|
||||
|
||||
Rados r = new Rados(pool.getAuthUserName());
|
||||
r.confSet("mon_host", pool.getSourceHost() + ":" + pool.getSourcePort());
|
||||
r.confSet("key", pool.getAuthSecret());
|
||||
r.confSet("client_mount_timeout", "30");
|
||||
r.connect();
|
||||
s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
|
||||
Rados r = new Rados(pool.getAuthUserName());
|
||||
r.confSet("mon_host", pool.getSourceHost() + ":" + pool.getSourcePort());
|
||||
r.confSet("key", pool.getAuthSecret());
|
||||
r.confSet("client_mount_timeout", "30");
|
||||
r.connect();
|
||||
s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
|
||||
|
||||
IoCTX io = r.ioCtxCreate(pool.getSourceDir());
|
||||
Rbd rbd = new Rbd(io);
|
||||
rbd.create(name, size, rbdFeatures, rbdOrder);
|
||||
IoCTX io = r.ioCtxCreate(pool.getSourceDir());
|
||||
Rbd rbd = new Rbd(io);
|
||||
rbd.create(name, size, this.rbdFeatures, this.rbdOrder);
|
||||
|
||||
r.ioCtxDestroy(io);
|
||||
} catch (RadosException e) {
|
||||
throw new CloudRuntimeException(e.toString());
|
||||
} catch (RbdException e) {
|
||||
throw new CloudRuntimeException(e.toString());
|
||||
}
|
||||
|
||||
volPath = pool.getSourceDir() + "/" + name;
|
||||
volName = name;
|
||||
volCapacity = size;
|
||||
volAllocation = size;
|
||||
} else {
|
||||
|
||||
if (format == PhysicalDiskFormat.QCOW2) {
|
||||
libvirtformat = LibvirtStorageVolumeDef.volFormat.QCOW2;
|
||||
} else if (format == PhysicalDiskFormat.RAW) {
|
||||
libvirtformat = LibvirtStorageVolumeDef.volFormat.RAW;
|
||||
} else if (format == PhysicalDiskFormat.DIR) {
|
||||
libvirtformat = LibvirtStorageVolumeDef.volFormat.DIR;
|
||||
} else if (format == PhysicalDiskFormat.TAR) {
|
||||
libvirtformat = LibvirtStorageVolumeDef.volFormat.TAR;
|
||||
}
|
||||
|
||||
LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(name, size, libvirtformat, null, null);
|
||||
s_logger.debug(volDef.toString());
|
||||
try {
|
||||
StorageVol vol = virtPool.storageVolCreateXML(volDef.toString(), 0);
|
||||
volPath = vol.getPath();
|
||||
volName = vol.getName();
|
||||
volAllocation = vol.getInfo().allocation;
|
||||
volCapacity = vol.getInfo().capacity;
|
||||
} catch (LibvirtException e) {
|
||||
throw new CloudRuntimeException(e.toString());
|
||||
}
|
||||
r.ioCtxDestroy(io);
|
||||
} catch (RadosException e) {
|
||||
throw new CloudRuntimeException(e.toString());
|
||||
} catch (RbdException e) {
|
||||
throw new CloudRuntimeException(e.toString());
|
||||
}
|
||||
|
||||
KVMPhysicalDisk disk = new KVMPhysicalDisk(volPath, volName, pool);
|
||||
volPath = pool.getSourceDir() + "/" + name;
|
||||
KVMPhysicalDisk disk = new KVMPhysicalDisk(volPath, name, pool);
|
||||
disk.setFormat(format);
|
||||
disk.setSize(volAllocation);
|
||||
disk.setVirtualSize(volCapacity);
|
||||
disk.setSize(size);
|
||||
disk.setVirtualSize(size);
|
||||
return disk;
|
||||
}
|
||||
|
||||
@ -806,38 +867,44 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
* If it has been created on Primary Storage, it will be copied on the Primary Storage
|
||||
*/
|
||||
@Override
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool, int timeout) {
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template,
|
||||
String name, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, KVMStoragePool destPool, int timeout) {
|
||||
|
||||
String newUuid = name;
|
||||
KVMStoragePool srcPool = template.getPool();
|
||||
KVMPhysicalDisk disk = null;
|
||||
|
||||
/*
|
||||
With RBD you can't run qemu-img convert with an existing RBD image as destination
|
||||
qemu-img will exit with the error that the destination already exists.
|
||||
So for RBD we don't create the image, but let qemu-img do that for us.
|
||||
|
||||
We then create a KVMPhysicalDisk object that we can return
|
||||
*/
|
||||
try {
|
||||
if (destPool.getType() != StoragePoolType.RBD) {
|
||||
disk = destPool.createPhysicalDisk(newUuid, format, template.getVirtualSize());
|
||||
if (destPool.getType() == StoragePoolType.RBD) {
|
||||
disk = createDiskFromTemplateOnRBD(template, name, format, provisioningType, size, destPool, timeout);
|
||||
} else {
|
||||
try {
|
||||
String newUuid = name;
|
||||
disk = destPool.createPhysicalDisk(newUuid, format, provisioningType, template.getVirtualSize());
|
||||
if (template.getFormat() == PhysicalDiskFormat.TAR) {
|
||||
Script.runSimpleBashScript("tar -x -f " + template.getPath() + " -C " + disk.getPath(), timeout);
|
||||
Script.runSimpleBashScript("tar -x -f " + template.getPath() + " -C " + disk.getPath(), timeout); // TO BE FIXED to aware provisioningType
|
||||
} else if (template.getFormat() == PhysicalDiskFormat.DIR) {
|
||||
Script.runSimpleBashScript("mkdir -p " + disk.getPath());
|
||||
Script.runSimpleBashScript("chmod 755 " + disk.getPath());
|
||||
Script.runSimpleBashScript("cp -p -r " + template.getPath() + "/* " + disk.getPath(), timeout);
|
||||
Script.runSimpleBashScript("cp -p -r " + template.getPath() + "/* " + disk.getPath(), timeout); // TO BE FIXED to aware provisioningType
|
||||
} else if (format == PhysicalDiskFormat.QCOW2) {
|
||||
QemuImgFile backingFile = new QemuImgFile(template.getPath(), template.getFormat());
|
||||
QemuImgFile destFile = new QemuImgFile(disk.getPath());
|
||||
QemuImg qemu = new QemuImg(timeout);
|
||||
QemuImgFile destFile = new QemuImgFile(disk.getPath(), format);
|
||||
if (size > template.getVirtualSize()) {
|
||||
destFile.setSize(size);
|
||||
} else {
|
||||
destFile.setSize(template.getVirtualSize());
|
||||
}
|
||||
QemuImg qemu = new QemuImg(timeout);
|
||||
qemu.create(destFile, backingFile);
|
||||
Map<String, String> options = new HashMap<String, String>();
|
||||
options.put("preallocation", QemuImg.PreallocationType.getPreallocationType(provisioningType).toString());
|
||||
switch(provisioningType){
|
||||
case THIN:
|
||||
QemuImgFile backingFile = new QemuImgFile(template.getPath(), template.getFormat());
|
||||
qemu.create(destFile, backingFile, options);
|
||||
break;
|
||||
case SPARSE:
|
||||
case FAT:
|
||||
QemuImgFile srcFile = new QemuImgFile(template.getPath(), template.getFormat());
|
||||
qemu.convert(srcFile, destFile, options);
|
||||
break;
|
||||
}
|
||||
} else if (format == PhysicalDiskFormat.RAW) {
|
||||
QemuImgFile sourceFile = new QemuImgFile(template.getPath(), template.getFormat());
|
||||
QemuImgFile destFile = new QemuImgFile(disk.getPath(), PhysicalDiskFormat.RAW);
|
||||
@ -847,137 +914,13 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
destFile.setSize(template.getVirtualSize());
|
||||
}
|
||||
QemuImg qemu = new QemuImg(timeout);
|
||||
qemu.convert(sourceFile, destFile);
|
||||
}
|
||||
} else {
|
||||
format = PhysicalDiskFormat.RAW;
|
||||
disk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + newUuid, newUuid, destPool);
|
||||
disk.setFormat(format);
|
||||
if (size > template.getVirtualSize()) {
|
||||
disk.setSize(size);
|
||||
disk.setVirtualSize(size);
|
||||
} else {
|
||||
// leave these as they were if size isn't applicable
|
||||
disk.setSize(template.getVirtualSize());
|
||||
disk.setVirtualSize(disk.getSize());
|
||||
}
|
||||
|
||||
QemuImg qemu = new QemuImg(timeout);
|
||||
QemuImgFile srcFile;
|
||||
QemuImgFile destFile =
|
||||
new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(destPool.getSourceHost(), destPool.getSourcePort(), destPool.getAuthUserName(),
|
||||
destPool.getAuthSecret(), disk.getPath()));
|
||||
destFile.setFormat(format);
|
||||
if (size > template.getVirtualSize()) {
|
||||
destFile.setSize(size);
|
||||
} else {
|
||||
destFile.setSize(template.getVirtualSize());
|
||||
}
|
||||
|
||||
if (srcPool.getType() != StoragePoolType.RBD) {
|
||||
srcFile = new QemuImgFile(template.getPath(), template.getFormat());
|
||||
qemu.convert(srcFile, destFile);
|
||||
} else {
|
||||
|
||||
/**
|
||||
* We have to find out if the source file is in the same RBD pool and has
|
||||
* RBD format 2 before we can do a layering/clone operation on the RBD image
|
||||
*
|
||||
* This will be the case when the template is already on Primary Storage and
|
||||
* we want to copy it
|
||||
*/
|
||||
|
||||
try {
|
||||
if ((srcPool.getSourceHost().equals(destPool.getSourceHost())) && (srcPool.getSourceDir().equals(destPool.getSourceDir()))) {
|
||||
/* We are on the same Ceph cluster, but we require RBD format 2 on the source image */
|
||||
s_logger.debug("Trying to perform a RBD clone (layering) since we are operating in the same storage pool");
|
||||
|
||||
Rados r = new Rados(srcPool.getAuthUserName());
|
||||
r.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
|
||||
r.confSet("key", srcPool.getAuthSecret());
|
||||
r.confSet("client_mount_timeout", "30");
|
||||
r.connect();
|
||||
s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
|
||||
|
||||
IoCTX io = r.ioCtxCreate(srcPool.getSourceDir());
|
||||
Rbd rbd = new Rbd(io);
|
||||
RbdImage srcImage = rbd.open(template.getName());
|
||||
|
||||
if (srcImage.isOldFormat()) {
|
||||
/* The source image is RBD format 1, we have to do a regular copy */
|
||||
s_logger.debug("The source image " + srcPool.getSourceDir() + "/" + template.getName() +
|
||||
" is RBD format 1. We have to perform a regular copy (" + disk.getVirtualSize() + " bytes)");
|
||||
|
||||
rbd.create(disk.getName(), disk.getVirtualSize(), rbdFeatures, rbdOrder);
|
||||
RbdImage destImage = rbd.open(disk.getName());
|
||||
|
||||
s_logger.debug("Starting to copy " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
|
||||
rbd.copy(srcImage, destImage);
|
||||
|
||||
s_logger.debug("Finished copying " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
|
||||
rbd.close(destImage);
|
||||
} else {
|
||||
s_logger.debug("The source image " + srcPool.getSourceDir() + "/" + template.getName() +
|
||||
" is RBD format 2. We will perform a RBD clone using snapshot " + rbdTemplateSnapName);
|
||||
/* The source image is format 2, we can do a RBD snapshot+clone (layering) */
|
||||
rbd.clone(template.getName(), rbdTemplateSnapName, io, disk.getName(), rbdFeatures, rbdOrder);
|
||||
s_logger.debug("Succesfully cloned " + template.getName() + "@" + rbdTemplateSnapName + " to " + disk.getName());
|
||||
}
|
||||
|
||||
rbd.close(srcImage);
|
||||
r.ioCtxDestroy(io);
|
||||
} else {
|
||||
/* The source pool or host is not the same Ceph cluster, we do a simple copy with Qemu-Img */
|
||||
s_logger.debug("Both the source and destination are RBD, but not the same Ceph cluster. Performing a copy");
|
||||
|
||||
Rados rSrc = new Rados(srcPool.getAuthUserName());
|
||||
rSrc.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
|
||||
rSrc.confSet("key", srcPool.getAuthSecret());
|
||||
rSrc.confSet("client_mount_timeout", "30");
|
||||
rSrc.connect();
|
||||
s_logger.debug("Succesfully connected to source Ceph cluster at " + rSrc.confGet("mon_host"));
|
||||
|
||||
Rados rDest = new Rados(destPool.getAuthUserName());
|
||||
rDest.confSet("mon_host", destPool.getSourceHost() + ":" + destPool.getSourcePort());
|
||||
rDest.confSet("key", destPool.getAuthSecret());
|
||||
rDest.confSet("client_mount_timeout", "30");
|
||||
rDest.connect();
|
||||
s_logger.debug("Succesfully connected to source Ceph cluster at " + rDest.confGet("mon_host"));
|
||||
|
||||
IoCTX sIO = rSrc.ioCtxCreate(srcPool.getSourceDir());
|
||||
Rbd sRbd = new Rbd(sIO);
|
||||
|
||||
IoCTX dIO = rDest.ioCtxCreate(destPool.getSourceDir());
|
||||
Rbd dRbd = new Rbd(dIO);
|
||||
|
||||
s_logger.debug("Creating " + disk.getName() + " on the destination cluster " + rDest.confGet("mon_host") + " in pool " +
|
||||
destPool.getSourceDir());
|
||||
dRbd.create(disk.getName(), disk.getVirtualSize(), rbdFeatures, rbdOrder);
|
||||
|
||||
RbdImage srcImage = sRbd.open(template.getName());
|
||||
RbdImage destImage = dRbd.open(disk.getName());
|
||||
|
||||
s_logger.debug("Copying " + template.getName() + " from Ceph cluster " + rSrc.confGet("mon_host") + " to " + disk.getName() + " on cluster " +
|
||||
rDest.confGet("mon_host"));
|
||||
sRbd.copy(srcImage, destImage);
|
||||
|
||||
sRbd.close(srcImage);
|
||||
dRbd.close(destImage);
|
||||
|
||||
rSrc.ioCtxDestroy(sIO);
|
||||
rDest.ioCtxDestroy(dIO);
|
||||
}
|
||||
} catch (RadosException e) {
|
||||
s_logger.error("Failed to perform a RADOS action on the Ceph cluster, the error was: " + e.getMessage());
|
||||
disk = null;
|
||||
} catch (RbdException e) {
|
||||
s_logger.error("Failed to perform a RBD action on the Ceph cluster, the error was: " + e.getMessage());
|
||||
disk = null;
|
||||
}
|
||||
Map<String, String> options = new HashMap<String, String>();
|
||||
qemu.convert(sourceFile, destFile, options);
|
||||
}
|
||||
} catch (QemuImgException e) {
|
||||
s_logger.error("Failed to create " + disk.getPath() +
|
||||
" due to a failed executing of qemu-img: " + e.getMessage());
|
||||
}
|
||||
} catch (QemuImgException e) {
|
||||
s_logger.error("Failed to create " + disk.getPath() + " due to a failed executing of qemu-img: " + e.getMessage());
|
||||
}
|
||||
|
||||
if (disk == null) {
|
||||
@ -987,6 +930,154 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
return disk;
|
||||
}
|
||||
|
||||
private KVMPhysicalDisk createDiskFromTemplateOnRBD(KVMPhysicalDisk template,
|
||||
String name, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, KVMStoragePool destPool, int timeout){
|
||||
|
||||
/*
|
||||
With RBD you can't run qemu-img convert with an existing RBD image as destination
|
||||
qemu-img will exit with the error that the destination already exists.
|
||||
So for RBD we don't create the image, but let qemu-img do that for us.
|
||||
|
||||
We then create a KVMPhysicalDisk object that we can return
|
||||
*/
|
||||
|
||||
KVMStoragePool srcPool = template.getPool();
|
||||
KVMPhysicalDisk disk = null;
|
||||
String newUuid = name;
|
||||
|
||||
format = PhysicalDiskFormat.RAW;
|
||||
disk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + newUuid, newUuid, destPool);
|
||||
disk.setFormat(format);
|
||||
if (size > template.getVirtualSize()) {
|
||||
disk.setSize(size);
|
||||
disk.setVirtualSize(size);
|
||||
} else {
|
||||
// leave these as they were if size isn't applicable
|
||||
disk.setSize(template.getVirtualSize());
|
||||
disk.setVirtualSize(disk.getSize());
|
||||
}
|
||||
|
||||
|
||||
QemuImg qemu = new QemuImg(timeout);
|
||||
QemuImgFile srcFile;
|
||||
QemuImgFile destFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(destPool.getSourceHost(),
|
||||
destPool.getSourcePort(),
|
||||
destPool.getAuthUserName(),
|
||||
destPool.getAuthSecret(),
|
||||
disk.getPath()));
|
||||
destFile.setFormat(format);
|
||||
|
||||
|
||||
if (srcPool.getType() != StoragePoolType.RBD) {
|
||||
srcFile = new QemuImgFile(template.getPath(), template.getFormat());
|
||||
try{
|
||||
qemu.convert(srcFile, destFile);
|
||||
} catch (QemuImgException e) {
|
||||
s_logger.error("Failed to create " + disk.getPath() +
|
||||
" due to a failed executing of qemu-img: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
|
||||
/**
|
||||
* We have to find out if the source file is in the same RBD pool and has
|
||||
* RBD format 2 before we can do a layering/clone operation on the RBD image
|
||||
*
|
||||
* This will be the case when the template is already on Primary Storage and
|
||||
* we want to copy it
|
||||
*/
|
||||
|
||||
try {
|
||||
if ((srcPool.getSourceHost().equals(destPool.getSourceHost())) && (srcPool.getSourceDir().equals(destPool.getSourceDir()))) {
|
||||
/* We are on the same Ceph cluster, but we require RBD format 2 on the source image */
|
||||
s_logger.debug("Trying to perform a RBD clone (layering) since we are operating in the same storage pool");
|
||||
|
||||
Rados r = new Rados(srcPool.getAuthUserName());
|
||||
r.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
|
||||
r.confSet("key", srcPool.getAuthSecret());
|
||||
r.confSet("client_mount_timeout", "30");
|
||||
r.connect();
|
||||
s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
|
||||
|
||||
IoCTX io = r.ioCtxCreate(srcPool.getSourceDir());
|
||||
Rbd rbd = new Rbd(io);
|
||||
RbdImage srcImage = rbd.open(template.getName());
|
||||
|
||||
if (srcImage.isOldFormat()) {
|
||||
/* The source image is RBD format 1, we have to do a regular copy */
|
||||
s_logger.debug("The source image " + srcPool.getSourceDir() + "/" + template.getName() +
|
||||
" is RBD format 1. We have to perform a regular copy (" + disk.getVirtualSize() + " bytes)");
|
||||
|
||||
rbd.create(disk.getName(), disk.getVirtualSize(), rbdFeatures, rbdOrder);
|
||||
RbdImage destImage = rbd.open(disk.getName());
|
||||
|
||||
s_logger.debug("Starting to copy " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
|
||||
rbd.copy(srcImage, destImage);
|
||||
|
||||
s_logger.debug("Finished copying " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
|
||||
rbd.close(destImage);
|
||||
} else {
|
||||
s_logger.debug("The source image " + srcPool.getSourceDir() + "/" + template.getName()
|
||||
+ " is RBD format 2. We will perform a RBD clone using snapshot "
|
||||
+ this.rbdTemplateSnapName);
|
||||
/* The source image is format 2, we can do a RBD snapshot+clone (layering) */
|
||||
rbd.clone(template.getName(), this.rbdTemplateSnapName, io, disk.getName(), this.rbdFeatures, this.rbdOrder);
|
||||
s_logger.debug("Succesfully cloned " + template.getName() + "@" + this.rbdTemplateSnapName + " to " + disk.getName());
|
||||
}
|
||||
|
||||
rbd.close(srcImage);
|
||||
r.ioCtxDestroy(io);
|
||||
} else {
|
||||
/* The source pool or host is not the same Ceph cluster, we do a simple copy with Qemu-Img */
|
||||
s_logger.debug("Both the source and destination are RBD, but not the same Ceph cluster. Performing a copy");
|
||||
|
||||
Rados rSrc = new Rados(srcPool.getAuthUserName());
|
||||
rSrc.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
|
||||
rSrc.confSet("key", srcPool.getAuthSecret());
|
||||
rSrc.confSet("client_mount_timeout", "30");
|
||||
rSrc.connect();
|
||||
s_logger.debug("Succesfully connected to source Ceph cluster at " + rSrc.confGet("mon_host"));
|
||||
|
||||
Rados rDest = new Rados(destPool.getAuthUserName());
|
||||
rDest.confSet("mon_host", destPool.getSourceHost() + ":" + destPool.getSourcePort());
|
||||
rDest.confSet("key", destPool.getAuthSecret());
|
||||
rDest.confSet("client_mount_timeout", "30");
|
||||
rDest.connect();
|
||||
s_logger.debug("Succesfully connected to source Ceph cluster at " + rDest.confGet("mon_host"));
|
||||
|
||||
IoCTX sIO = rSrc.ioCtxCreate(srcPool.getSourceDir());
|
||||
Rbd sRbd = new Rbd(sIO);
|
||||
|
||||
IoCTX dIO = rDest.ioCtxCreate(destPool.getSourceDir());
|
||||
Rbd dRbd = new Rbd(dIO);
|
||||
|
||||
s_logger.debug("Creating " + disk.getName() + " on the destination cluster " + rDest.confGet("mon_host") + " in pool " +
|
||||
destPool.getSourceDir());
|
||||
dRbd.create(disk.getName(), disk.getVirtualSize(), rbdFeatures, rbdOrder);
|
||||
|
||||
RbdImage srcImage = sRbd.open(template.getName());
|
||||
RbdImage destImage = dRbd.open(disk.getName());
|
||||
|
||||
s_logger.debug("Copying " + template.getName() + " from Ceph cluster " + rSrc.confGet("mon_host") + " to " + disk.getName()
|
||||
+ " on cluster " + rDest.confGet("mon_host"));
|
||||
sRbd.copy(srcImage, destImage);
|
||||
|
||||
sRbd.close(srcImage);
|
||||
dRbd.close(destImage);
|
||||
|
||||
rSrc.ioCtxDestroy(sIO);
|
||||
rDest.ioCtxDestroy(dIO);
|
||||
}
|
||||
} catch (RadosException e) {
|
||||
s_logger.error("Failed to perform a RADOS action on the Ceph cluster, the error was: " + e.getMessage());
|
||||
disk = null;
|
||||
} catch (RbdException e) {
|
||||
s_logger.error("Failed to perform a RBD action on the Ceph cluster, the error was: " + e.getMessage());
|
||||
disk = null;
|
||||
}
|
||||
}
|
||||
return disk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk createTemplateFromDisk(KVMPhysicalDisk disk, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool) {
|
||||
return null;
|
||||
@ -1037,13 +1128,13 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
s_logger.debug("copyPhysicalDisk: disk size:" + disk.getSize() + ", virtualsize:" + disk.getVirtualSize()+" format:"+disk.getFormat());
|
||||
if (destPool.getType() != StoragePoolType.RBD) {
|
||||
if (disk.getFormat() == PhysicalDiskFormat.TAR) {
|
||||
newDisk = destPool.createPhysicalDisk(name, PhysicalDiskFormat.DIR, disk.getVirtualSize());
|
||||
newDisk = destPool.createPhysicalDisk(name, PhysicalDiskFormat.DIR, Storage.ProvisioningType.THIN, disk.getVirtualSize());
|
||||
} else {
|
||||
/* If the source device is on a RBD storage pool force the new disk to the same format (RAW) */
|
||||
if (srcPool.getType() != StoragePoolType.RBD) {
|
||||
newDisk = destPool.createPhysicalDisk(name, disk.getVirtualSize());
|
||||
newDisk = destPool.createPhysicalDisk(name, Storage.ProvisioningType.THIN, disk.getVirtualSize());
|
||||
} else {
|
||||
newDisk = destPool.createPhysicalDisk(name, sourceFormat, disk.getVirtualSize());
|
||||
newDisk = destPool.createPhysicalDisk(name, sourceFormat, Storage.ProvisioningType.THIN, disk.getVirtualSize());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1071,7 +1162,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
srcFile = new QemuImgFile(sourcePath, sourceFormat);
|
||||
try {
|
||||
Map<String, String> info = qemu.info(srcFile);
|
||||
String backingFile = info.get(new String("backing_file"));
|
||||
String backingFile = info.get(new String("backing-file"));
|
||||
// qcow2 templates can just be copied into place
|
||||
if (sourceFormat.equals(destFormat) && backingFile == null && sourcePath.endsWith(".qcow2")) {
|
||||
String result = Script.runSimpleBashScript("cp -f " + sourcePath + " " + destPath, timeout);
|
||||
|
||||
@ -25,6 +25,7 @@ import org.libvirt.StoragePool;
|
||||
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
@ -113,13 +114,16 @@ public class LibvirtStoragePool implements KVMStoragePool {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, PhysicalDiskFormat format, long size) {
|
||||
return this._storageAdaptor.createPhysicalDisk(name, this, format, size);
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name,
|
||||
PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size) {
|
||||
return this._storageAdaptor
|
||||
.createPhysicalDisk(name, this, format, provisioningType, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, long size) {
|
||||
return this._storageAdaptor.createPhysicalDisk(name, this, this.getDefaultFormat(), size);
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, Storage.ProvisioningType provisioningType, long size) {
|
||||
return this._storageAdaptor.createPhysicalDisk(name, this,
|
||||
this.getDefaultFormat(), provisioningType, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -21,6 +21,7 @@ import java.util.Map;
|
||||
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
|
||||
public interface StorageAdaptor {
|
||||
@ -35,7 +36,8 @@ public interface StorageAdaptor {
|
||||
|
||||
public boolean deleteStoragePool(String uuid);
|
||||
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, PhysicalDiskFormat format, long size);
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool,
|
||||
PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size);
|
||||
|
||||
// given disk path (per database) and pool, prepare disk on host
|
||||
public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<String, String> details);
|
||||
@ -49,7 +51,9 @@ public interface StorageAdaptor {
|
||||
|
||||
public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool);
|
||||
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool, int timeout);
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template,
|
||||
String name, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size,
|
||||
KVMStoragePool destPool, int timeout);
|
||||
|
||||
public KVMPhysicalDisk createTemplateFromDisk(KVMPhysicalDisk disk, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool);
|
||||
|
||||
|
||||
@ -16,11 +16,16 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.utils.qemu;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.cloud.storage.Storage;
|
||||
|
||||
import com.cloud.utils.script.OutputInterpreter;
|
||||
import com.cloud.utils.script.Script;
|
||||
import com.cloud.utils.script.OutputInterpreter;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class QemuImg {
|
||||
|
||||
@ -43,6 +48,35 @@ public class QemuImg {
|
||||
}
|
||||
}
|
||||
|
||||
public static enum PreallocationType {
|
||||
Off("off"),
|
||||
Metadata("metadata"),
|
||||
Full("full");
|
||||
|
||||
private final String preallocationType;
|
||||
|
||||
private PreallocationType(String preallocationType){
|
||||
this.preallocationType = preallocationType;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return this.preallocationType;
|
||||
}
|
||||
|
||||
public static PreallocationType getPreallocationType(Storage.ProvisioningType provisioningType){
|
||||
switch (provisioningType){
|
||||
case THIN:
|
||||
return PreallocationType.Off;
|
||||
case SPARSE:
|
||||
return PreallocationType.Metadata;
|
||||
case FAT:
|
||||
return PreallocationType.Full;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public QemuImg(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
@ -251,9 +285,9 @@ public class QemuImg {
|
||||
* Qemu-img returns human readable output, but this method does it's best
|
||||
* to turn that into machine readeable data.
|
||||
*
|
||||
* Spaces in keys are replaced by underscores (_).
|
||||
* Sizes (virtual_size and disk_size) are returned in bytes
|
||||
* Paths (image and backing_file) are the absolute path to the file
|
||||
* Spaces in keys are replaced by hyphen-minus (-).
|
||||
* Sizes (virtual-size and disk-size) are returned in bytes
|
||||
* Paths (image and backing-file) are the absolute path to the file
|
||||
*
|
||||
* @param file
|
||||
* A QemuImgFile object containing the file to get the information from
|
||||
@ -262,6 +296,8 @@ public class QemuImg {
|
||||
public Map<String, String> info(QemuImgFile file) throws QemuImgException {
|
||||
Script s = new Script(_qemuImgPath);
|
||||
s.add("info");
|
||||
s.add("--output");
|
||||
s.add("json");
|
||||
s.add(file.getFileName());
|
||||
OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
|
||||
String result = s.execute(parser);
|
||||
@ -269,24 +305,9 @@ public class QemuImg {
|
||||
throw new QemuImgException(result);
|
||||
}
|
||||
|
||||
HashMap<String, String> info = new HashMap<String, String>();
|
||||
String[] outputBuffer = parser.getLines().trim().split("\n");
|
||||
for (int i = 0; i < outputBuffer.length; i++) {
|
||||
String[] lineBuffer = outputBuffer[i].split(":", 2);
|
||||
if (lineBuffer.length == 2) {
|
||||
String key = lineBuffer[0].trim().replace(" ", "_");
|
||||
String value = null;
|
||||
|
||||
if (key.equals("virtual_size")) {
|
||||
value = lineBuffer[1].trim().replaceAll("^.*\\(([0-9]+).*$", "$1");
|
||||
} else {
|
||||
value = lineBuffer[1].trim();
|
||||
}
|
||||
|
||||
info.put(key, value);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
Type stringStringMap = new TypeToken<Map<String, String>>(){}.getType();
|
||||
Gson gson = new Gson();
|
||||
return gson.fromJson(parser.getLines(), stringStringMap);
|
||||
}
|
||||
|
||||
/* List, apply, create or delete snapshots in image */
|
||||
|
||||
@ -17,9 +17,11 @@
|
||||
package org.apache.cloudstack.utils.qemu;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import com.cloud.utils.script.Script;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -29,6 +31,7 @@ import org.junit.Test;
|
||||
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||
|
||||
|
||||
@Ignore
|
||||
public class QemuImgTest {
|
||||
|
||||
@ -48,7 +51,7 @@ public class QemuImgTest {
|
||||
fail("We didn't get any information back from qemu-img");
|
||||
}
|
||||
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual_size")));
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual-size")));
|
||||
assertEquals(Long.valueOf(size), Long.valueOf(infoSize));
|
||||
|
||||
String infoPath = info.get(new String("image"));
|
||||
@ -75,13 +78,13 @@ public class QemuImgTest {
|
||||
qemu.create(file, options);
|
||||
Map<String, String> info = qemu.info(file);
|
||||
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual_size")));
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual-size")));
|
||||
assertEquals(Long.valueOf(size), Long.valueOf(infoSize));
|
||||
|
||||
String infoPath = info.get(new String("image"));
|
||||
assertEquals(filename, infoPath);
|
||||
|
||||
String infoClusterSize = info.get(new String("cluster_size"));
|
||||
String infoClusterSize = info.get(new String("cluster-size"));
|
||||
assertEquals(clusterSize, infoClusterSize);
|
||||
|
||||
File f = new File(filename);
|
||||
@ -89,6 +92,31 @@ public class QemuImgTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSparseVolume() throws QemuImgException {
|
||||
String filename = "/tmp/" + UUID.randomUUID() + ".qcow2";
|
||||
|
||||
/* 10TB virtual_size */
|
||||
long size = 10995116277760l;
|
||||
QemuImgFile file = new QemuImgFile(filename, size, PhysicalDiskFormat.QCOW2);
|
||||
String preallocation = "metadata";
|
||||
Map<String, String> options = new HashMap<String, String>();
|
||||
|
||||
options.put("preallocation", preallocation);
|
||||
|
||||
QemuImg qemu = new QemuImg(0);
|
||||
qemu.create(file, options);
|
||||
|
||||
String allocatedSize = Script.runSimpleBashScript(String.format("ls -alhs %s | awk '{print $1}'", file));
|
||||
String declaredSize = Script.runSimpleBashScript(String.format("ls -alhs %s | awk '{print $6}'", file));
|
||||
|
||||
assertFalse(allocatedSize.equals(declaredSize));
|
||||
|
||||
File f = new File(filename);
|
||||
f.delete();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndResize() throws QemuImgException {
|
||||
String filename = "/tmp/" + UUID.randomUUID() + ".qcow2";
|
||||
@ -107,7 +135,7 @@ public class QemuImgTest {
|
||||
fail("We didn't get any information back from qemu-img");
|
||||
}
|
||||
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual_size")));
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual-size")));
|
||||
assertEquals(Long.valueOf(endSize), Long.valueOf(infoSize));
|
||||
} catch (QemuImgException e) {
|
||||
fail(e.getMessage());
|
||||
@ -136,7 +164,7 @@ public class QemuImgTest {
|
||||
fail("We didn't get any information back from qemu-img");
|
||||
}
|
||||
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual_size")));
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual-size")));
|
||||
assertEquals(Long.valueOf(startSize + increment), Long.valueOf(infoSize));
|
||||
} catch (QemuImgException e) {
|
||||
fail(e.getMessage());
|
||||
@ -164,7 +192,7 @@ public class QemuImgTest {
|
||||
fail("We didn't get any information back from qemu-img");
|
||||
}
|
||||
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual_size")));
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual-size")));
|
||||
assertEquals(Long.valueOf(startSize + increment), Long.valueOf(infoSize));
|
||||
} catch (QemuImgException e) {
|
||||
fail(e.getMessage());
|
||||
@ -227,7 +255,7 @@ public class QemuImgTest {
|
||||
fail("We didn't get any information back from qemu-img");
|
||||
}
|
||||
|
||||
String backingFile = info.get(new String("backing_file"));
|
||||
String backingFile = info.get(new String("backing-file"));
|
||||
if (backingFile == null) {
|
||||
fail("The second file does not have a property backing_file! Create failed?");
|
||||
}
|
||||
@ -275,10 +303,10 @@ public class QemuImgTest {
|
||||
|
||||
Map<String, String> info = qemu.info(destFile);
|
||||
|
||||
PhysicalDiskFormat infoFormat = PhysicalDiskFormat.valueOf(info.get(new String("file_format")).toUpperCase());
|
||||
PhysicalDiskFormat infoFormat = PhysicalDiskFormat.valueOf(info.get(new String("format")).toUpperCase());
|
||||
assertEquals(destFormat, infoFormat);
|
||||
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual_size")));
|
||||
Long infoSize = Long.parseLong(info.get(new String("virtual-size")));
|
||||
assertEquals(Long.valueOf(srcSize), Long.valueOf(infoSize));
|
||||
|
||||
File sf = new File(srcFileName);
|
||||
|
||||
@ -83,6 +83,7 @@ import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.offerings.dao.NetworkOfferingDao;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
@ -294,8 +295,9 @@ public class ElasticLoadBalancerManagerImpl extends ManagerBase implements Elast
|
||||
_elasticLbVmRamSize = NumbersUtil.parseInt(configs.get(Config.ElasticLoadBalancerVmMemory.key()), DEFAULT_ELB_VM_RAMSIZE);
|
||||
_elasticLbvmCpuMHz = NumbersUtil.parseInt(configs.get(Config.ElasticLoadBalancerVmCpuMhz.key()), DEFAULT_ELB_VM_CPU_MHZ);
|
||||
_elasticLbvmNumCpu = NumbersUtil.parseInt(configs.get(Config.ElasticLoadBalancerVmNumVcpu.key()), 1);
|
||||
_elasticLbVmOffering = new ServiceOfferingVO("System Offering For Elastic LB VM", _elasticLbvmNumCpu, _elasticLbVmRamSize, _elasticLbvmCpuMHz, 0, 0, true, null,
|
||||
useLocalStorage, true, null, true, VirtualMachine.Type.ElasticLoadBalancerVm, true);
|
||||
_elasticLbVmOffering = new ServiceOfferingVO("System Offering For Elastic LB VM", _elasticLbvmNumCpu,
|
||||
_elasticLbVmRamSize, _elasticLbvmCpuMHz, 0, 0, true, null, Storage.ProvisioningType.THIN, useLocalStorage,
|
||||
true, null, true, VirtualMachine.Type.ElasticLoadBalancerVm, true);
|
||||
_elasticLbVmOffering.setUniqueName(ServiceOffering.elbVmDefaultOffUniqueName);
|
||||
_elasticLbVmOffering = _serviceOfferingDao.persistSystemServiceOffering(_elasticLbVmOffering);
|
||||
|
||||
|
||||
@ -92,6 +92,7 @@ import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.User;
|
||||
@ -379,7 +380,8 @@ public class InternalLoadBalancerVMManagerImpl extends ManagerBase implements In
|
||||
boolean useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key()));
|
||||
ServiceOfferingVO newOff =
|
||||
new ServiceOfferingVO("System Offering For Internal LB VM", 1, InternalLoadBalancerVMManager.DEFAULT_INTERNALLB_VM_RAMSIZE,
|
||||
InternalLoadBalancerVMManager.DEFAULT_INTERNALLB_VM_CPU_MHZ, null, null, true, null, useLocalStorage, true, null, true,
|
||||
InternalLoadBalancerVMManager.DEFAULT_INTERNALLB_VM_CPU_MHZ, null, null, true, null,
|
||||
Storage.ProvisioningType.THIN, useLocalStorage, true, null, true,
|
||||
VirtualMachine.Type.InternalLoadBalancerVm, true);
|
||||
newOff.setUniqueName(ServiceOffering.internalLbVmDefaultOffUniqueName);
|
||||
newOff = _serviceOfferingDao.persistSystemServiceOffering(newOff);
|
||||
|
||||
@ -24,6 +24,7 @@ import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
@ -117,8 +118,8 @@ public class InternalLBVMManagerTest extends TestCase {
|
||||
public void setUp() {
|
||||
//mock system offering creation as it's used by configure() method called by initComponentsLifeCycle
|
||||
Mockito.when(_accountMgr.getAccount(1L)).thenReturn(new AccountVO());
|
||||
ServiceOfferingVO off =
|
||||
new ServiceOfferingVO("alena", 1, 1, 1, 1, 1, false, "alena", false, false, null, false, VirtualMachine.Type.InternalLoadBalancerVm, false);
|
||||
ServiceOfferingVO off = new ServiceOfferingVO("alena", 1, 1,
|
||||
1, 1, 1, false, "alena", Storage.ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.InternalLoadBalancerVm, false);
|
||||
off = setId(off, 1);
|
||||
Mockito.when(_svcOffDao.persistSystemServiceOffering(Matchers.any(ServiceOfferingVO.class))).thenReturn(off);
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import java.lang.reflect.Field;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.After;
|
||||
@ -87,8 +88,8 @@ public class InternalLBVMServiceTest extends TestCase {
|
||||
public void setUp() {
|
||||
//mock system offering creation as it's used by configure() method called by initComponentsLifeCycle
|
||||
Mockito.when(_accountMgr.getAccount(1L)).thenReturn(new AccountVO());
|
||||
ServiceOfferingVO off =
|
||||
new ServiceOfferingVO("alena", 1, 1, 1, 1, 1, false, "alena", false, false, null, false, VirtualMachine.Type.InternalLoadBalancerVm, false);
|
||||
ServiceOfferingVO off = new ServiceOfferingVO("alena", 1, 1,
|
||||
1, 1, 1, false, "alena", Storage.ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.InternalLoadBalancerVm, false);
|
||||
off = setId(off, 1);
|
||||
Mockito.when(_svcOffDao.persistSystemServiceOffering(Matchers.any(ServiceOfferingVO.class))).thenReturn(off);
|
||||
|
||||
|
||||
@ -59,6 +59,7 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase<DiskOfferingJoinVO,
|
||||
diskOfferingResponse.setId(offering.getUuid());
|
||||
diskOfferingResponse.setName(offering.getName());
|
||||
diskOfferingResponse.setDisplayText(offering.getDisplayText());
|
||||
diskOfferingResponse.setProvisioningType(offering.getProvisioningType().toString());
|
||||
diskOfferingResponse.setCreated(offering.getCreated());
|
||||
diskOfferingResponse.setDiskSize(offering.getDiskSize() / (1024 * 1024 * 1024));
|
||||
diskOfferingResponse.setMinIops(offering.getMinIops());
|
||||
|
||||
@ -59,6 +59,7 @@ public class ServiceOfferingJoinDaoImpl extends GenericDaoBase<ServiceOfferingJo
|
||||
offeringResponse.setDefaultUse(offering.isDefaultUse());
|
||||
offeringResponse.setSystemVmType(offering.getSystemVmType());
|
||||
offeringResponse.setDisplayText(offering.getDisplayText());
|
||||
offeringResponse.setProvisioningType(offering.getProvisioningType().toString());
|
||||
offeringResponse.setCpuNumber(offering.getCpu());
|
||||
offeringResponse.setCpuSpeed(offering.getSpeed());
|
||||
offeringResponse.setMemory(offering.getRamSize());
|
||||
|
||||
@ -99,6 +99,8 @@ public class VolumeJoinDaoImpl extends GenericDaoBase<VolumeJoinVO, Long> implem
|
||||
volResponse.setVirtualMachineDisplayName(volume.getVmDisplayName());
|
||||
}
|
||||
|
||||
volResponse.setProvisioningType(volume.getProvisioningType().toString());
|
||||
|
||||
// Show the virtual size of the volume
|
||||
volResponse.setSize(volume.getSize());
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
@ -46,6 +47,9 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity,
|
||||
@Column(name = "display_text")
|
||||
private String displayText;
|
||||
|
||||
@Column(name = "provisioning_type")
|
||||
Storage.ProvisioningType provisioningType;
|
||||
|
||||
@Column(name = "disk_size")
|
||||
long diskSize;
|
||||
|
||||
@ -136,6 +140,10 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity,
|
||||
return displayText;
|
||||
}
|
||||
|
||||
public Storage.ProvisioningType getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
public long getDiskSize() {
|
||||
return diskSize;
|
||||
}
|
||||
|
||||
@ -23,6 +23,8 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
@ -45,6 +47,9 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit
|
||||
@Column(name = "display_text")
|
||||
private String displayText;
|
||||
|
||||
@Column(name = "provisioning_type")
|
||||
Storage.ProvisioningType provisioningType;
|
||||
|
||||
@Column(name = "tags", length = 4096)
|
||||
String tags;
|
||||
|
||||
@ -156,6 +161,10 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit
|
||||
return displayText;
|
||||
}
|
||||
|
||||
public Storage.ProvisioningType getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
public String getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
@ -56,6 +56,10 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity {
|
||||
@Enumerated(EnumType.STRING)
|
||||
Volume.Type volumeType;
|
||||
|
||||
@Column(name = "provisioning_type")
|
||||
@Enumerated(EnumType.STRING)
|
||||
Storage.ProvisioningType provisioningType;
|
||||
|
||||
@Column(name = "size")
|
||||
long size;
|
||||
|
||||
@ -292,6 +296,10 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity {
|
||||
return volumeType;
|
||||
}
|
||||
|
||||
public Storage.ProvisioningType getProvisioningType(){
|
||||
return provisioningType;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -175,6 +175,7 @@ import com.cloud.service.ServiceOfferingDetailsVO;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
import com.cloud.test.IPRangeConfig;
|
||||
@ -2018,19 +2019,24 @@ 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.isCustomizedIops(), cmd.getMinIops(), cmd.getMaxIops(), cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate(),
|
||||
cmd.getHypervisorSnapshotReserve());
|
||||
return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber, memory, cpuSpeed, cmd.getDisplayText(),
|
||||
cmd.getProvisioningType(), localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(),
|
||||
cmd.getNetworkRate(), cmd.getDeploymentPlanner(), cmd.getDetails(), 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,
|
||||
protected ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vmType,
|
||||
String name, Integer cpu, Integer ramSize, Integer speed, String displayText, String provisioningType, boolean localStorageRequired,
|
||||
boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag,
|
||||
Integer networkRate, String deploymentPlanner, Map<String, String> details, Boolean isCustomizedIops, Long minIops, Long maxIops,
|
||||
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate, Integer hypervisorSnapshotReserve) {
|
||||
|
||||
ProvisioningType typedProvisioningType = ProvisioningType.getProvisioningType(provisioningType);
|
||||
|
||||
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);
|
||||
ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA,
|
||||
limitResourceUse, volatileVm, displayText, typedProvisioningType, localStorageRequired, false, tags, isSystem, vmType,
|
||||
domainId, hostTag, deploymentPlanner);
|
||||
|
||||
if (isCustomizedIops != null) {
|
||||
bytesReadRate = null;
|
||||
@ -2200,8 +2206,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
}
|
||||
}
|
||||
|
||||
protected DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired,
|
||||
boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate,
|
||||
protected DiskOfferingVO createDiskOffering(Long domainId, String name, String description, String provisioningType,
|
||||
Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired,
|
||||
boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops,
|
||||
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate,
|
||||
Integer hypervisorSnapshotReserve) {
|
||||
long diskSize = 0;// special case for custom disk offerings
|
||||
if (numGibibytes != null && (numGibibytes <= 0)) {
|
||||
@ -2209,6 +2217,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
} else if (numGibibytes != null && (numGibibytes > _maxVolumeSizeInGb)) {
|
||||
throw new InvalidParameterValueException("The maximum size for a disk is " + _maxVolumeSizeInGb + " Gb.");
|
||||
}
|
||||
ProvisioningType typedProvisioningType = ProvisioningType.getProvisioningType(provisioningType);
|
||||
|
||||
if (numGibibytes != null) {
|
||||
diskSize = numGibibytes * 1024 * 1024 * 1024;
|
||||
@ -2251,7 +2260,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
}
|
||||
|
||||
tags = StringUtils.cleanupTags(tags);
|
||||
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized, isCustomizedIops, minIops, maxIops);
|
||||
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, typedProvisioningType, diskSize, tags, isCustomized,
|
||||
isCustomizedIops, minIops, maxIops);
|
||||
newDiskOffering.setUseLocalStorage(localStorageRequired);
|
||||
newDiskOffering.setDisplayOffering(isDisplayOfferingEnabled);
|
||||
|
||||
@ -2285,6 +2295,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
public DiskOffering createDiskOffering(CreateDiskOfferingCmd cmd) {
|
||||
String name = cmd.getOfferingName();
|
||||
String description = cmd.getDisplayText();
|
||||
String provisioningType = cmd.getProvisioningType();
|
||||
Long numGibibytes = cmd.getDiskSize();
|
||||
boolean isDisplayOfferingEnabled = cmd.getDisplayOffering() != null ? cmd.getDisplayOffering() : true;
|
||||
boolean isCustomized = cmd.isCustomized() != null ? cmd.isCustomized() : false; // false
|
||||
@ -2320,7 +2331,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
Long iopsWriteRate = cmd.getIopsWriteRate();
|
||||
Integer hypervisorSnapshotReserve = cmd.getHypervisorSnapshotReserve();
|
||||
|
||||
return createDiskOffering(domainId, name, description, numGibibytes, tags, isCustomized, localStorageRequired, isDisplayOfferingEnabled, isCustomizedIops, minIops,
|
||||
return createDiskOffering(domainId, name, description, provisioningType, numGibibytes, tags, isCustomized,
|
||||
localStorageRequired, isDisplayOfferingEnabled, isCustomizedIops, minIops,
|
||||
maxIops, bytesReadRate, bytesWriteRate, iopsReadRate, iopsWriteRate, hypervisorSnapshotReserve);
|
||||
}
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import org.apache.cloudstack.config.ApiServiceConfiguration;
|
||||
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||
@ -100,6 +101,7 @@ import com.cloud.resource.ServerResource;
|
||||
import com.cloud.resource.UnableDeleteHostException;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.storage.StoragePoolStatus;
|
||||
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
@ -1267,7 +1269,8 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy
|
||||
int ramSize = NumbersUtil.parseInt(_configDao.getValue("console.ram.size"), DEFAULT_PROXY_VM_RAMSIZE);
|
||||
int cpuFreq = NumbersUtil.parseInt(_configDao.getValue("console.cpu.mhz"), DEFAULT_PROXY_VM_CPUMHZ);
|
||||
_serviceOffering =
|
||||
new ServiceOfferingVO("System Offering For Console Proxy", 1, ramSize, cpuFreq, 0, 0, false, null, useLocalStorage, true, null, true,
|
||||
new ServiceOfferingVO("System Offering For Console Proxy", 1, ramSize, cpuFreq, 0, 0, false, null,
|
||||
Storage.ProvisioningType.THIN, useLocalStorage, true, null, true,
|
||||
VirtualMachine.Type.ConsoleProxy, true);
|
||||
_serviceOffering.setUniqueName(ServiceOffering.consoleProxyDefaultOffUniqueName);
|
||||
_serviceOffering = _offeringDao.persistSystemServiceOffering(_serviceOffering);
|
||||
|
||||
@ -226,6 +226,7 @@ import com.cloud.resource.ResourceManager;
|
||||
import com.cloud.server.ConfigurationServer;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
@ -741,9 +742,8 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
|
||||
_agentMgr.registerForHostEvents(new SshKeysDistriMonitor(_agentMgr, _hostDao, _configDao), true, false, false);
|
||||
|
||||
final boolean useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key()));
|
||||
_offering =
|
||||
new ServiceOfferingVO("System Offering For Software Router", 1, _routerRamSize, _routerCpuMHz, null, null, true, null, useLocalStorage, true, null, true,
|
||||
VirtualMachine.Type.DomainRouter, true);
|
||||
_offering = new ServiceOfferingVO("System Offering For Software Router", 1, _routerRamSize, _routerCpuMHz, null,
|
||||
null, true, null, ProvisioningType.THIN, useLocalStorage, true, null, true, VirtualMachine.Type.DomainRouter, true);
|
||||
_offering.setUniqueName(ServiceOffering.routerDefaultOffUniqueName);
|
||||
_offering = _serviceOfferingDao.persistSystemServiceOffering(_offering);
|
||||
|
||||
|
||||
@ -96,6 +96,7 @@ import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
import com.cloud.test.IPRangeConfig;
|
||||
import com.cloud.user.Account;
|
||||
@ -218,14 +219,14 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
|
||||
s_logger.debug("ConfigurationServer made secondary storage copy use realhostip.");
|
||||
|
||||
// Save default service offerings
|
||||
createServiceOffering(User.UID_SYSTEM, "Small Instance", 1, 512, 500, "Small Instance", false, false, null);
|
||||
createServiceOffering(User.UID_SYSTEM, "Medium Instance", 1, 1024, 1000, "Medium Instance", false, false, null);
|
||||
createServiceOffering(User.UID_SYSTEM, "Small Instance", 1, 512, 500, "Small Instance", ProvisioningType.THIN, false, false, null);
|
||||
createServiceOffering(User.UID_SYSTEM, "Medium Instance", 1, 1024, 1000, "Medium Instance", ProvisioningType.THIN, false, false, null);
|
||||
// Save default disk offerings
|
||||
createdefaultDiskOffering(null, "Small", "Small Disk, 5 GB", 5, null, false, false);
|
||||
createdefaultDiskOffering(null, "Medium", "Medium Disk, 20 GB", 20, null, false, false);
|
||||
createdefaultDiskOffering(null, "Large", "Large Disk, 100 GB", 100, null, false, false);
|
||||
createdefaultDiskOffering(null, "Large", "Large Disk, 100 GB", 100, null, false, false);
|
||||
createdefaultDiskOffering(null, "Custom", "Custom Disk", 0, null, true, false);
|
||||
createdefaultDiskOffering(null, "Small", "Small Disk, 5 GB", ProvisioningType.THIN, 5, null, false, false);
|
||||
createdefaultDiskOffering(null, "Medium", "Medium Disk, 20 GB", ProvisioningType.THIN, 20, null, false, false);
|
||||
createdefaultDiskOffering(null, "Large", "Large Disk, 100 GB", ProvisioningType.THIN, 100, null, false, false);
|
||||
createdefaultDiskOffering(null, "Large", "Large Disk, 100 GB", ProvisioningType.THIN, 100, null, false, false);
|
||||
createdefaultDiskOffering(null, "Custom", "Custom Disk", ProvisioningType.THIN, 0, null, true, false);
|
||||
|
||||
// Save the mount parent to the configuration table
|
||||
String mountParent = getMountParent();
|
||||
@ -1026,24 +1027,24 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
|
||||
return pod;
|
||||
}
|
||||
|
||||
private DiskOfferingVO createdefaultDiskOffering(Long domainId, String name, String description, int numGibibytes, String tags, boolean isCustomized,
|
||||
boolean isSystemUse) {
|
||||
private DiskOfferingVO createdefaultDiskOffering(Long domainId, String name, String description, ProvisioningType provisioningType,
|
||||
int numGibibytes, String tags, boolean isCustomized, boolean isSystemUse) {
|
||||
long diskSize = numGibibytes;
|
||||
diskSize = diskSize * 1024 * 1024 * 1024;
|
||||
tags = cleanupTags(tags);
|
||||
|
||||
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized, null, null, null);
|
||||
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, provisioningType, diskSize, tags, isCustomized, null, null, null);
|
||||
newDiskOffering.setUniqueName("Cloud.Com-" + name);
|
||||
newDiskOffering.setSystemUse(isSystemUse);
|
||||
newDiskOffering = _diskOfferingDao.persistDeafultDiskOffering(newDiskOffering);
|
||||
return newDiskOffering;
|
||||
}
|
||||
|
||||
private ServiceOfferingVO createServiceOffering(long userId, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired,
|
||||
boolean offerHA, String tags) {
|
||||
private ServiceOfferingVO createServiceOffering(long userId, String name, int cpu, int ramSize, int speed, String displayText,
|
||||
ProvisioningType provisioningType, boolean localStorageRequired, boolean offerHA, String tags) {
|
||||
tags = cleanupTags(tags);
|
||||
ServiceOfferingVO offering =
|
||||
new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, offerHA, displayText, localStorageRequired, false, tags, false, null, false);
|
||||
new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, offerHA, displayText, provisioningType, localStorageRequired, false, tags, false, null, false);
|
||||
offering.setUniqueName("Cloud.Com-" + name);
|
||||
offering = _serviceOfferingDao.persistSystemServiceOffering(offering);
|
||||
return offering;
|
||||
|
||||
@ -330,10 +330,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
return Transaction.execute(new TransactionCallback<VolumeVO>() {
|
||||
@Override
|
||||
public VolumeVO doInTransaction(TransactionStatus status) {
|
||||
VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
volume.setDataCenterId(zoneId);
|
||||
volume.setPodId(null);
|
||||
VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, new Long(-1), null, null, Storage.ProvisioningType.THIN, 0, Volume.Type.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
volume.setDataCenterId(zoneId);
|
||||
volume.setPodId(null);
|
||||
// to prevent a nullpointer deref I put the system account id here when no owner is given.
|
||||
// TODO Decide if this is valid or whether throwing a CloudRuntimeException is more appropriate
|
||||
volume.setAccountId((owner == null) ? Account.ACCOUNT_ID_SYSTEM : owner.getAccountId());
|
||||
@ -391,6 +391,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
Long zoneId = cmd.getZoneId();
|
||||
Long diskOfferingId = null;
|
||||
DiskOfferingVO diskOffering = null;
|
||||
Storage.ProvisioningType provisioningType;
|
||||
Long size = null;
|
||||
Long minIops = null;
|
||||
Long maxIops = null;
|
||||
@ -477,6 +478,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
}
|
||||
}
|
||||
|
||||
provisioningType = diskOffering.getProvisioningType();
|
||||
|
||||
if (!validateVolumeSizeRange(size)) {// convert size from mb to gb
|
||||
// for validation
|
||||
throw new InvalidParameterValueException("Invalid size for custom volume creation: " + size + " ,max volume size is:" + _maxVolumeSizeInGb);
|
||||
@ -502,6 +505,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
size = snapshotCheck.getSize(); // ; disk offering is used for tags
|
||||
// purposes
|
||||
|
||||
provisioningType = diskOffering.getProvisioningType();
|
||||
|
||||
// one step operation - create volume in VM's cluster and attach it
|
||||
// to the VM
|
||||
Long vmId = cmd.getVirtualMachineId();
|
||||
@ -545,54 +550,55 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
userSpecifiedName = getRandomVolumeName();
|
||||
}
|
||||
|
||||
VolumeVO volume = commitVolume(cmd, caller, ownerId, displayVolume, zoneId, diskOfferingId, size, minIops, maxIops, parentVolume, userSpecifiedName,
|
||||
_uuidMgr.generateUuid(Volume.class, cmd.getCustomId()));
|
||||
VolumeVO volume = commitVolume(cmd, caller, ownerId, displayVolume, zoneId, diskOfferingId, provisioningType, size,
|
||||
minIops, maxIops, parentVolume, userSpecifiedName, _uuidMgr.generateUuid(Volume.class, cmd.getCustomId()));
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
private VolumeVO commitVolume(final CreateVolumeCmd cmd, final Account caller, final long ownerId, final Boolean displayVolume, final Long zoneId,
|
||||
final Long diskOfferingId, final Long size, final Long minIops, final Long maxIops, final VolumeVO parentVolume, final String userSpecifiedName, final String uuid) {
|
||||
private VolumeVO commitVolume(final CreateVolumeCmd cmd, final Account caller, final long ownerId, final Boolean displayVolume,
|
||||
final Long zoneId, final Long diskOfferingId, final Storage.ProvisioningType provisioningType, final Long size, final Long minIops, final Long maxIops, final VolumeVO parentVolume,
|
||||
final String userSpecifiedName, final String uuid) {
|
||||
return Transaction.execute(new TransactionCallback<VolumeVO>() {
|
||||
@Override
|
||||
public VolumeVO doInTransaction(TransactionStatus status) {
|
||||
VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, provisioningType, 0, Volume.Type.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
volume.setUuid(uuid);
|
||||
volume.setDataCenterId(zoneId);
|
||||
volume.setPodId(null);
|
||||
volume.setAccountId(ownerId);
|
||||
volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId()));
|
||||
volume.setDiskOfferingId(diskOfferingId);
|
||||
volume.setSize(size);
|
||||
volume.setMinIops(minIops);
|
||||
volume.setMaxIops(maxIops);
|
||||
volume.setInstanceId(null);
|
||||
volume.setUpdated(new Date());
|
||||
volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId());
|
||||
volume.setDataCenterId(zoneId);
|
||||
volume.setPodId(null);
|
||||
volume.setAccountId(ownerId);
|
||||
volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId()));
|
||||
volume.setDiskOfferingId(diskOfferingId);
|
||||
volume.setSize(size);
|
||||
volume.setMinIops(minIops);
|
||||
volume.setMaxIops(maxIops);
|
||||
volume.setInstanceId(null);
|
||||
volume.setUpdated(new Date());
|
||||
volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId());
|
||||
volume.setDisplayVolume(displayVolume);
|
||||
if (parentVolume != null) {
|
||||
volume.setTemplateId(parentVolume.getTemplateId());
|
||||
volume.setFormat(parentVolume.getFormat());
|
||||
} else {
|
||||
volume.setTemplateId(null);
|
||||
}
|
||||
if (parentVolume != null) {
|
||||
volume.setTemplateId(parentVolume.getTemplateId());
|
||||
volume.setFormat(parentVolume.getFormat());
|
||||
} else {
|
||||
volume.setTemplateId(null);
|
||||
}
|
||||
|
||||
volume = _volsDao.persist(volume);
|
||||
if (cmd.getSnapshotId() == null && displayVolume) {
|
||||
// for volume created from snapshot, create usage event after volume creation
|
||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
|
||||
diskOfferingId, null, size, Volume.class.getName(), volume.getUuid(), displayVolume);
|
||||
}
|
||||
volume = _volsDao.persist(volume);
|
||||
if (cmd.getSnapshotId() == null && displayVolume) {
|
||||
// for volume created from snapshot, create usage event after volume creation
|
||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
|
||||
diskOfferingId, null, size, Volume.class.getName(), volume.getUuid(), displayVolume);
|
||||
}
|
||||
|
||||
CallContext.current().setEventDetails("Volume Id: " + volume.getId());
|
||||
CallContext.current().setEventDetails("Volume Id: " + volume.getId());
|
||||
|
||||
// Increment resource count during allocation; if actual creation fails,
|
||||
// decrement it
|
||||
// Increment resource count during allocation; if actual creation fails,
|
||||
// decrement it
|
||||
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume, displayVolume);
|
||||
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, displayVolume, new Long(volume.getSize()));
|
||||
return volume;
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@ import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDaoImpl;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.dao.DiskOfferingDaoImpl;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.utils.PropertiesUtil;
|
||||
import com.cloud.utils.component.ComponentContext;
|
||||
import com.cloud.utils.db.DB;
|
||||
@ -906,6 +907,7 @@ public class DatabaseConfig {
|
||||
long id = Long.parseLong(_currentObjectParams.get("id"));
|
||||
String name = _currentObjectParams.get("name");
|
||||
String displayText = _currentObjectParams.get("displayText");
|
||||
ProvisioningType provisioningType = ProvisioningType.valueOf(_currentObjectParams.get("provisioningType"));
|
||||
int cpu = Integer.parseInt(_currentObjectParams.get("cpu"));
|
||||
int ramSize = Integer.parseInt(_currentObjectParams.get("ramSize"));
|
||||
int speed = Integer.parseInt(_currentObjectParams.get("speed"));
|
||||
@ -928,7 +930,8 @@ public class DatabaseConfig {
|
||||
}
|
||||
|
||||
ServiceOfferingVO serviceOffering =
|
||||
new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, ha, displayText, useLocalStorage, false, null, false, null, false);
|
||||
new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, ha, displayText,
|
||||
provisioningType, useLocalStorage, false, null, false, null, false);
|
||||
|
||||
Long bytesReadRate = Long.parseLong(_currentObjectParams.get("bytesReadRate"));
|
||||
if ((bytesReadRate != null) && (bytesReadRate > 0))
|
||||
@ -971,6 +974,7 @@ public class DatabaseConfig {
|
||||
long domainId = Long.parseLong(_currentObjectParams.get("domainId"));
|
||||
String name = _currentObjectParams.get("name");
|
||||
String displayText = _currentObjectParams.get("displayText");
|
||||
ProvisioningType provisioningType = ProvisioningType.valueOf(_currentObjectParams.get("provisioningtype"));
|
||||
long diskSpace = Long.parseLong(_currentObjectParams.get("diskSpace"));
|
||||
diskSpace = diskSpace * 1024 * 1024;
|
||||
// boolean mirroring = Boolean.parseBoolean(_currentObjectParams.get("mirrored"));
|
||||
@ -990,7 +994,7 @@ public class DatabaseConfig {
|
||||
newTags.delete(newTags.length() - 1, newTags.length());
|
||||
tags = newTags.toString();
|
||||
}
|
||||
DiskOfferingVO diskOffering = new DiskOfferingVO(domainId, name, displayText, diskSpace, tags, false, null, null, null);
|
||||
DiskOfferingVO diskOffering = new DiskOfferingVO(domainId, name, displayText, provisioningType, diskSpace, tags, false, null, null, null);
|
||||
diskOffering.setUseLocalStorage(local);
|
||||
|
||||
Long bytesReadRate = Long.parseLong(_currentObjectParams.get("bytesReadRate"));
|
||||
|
||||
@ -116,7 +116,7 @@ public class VolumeApiServiceImplTest {
|
||||
TransactionLegacy txn = TransactionLegacy.open("runVolumeDaoImplTest");
|
||||
try {
|
||||
// volume of running vm id=1
|
||||
VolumeVO volumeOfRunningVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 1L, "root", "root", 1, null,
|
||||
VolumeVO volumeOfRunningVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 1L, "root", "root", Storage.ProvisioningType.THIN, 1, null,
|
||||
null, "root", Volume.Type.ROOT);
|
||||
when(_svc._volsDao.findById(1L)).thenReturn(volumeOfRunningVm);
|
||||
|
||||
@ -127,7 +127,7 @@ public class VolumeApiServiceImplTest {
|
||||
when(_svc._userVmDao.findById(1L)).thenReturn(runningVm);
|
||||
|
||||
// volume of stopped vm id=2
|
||||
VolumeVO volumeOfStoppedVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", 1, null,
|
||||
VolumeVO volumeOfStoppedVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null,
|
||||
null, "root", Volume.Type.ROOT);
|
||||
volumeOfStoppedVm.setPoolId(1L);
|
||||
when(_svc._volsDao.findById(2L)).thenReturn(volumeOfStoppedVm);
|
||||
@ -146,7 +146,7 @@ public class VolumeApiServiceImplTest {
|
||||
hyperVVm.setDataCenterId(1L);
|
||||
when(_svc._userVmDao.findById(3L)).thenReturn(hyperVVm);
|
||||
|
||||
VolumeVO volumeOfStoppeHyperVVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 3L, "root", "root", 1, null,
|
||||
VolumeVO volumeOfStoppeHyperVVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 3L, "root", "root", Storage.ProvisioningType.THIN, 1, null,
|
||||
null, "root", Volume.Type.ROOT);
|
||||
volumeOfStoppeHyperVVm.setPoolId(1L);
|
||||
when(_svc._volsDao.findById(3L)).thenReturn(volumeOfStoppeHyperVVm);
|
||||
@ -158,7 +158,7 @@ public class VolumeApiServiceImplTest {
|
||||
StoragePoolVO managedPool = new StoragePoolVO();
|
||||
managedPool.setManaged(true);
|
||||
when(_svc._storagePoolDao.findById(2L)).thenReturn(managedPool);
|
||||
VolumeVO managedPoolVolume = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", 1, null,
|
||||
VolumeVO managedPoolVolume = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null,
|
||||
null, "root", Volume.Type.ROOT);
|
||||
managedPoolVolume.setPoolId(2L);
|
||||
when(_svc._volsDao.findById(4L)).thenReturn(managedPoolVolume);
|
||||
@ -177,7 +177,7 @@ public class VolumeApiServiceImplTest {
|
||||
when(correctRootVolume.getInstanceId()).thenReturn(null);
|
||||
when(_svc.volFactory.getVolume(6L)).thenReturn(correctRootVolume);
|
||||
|
||||
VolumeVO correctRootVolumeVO = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", 1, null,
|
||||
VolumeVO correctRootVolumeVO = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null,
|
||||
null, "root", Volume.Type.ROOT);
|
||||
when(_svc._volsDao.findById(6L)).thenReturn(correctRootVolumeVO);
|
||||
|
||||
@ -190,7 +190,7 @@ public class VolumeApiServiceImplTest {
|
||||
when(managedVolume.getPoolId()).thenReturn(2L);
|
||||
when(_svc.volFactory.getVolume(7L)).thenReturn(managedVolume);
|
||||
|
||||
VolumeVO managedVolume1 = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", 1, null,
|
||||
VolumeVO managedVolume1 = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null,
|
||||
null, "root", Volume.Type.ROOT);
|
||||
managedVolume1.setPoolId(2L);
|
||||
managedVolume1.setDataCenterId(1L);
|
||||
@ -216,7 +216,7 @@ public class VolumeApiServiceImplTest {
|
||||
when(uploadedVolume.getState()).thenReturn(Volume.State.Uploaded);
|
||||
when(_svc.volFactory.getVolume(8L)).thenReturn(uploadedVolume);
|
||||
|
||||
VolumeVO upVolume = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", 1, null,
|
||||
VolumeVO upVolume = new VolumeVO("root", 1L, 1L, 1L, 1L, 2L, "root", "root", Storage.ProvisioningType.THIN, 1, null,
|
||||
null, "root", Volume.Type.ROOT);
|
||||
upVolume.setPoolId(1L);
|
||||
upVolume.setDataCenterId(1L);
|
||||
|
||||
@ -81,6 +81,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.resource.ResourceManager;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.StorageManager;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
import com.cloud.storage.dao.GuestOSCategoryDao;
|
||||
@ -163,7 +164,8 @@ public class DeploymentPlanningManagerImplTest {
|
||||
@Test
|
||||
public void dataCenterAvoidTest() throws InsufficientServerCapacityException, AffinityConflictException {
|
||||
ServiceOfferingVO svcOffering =
|
||||
new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm", false, false, null, false, VirtualMachine.Type.User, domainId,
|
||||
new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm",
|
||||
ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, domainId,
|
||||
null, "FirstFitPlanner");
|
||||
Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering);
|
||||
|
||||
@ -177,7 +179,8 @@ public class DeploymentPlanningManagerImplTest {
|
||||
@Test
|
||||
public void plannerCannotHandleTest() throws InsufficientServerCapacityException, AffinityConflictException {
|
||||
ServiceOfferingVO svcOffering =
|
||||
new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm", false, false, null, false, VirtualMachine.Type.User, domainId,
|
||||
new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm",
|
||||
ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, domainId,
|
||||
null, "UserDispersingPlanner");
|
||||
Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering);
|
||||
|
||||
@ -192,7 +195,8 @@ public class DeploymentPlanningManagerImplTest {
|
||||
@Test
|
||||
public void emptyClusterListTest() throws InsufficientServerCapacityException, AffinityConflictException {
|
||||
ServiceOfferingVO svcOffering =
|
||||
new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm", false, false, null, false, VirtualMachine.Type.User, domainId,
|
||||
new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm",
|
||||
ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, domainId,
|
||||
null, "FirstFitPlanner");
|
||||
Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering);
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
@ -538,7 +539,8 @@ public class UserVmManagerTest {
|
||||
boolean useLocalStorage = false;
|
||||
|
||||
ServiceOfferingVO serviceOffering =
|
||||
new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, ha, displayText, useLocalStorage, false, null, false, null, false);
|
||||
new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, ha, displayText, Storage.ProvisioningType.THIN,
|
||||
useLocalStorage, false, null, false, null, false);
|
||||
return serviceOffering;
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
|
||||
@ -31,8 +32,8 @@ public class ServiceOfferingVOTest {
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
offeringCustom = new ServiceOfferingVO("custom", null, null, 500, 10, 10, false, "custom", false, false, "", false, VirtualMachine.Type.User, false);
|
||||
offering = new ServiceOfferingVO("normal", 1, 1000, 500, 10, 10, false, "normal", false, false, "", false, VirtualMachine.Type.User, false);
|
||||
offeringCustom = new ServiceOfferingVO("custom", null, null, 500, 10, 10, false, "custom", Storage.ProvisioningType.THIN, false, false, "", false, VirtualMachine.Type.User, false);
|
||||
offering = new ServiceOfferingVO("normal", 1, 1000, 500, 10, 10, false, "normal", Storage.ProvisioningType.THIN, false, false, "", false, VirtualMachine.Type.User, false);
|
||||
}
|
||||
|
||||
// Test restoreVm when VM state not in running/stopped case
|
||||
|
||||
@ -32,6 +32,7 @@ import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import org.apache.cloudstack.config.ApiServiceConfiguration;
|
||||
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
@ -109,6 +110,7 @@ import com.cloud.storage.secondary.SecStorageVmAlertEventArgs;
|
||||
import com.cloud.storage.secondary.SecondaryStorageListener;
|
||||
import com.cloud.storage.secondary.SecondaryStorageVmAllocator;
|
||||
import com.cloud.storage.secondary.SecondaryStorageVmManager;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.storage.template.TemplateConstants;
|
||||
import com.cloud.template.TemplateManager;
|
||||
import com.cloud.user.Account;
|
||||
@ -849,8 +851,8 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar
|
||||
int cpuFreq = NumbersUtil.parseInt(_configDao.getValue("ssvm.cpu.mhz"), DEFAULT_SS_VM_CPUMHZ);
|
||||
_useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key()));
|
||||
_serviceOffering =
|
||||
new ServiceOfferingVO("System Offering For Secondary Storage VM", 1, ramSize, cpuFreq, null, null, false, null, _useLocalStorage, true, null, true,
|
||||
VirtualMachine.Type.SecondaryStorageVm, true);
|
||||
new ServiceOfferingVO("System Offering For Secondary Storage VM", 1, ramSize, cpuFreq, null, null, false, null,
|
||||
Storage.ProvisioningType.THIN, _useLocalStorage, true, null, true, VirtualMachine.Type.SecondaryStorageVm, true);
|
||||
_serviceOffering.setUniqueName(ServiceOffering.ssvmDefaultOffUniqueName);
|
||||
_serviceOffering = _offeringDao.persistSystemServiceOffering(_serviceOffering);
|
||||
|
||||
|
||||
@ -22,3 +22,204 @@
|
||||
-- Disable foreign key checking
|
||||
-- SET foreign_key_checks = 0;
|
||||
|
||||
ALTER TABLE `cloud`.`volumes` ADD COLUMN `provisioning_type` VARCHAR(32) NOT NULL DEFAULT 'Off' COMMENT 'pre allocation setting of the volume';
|
||||
ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `provisioning_type` VARCHAR(32) NOT NULL DEFAULT 'Off' COMMENT 'pre allocation setting of the volume';
|
||||
|
||||
DROP VIEW IF EXISTS `cloud`.`disk_offering_view`;
|
||||
CREATE VIEW `cloud`.`disk_offering_view` AS
|
||||
select
|
||||
disk_offering.id,
|
||||
disk_offering.uuid,
|
||||
disk_offering.name,
|
||||
disk_offering.display_text,
|
||||
disk_offering.provisioning_type,
|
||||
disk_offering.disk_size,
|
||||
disk_offering.min_iops,
|
||||
disk_offering.max_iops,
|
||||
disk_offering.created,
|
||||
disk_offering.tags,
|
||||
disk_offering.customized,
|
||||
disk_offering.customized_iops,
|
||||
disk_offering.removed,
|
||||
disk_offering.use_local_storage,
|
||||
disk_offering.system_use,
|
||||
disk_offering.hv_ss_reserve,
|
||||
disk_offering.bytes_read_rate,
|
||||
disk_offering.bytes_write_rate,
|
||||
disk_offering.iops_read_rate,
|
||||
disk_offering.iops_write_rate,
|
||||
disk_offering.cache_mode,
|
||||
disk_offering.sort_key,
|
||||
disk_offering.type,
|
||||
disk_offering.display_offering,
|
||||
domain.id domain_id,
|
||||
domain.uuid domain_uuid,
|
||||
domain.name domain_name,
|
||||
domain.path domain_path
|
||||
from
|
||||
`cloud`.`disk_offering`
|
||||
left join
|
||||
`cloud`.`domain` ON disk_offering.domain_id = domain.id
|
||||
where
|
||||
disk_offering.state='ACTIVE';
|
||||
|
||||
|
||||
DROP VIEW IF EXISTS `cloud`.`service_offering_view`;
|
||||
CREATE VIEW `cloud`.`service_offering_view` AS
|
||||
select
|
||||
service_offering.id,
|
||||
disk_offering.uuid,
|
||||
disk_offering.name,
|
||||
disk_offering.display_text,
|
||||
disk_offering.provisioning_type,
|
||||
disk_offering.created,
|
||||
disk_offering.tags,
|
||||
disk_offering.removed,
|
||||
disk_offering.use_local_storage,
|
||||
disk_offering.system_use,
|
||||
disk_offering.customized_iops,
|
||||
disk_offering.min_iops,
|
||||
disk_offering.max_iops,
|
||||
disk_offering.hv_ss_reserve,
|
||||
disk_offering.bytes_read_rate,
|
||||
disk_offering.bytes_write_rate,
|
||||
disk_offering.iops_read_rate,
|
||||
disk_offering.iops_write_rate,
|
||||
disk_offering.cache_mode,
|
||||
service_offering.cpu,
|
||||
service_offering.speed,
|
||||
service_offering.ram_size,
|
||||
service_offering.nw_rate,
|
||||
service_offering.mc_rate,
|
||||
service_offering.ha_enabled,
|
||||
service_offering.limit_cpu_use,
|
||||
service_offering.host_tag,
|
||||
service_offering.default_use,
|
||||
service_offering.vm_type,
|
||||
service_offering.sort_key,
|
||||
service_offering.is_volatile,
|
||||
service_offering.deployment_planner,
|
||||
domain.id domain_id,
|
||||
domain.uuid domain_uuid,
|
||||
domain.name domain_name,
|
||||
domain.path domain_path
|
||||
from
|
||||
`cloud`.`service_offering`
|
||||
inner join
|
||||
`cloud`.`disk_offering` ON service_offering.id = disk_offering.id
|
||||
left join
|
||||
`cloud`.`domain` ON disk_offering.domain_id = domain.id
|
||||
where
|
||||
disk_offering.state='Active';
|
||||
|
||||
DROP VIEW IF EXISTS `cloud`.`volume_view`;
|
||||
CREATE VIEW `cloud`.`volume_view` AS
|
||||
select
|
||||
volumes.id,
|
||||
volumes.uuid,
|
||||
volumes.name,
|
||||
volumes.device_id,
|
||||
volumes.volume_type,
|
||||
volumes.provisioning_type,
|
||||
volumes.size,
|
||||
volumes.min_iops,
|
||||
volumes.max_iops,
|
||||
volumes.created,
|
||||
volumes.state,
|
||||
volumes.attached,
|
||||
volumes.removed,
|
||||
volumes.pod_id,
|
||||
volumes.display_volume,
|
||||
volumes.format,
|
||||
volumes.path,
|
||||
volumes.chain_info,
|
||||
account.id account_id,
|
||||
account.uuid account_uuid,
|
||||
account.account_name account_name,
|
||||
account.type account_type,
|
||||
domain.id domain_id,
|
||||
domain.uuid domain_uuid,
|
||||
domain.name domain_name,
|
||||
domain.path domain_path,
|
||||
projects.id project_id,
|
||||
projects.uuid project_uuid,
|
||||
projects.name project_name,
|
||||
data_center.id data_center_id,
|
||||
data_center.uuid data_center_uuid,
|
||||
data_center.name data_center_name,
|
||||
data_center.networktype data_center_type,
|
||||
vm_instance.id vm_id,
|
||||
vm_instance.uuid vm_uuid,
|
||||
vm_instance.name vm_name,
|
||||
vm_instance.state vm_state,
|
||||
vm_instance.vm_type,
|
||||
user_vm.display_name vm_display_name,
|
||||
volume_store_ref.size volume_store_size,
|
||||
volume_store_ref.download_pct,
|
||||
volume_store_ref.download_state,
|
||||
volume_store_ref.error_str,
|
||||
volume_store_ref.created created_on_store,
|
||||
disk_offering.id disk_offering_id,
|
||||
disk_offering.uuid disk_offering_uuid,
|
||||
disk_offering.name disk_offering_name,
|
||||
disk_offering.display_text disk_offering_display_text,
|
||||
disk_offering.use_local_storage,
|
||||
disk_offering.system_use,
|
||||
disk_offering.bytes_read_rate,
|
||||
disk_offering.bytes_write_rate,
|
||||
disk_offering.iops_read_rate,
|
||||
disk_offering.iops_write_rate,
|
||||
disk_offering.cache_mode,
|
||||
storage_pool.id pool_id,
|
||||
storage_pool.uuid pool_uuid,
|
||||
storage_pool.name pool_name,
|
||||
cluster.hypervisor_type,
|
||||
vm_template.id template_id,
|
||||
vm_template.uuid template_uuid,
|
||||
vm_template.extractable,
|
||||
vm_template.type template_type,
|
||||
resource_tags.id tag_id,
|
||||
resource_tags.uuid tag_uuid,
|
||||
resource_tags.key tag_key,
|
||||
resource_tags.value tag_value,
|
||||
resource_tags.domain_id tag_domain_id,
|
||||
resource_tags.account_id tag_account_id,
|
||||
resource_tags.resource_id tag_resource_id,
|
||||
resource_tags.resource_uuid tag_resource_uuid,
|
||||
resource_tags.resource_type tag_resource_type,
|
||||
resource_tags.customer tag_customer,
|
||||
async_job.id job_id,
|
||||
async_job.uuid job_uuid,
|
||||
async_job.job_status job_status,
|
||||
async_job.account_id job_account_id
|
||||
from
|
||||
`cloud`.`volumes`
|
||||
inner join
|
||||
`cloud`.`account` ON volumes.account_id = account.id
|
||||
inner join
|
||||
`cloud`.`domain` ON volumes.domain_id = domain.id
|
||||
left join
|
||||
`cloud`.`projects` ON projects.project_account_id = account.id
|
||||
left join
|
||||
`cloud`.`data_center` ON volumes.data_center_id = data_center.id
|
||||
left join
|
||||
`cloud`.`vm_instance` ON volumes.instance_id = vm_instance.id
|
||||
left join
|
||||
`cloud`.`user_vm` ON user_vm.id = vm_instance.id
|
||||
left join
|
||||
`cloud`.`volume_store_ref` ON volumes.id = volume_store_ref.volume_id
|
||||
left join
|
||||
`cloud`.`disk_offering` ON volumes.disk_offering_id = disk_offering.id
|
||||
left join
|
||||
`cloud`.`storage_pool` ON volumes.pool_id = storage_pool.id
|
||||
left join
|
||||
`cloud`.`cluster` ON storage_pool.cluster_id = cluster.id
|
||||
left join
|
||||
`cloud`.`vm_template` ON volumes.template_id = vm_template.id OR volumes.iso_id = vm_template.id
|
||||
left join
|
||||
`cloud`.`resource_tags` ON resource_tags.resource_id = volumes.id
|
||||
and resource_tags.resource_type = 'Volume'
|
||||
left join
|
||||
`cloud`.`async_job` ON async_job.instance_id = volumes.id
|
||||
and async_job.instance_type = 'Volume'
|
||||
and async_job.job_status = 0;
|
||||
|
||||
@ -38,6 +38,18 @@ class Services:
|
||||
"displaytext": "Disk offering",
|
||||
"disksize": 1 # in GB
|
||||
},
|
||||
"sparse": {
|
||||
"name": "Sparse Type Disk offering",
|
||||
"displaytext": "Sparse Type Disk offering",
|
||||
"disksize": 1, # in GB
|
||||
"provisioningtype" : "sparse"
|
||||
},
|
||||
"fat": {
|
||||
"name": "Fat Type Disk offering",
|
||||
"displaytext": "Fat Type Disk offering",
|
||||
"disksize": 1, # in GB
|
||||
"provisioningtype" : "fat"
|
||||
}
|
||||
}
|
||||
|
||||
class TestCreateDiskOffering(cloudstackTestCase):
|
||||
@ -102,6 +114,86 @@ class TestCreateDiskOffering(cloudstackTestCase):
|
||||
)
|
||||
return
|
||||
|
||||
@attr(hypervisor="kvm")
|
||||
@attr(tags = ["advanced", "basic", "eip", "sg", "advancedns", "simulator", "smoke"])
|
||||
def test_02_create_sparse_type_disk_offering(self):
|
||||
"""Test to create a sparse type disk offering"""
|
||||
|
||||
# Validate the following:
|
||||
# 1. createDiskOfferings should return valid info for new offering
|
||||
# 2. The Cloud Database contains the valid information
|
||||
|
||||
disk_offering = DiskOffering.create(
|
||||
self.apiclient,
|
||||
self.services["sparse"]
|
||||
)
|
||||
self.cleanup.append(disk_offering)
|
||||
|
||||
self.debug("Created Disk offering with ID: %s" % disk_offering.id)
|
||||
|
||||
list_disk_response = list_disk_offering(
|
||||
self.apiclient,
|
||||
id=disk_offering.id
|
||||
)
|
||||
self.assertEqual(
|
||||
isinstance(list_disk_response, list),
|
||||
True,
|
||||
"Check list response returns a valid list"
|
||||
)
|
||||
self.assertNotEqual(
|
||||
len(list_disk_response),
|
||||
0,
|
||||
"Check Disk offering is created"
|
||||
)
|
||||
disk_response = list_disk_response[0]
|
||||
|
||||
self.assertEqual(
|
||||
disk_response.provisioningtype,
|
||||
self.services["sparse"]["provisioningtype"],
|
||||
"Check provisionig type in createServiceOffering"
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
@attr(hypervisor="kvm")
|
||||
@attr(tags = ["advanced", "basic", "eip", "sg", "advancedns", "simulator", "smoke"])
|
||||
def test_04_create_fat_type_disk_offering(self):
|
||||
"""Test to create a sparse type disk offering"""
|
||||
|
||||
# Validate the following:
|
||||
# 1. createDiskOfferings should return valid info for new offering
|
||||
# 2. The Cloud Database contains the valid information
|
||||
|
||||
disk_offering = DiskOffering.create(
|
||||
self.apiclient,
|
||||
self.services["fat"]
|
||||
)
|
||||
self.cleanup.append(disk_offering)
|
||||
|
||||
self.debug("Created Disk offering with ID: %s" % disk_offering.id)
|
||||
|
||||
list_disk_response = list_disk_offering(
|
||||
self.apiclient,
|
||||
id=disk_offering.id
|
||||
)
|
||||
self.assertEqual(
|
||||
isinstance(list_disk_response, list),
|
||||
True,
|
||||
"Check list response returns a valid list"
|
||||
)
|
||||
self.assertNotEqual(
|
||||
len(list_disk_response),
|
||||
0,
|
||||
"Check Disk offering is created"
|
||||
)
|
||||
disk_response = list_disk_response[0]
|
||||
|
||||
self.assertEqual(
|
||||
disk_response.provisioningtype,
|
||||
self.services["fat"]["provisioningtype"],
|
||||
"Check provisionig type in createServiceOffering"
|
||||
)
|
||||
return
|
||||
|
||||
class TestDiskOfferings(cloudstackTestCase):
|
||||
|
||||
|
||||
@ -62,6 +62,12 @@ class Services:
|
||||
"name": "Small",
|
||||
"disksize": 1
|
||||
},
|
||||
"sparse_disk_offering": {
|
||||
"displaytext": "Sparse",
|
||||
"name": "Sparse",
|
||||
"provisioningtype": "sparse",
|
||||
"disksize": 1
|
||||
},
|
||||
'resized_disk_offering': {
|
||||
"displaytext": "Resized",
|
||||
"name": "Resized",
|
||||
@ -102,6 +108,10 @@ class TestCreateVolume(cloudstackTestCase):
|
||||
cls.api_client,
|
||||
cls.services["disk_offering"]
|
||||
)
|
||||
cls.sparse_disk_offering = DiskOffering.create(
|
||||
cls.api_client,
|
||||
cls.services["sparse_disk_offering"]
|
||||
)
|
||||
cls.custom_disk_offering = DiskOffering.create(
|
||||
cls.api_client,
|
||||
cls.services["disk_offering"],
|
||||
@ -172,6 +182,18 @@ class TestCreateVolume(cloudstackTestCase):
|
||||
self.debug("Created a volume with ID: %s" % volume.id)
|
||||
self.volumes.append(volume)
|
||||
|
||||
if self.virtual_machine.hypervisor == "KVM":
|
||||
sparse_volume = Volume.create(
|
||||
self.apiClient,
|
||||
self.services,
|
||||
zoneid=self.zone.id,
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid,
|
||||
diskofferingid=self.sparse_disk_offering.id
|
||||
)
|
||||
self.debug("Created a sparse volume: %s" % sparse_volume.id)
|
||||
self.volumes.append(sparse_volume)
|
||||
|
||||
volume = Volume.create_custom_disk(
|
||||
self.apiClient,
|
||||
self.services,
|
||||
|
||||
@ -536,6 +536,7 @@ dictionary = {
|
||||
'label.disk.read.bytes': '<fmt:message key="label.disk.read.bytes" />',
|
||||
'label.disk.read.io': '<fmt:message key="label.disk.read.io" />',
|
||||
'label.disk.offering': '<fmt:message key="label.disk.offering" />',
|
||||
'label.disk.provisioningtype': '<fmt:message key="label.disk.provisioningtype" />',
|
||||
'label.disk.size': '<fmt:message key="label.disk.size" />',
|
||||
'label.disk.size.gb': '<fmt:message key="label.disk.size.gb" />',
|
||||
'label.disk.total': '<fmt:message key="label.disk.total" />',
|
||||
|
||||
@ -95,6 +95,28 @@
|
||||
});
|
||||
}
|
||||
},
|
||||
provisioningType: {
|
||||
label: 'label.disk.provisioningtype',
|
||||
docID: 'helpComputeOfferingProvisioningType',
|
||||
select: function(args) {
|
||||
var items = [];
|
||||
items.push({
|
||||
id: 'thin',
|
||||
description: 'thin'
|
||||
});
|
||||
items.push({
|
||||
id: 'sparse',
|
||||
description: 'sparse'
|
||||
});
|
||||
items.push({
|
||||
id: 'fat',
|
||||
description: 'fat'
|
||||
});
|
||||
args.response.success({
|
||||
data: items
|
||||
});
|
||||
}
|
||||
},
|
||||
isCustomized: {
|
||||
label: 'label.custom',
|
||||
isBoolean: true,
|
||||
@ -456,7 +478,8 @@
|
||||
name: args.data.name,
|
||||
displaytext: args.data.description,
|
||||
storageType: args.data.storageType,
|
||||
customized: (args.data.isCustomized == "on")
|
||||
provisioningType :args.data.provisioningType,
|
||||
customized: (args.data.isCustomized == "on")
|
||||
};
|
||||
|
||||
//custom fields (begin)
|
||||
@ -721,6 +744,9 @@
|
||||
storagetype: {
|
||||
label: 'label.storage.type'
|
||||
},
|
||||
provisioningtype: {
|
||||
label: 'label.disk.provisioningtype'
|
||||
},
|
||||
cpunumber: {
|
||||
label: 'label.num.cpu.cores'
|
||||
},
|
||||
@ -937,6 +963,28 @@
|
||||
});
|
||||
}
|
||||
},
|
||||
provisioningType: {
|
||||
label: 'label.disk.provisioningtype',
|
||||
docID: 'helpDiskOfferingProvisioningType',
|
||||
select: function(args) {
|
||||
var items = [];
|
||||
items.push({
|
||||
id: 'thin',
|
||||
description: 'thin'
|
||||
});
|
||||
items.push({
|
||||
id: 'sparse',
|
||||
description: 'sparse'
|
||||
});
|
||||
items.push({
|
||||
id: 'fat',
|
||||
description: 'fat'
|
||||
});
|
||||
args.response.success({
|
||||
data: items
|
||||
});
|
||||
}
|
||||
},
|
||||
cpuNumber: {
|
||||
label: 'label.num.cpu.cores',
|
||||
docID: 'helpSystemOfferingCPUCores',
|
||||
@ -1064,6 +1112,7 @@
|
||||
displaytext: args.data.description,
|
||||
systemvmtype: args.data.systemvmtype,
|
||||
storageType: args.data.storageType,
|
||||
provisioningType: args.data.provisioningType,
|
||||
cpuNumber: args.data.cpuNumber,
|
||||
cpuSpeed: args.data.cpuSpeed,
|
||||
memory: args.data.memory
|
||||
@ -1271,6 +1320,9 @@
|
||||
storagetype: {
|
||||
label: 'label.storage.type'
|
||||
},
|
||||
provisioningtype: {
|
||||
label: 'label.disk.provisioningtype'
|
||||
},
|
||||
cpunumber: {
|
||||
label: 'label.num.cpu.cores'
|
||||
},
|
||||
@ -1447,6 +1499,28 @@
|
||||
});
|
||||
}
|
||||
},
|
||||
provisioningType: {
|
||||
label: 'label.disk.provisioningtype',
|
||||
docID: 'helpDiskOfferingProvisioningType',
|
||||
select: function(args) {
|
||||
var items = [];
|
||||
items.push({
|
||||
id: 'thin',
|
||||
description: 'thin'
|
||||
});
|
||||
items.push({
|
||||
id: 'sparse',
|
||||
description: 'sparse'
|
||||
});
|
||||
items.push({
|
||||
id: 'fat',
|
||||
description: 'fat'
|
||||
});
|
||||
args.response.success({
|
||||
data: items
|
||||
});
|
||||
}
|
||||
},
|
||||
isCustomized: {
|
||||
label: 'label.custom.disk.size',
|
||||
docID: 'helpDiskOfferingCustomDiskSize',
|
||||
@ -1671,6 +1745,7 @@
|
||||
displaytext: args.data.description,
|
||||
storageType: args.data.storageType,
|
||||
cacheMode: args.data.cacheMode,
|
||||
provisioningType: args.data.provisioningType,
|
||||
customized: (args.data.isCustomized == "on")
|
||||
};
|
||||
|
||||
@ -1917,6 +1992,9 @@
|
||||
},
|
||||
storagetype: {
|
||||
label: 'label.storage.type'
|
||||
},
|
||||
provisioningtype: {
|
||||
label: 'label.disk.provisioningtype'
|
||||
}
|
||||
}],
|
||||
|
||||
|
||||
@ -218,6 +218,10 @@ cloudStack.docs = {
|
||||
desc: 'Type of disk for the VM. Local storage is attached to the hypervisor host where the VM is running. Shared storage is accessible via NFS.',
|
||||
externalLink: ''
|
||||
},
|
||||
helpComputeOfferingProvisioningType: {
|
||||
desc: 'Provisioning type to create a volume. Thin and sparse is lazy allocation. fat is eager allocation.',
|
||||
externalLink: ''
|
||||
},
|
||||
helpComputeOfferingCPUCores: {
|
||||
desc: 'The number of cores which should be allocated to a VM with this offering',
|
||||
externalLink: ''
|
||||
@ -282,6 +286,10 @@ cloudStack.docs = {
|
||||
desc: 'A short description of the offering that can be displayed to users',
|
||||
externalLink: ''
|
||||
},
|
||||
helpDiskOfferingProvisioningType: {
|
||||
desc: 'Provisioning type to create a volume. Thin and sparse is lazy allocation. fat is eager allocation.',
|
||||
externalLink: ''
|
||||
},
|
||||
helpDiskOfferingStorageType: {
|
||||
desc: 'Type of disk for the VM. Local is attached to the hypervisor host where the VM is running. Shared is storage accessible via NFS.',
|
||||
externalLink: ''
|
||||
|
||||
@ -1402,6 +1402,9 @@
|
||||
storagetype: {
|
||||
label: 'label.storage.type'
|
||||
},
|
||||
provisioningtype: {
|
||||
label: 'label.disk.provisioningtype'
|
||||
},
|
||||
hypervisor: {
|
||||
label: 'label.hypervisor'
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user