diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 4916c1d6d82c..fd0688a66b06 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -755,6 +755,7 @@ public class ApiConstants { public static final String ROUTER_CHECK_TYPE = "checktype"; public static final String LAST_UPDATED = "lastupdated"; public static final String PERFORM_FRESH_CHECKS = "performfreshchecks"; + public static final String CACHE_MODE = "cachemode"; public static final String BOOT_TYPE ="boottype"; public static final String BOOT_MODE ="bootmode"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java index 3ff8f69568cf..9c4ec42c1769 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java @@ -144,6 +144,9 @@ public class CreateDiskOfferingCmd extends BaseCmd { description = "Hypervisor snapshot reserve space as a percent of a volume (for managed storage using Xen or VMware)") private Integer hypervisorSnapshotReserve; + @Parameter(name = ApiConstants.CACHE_MODE, type = CommandType.STRING, required = false, description = "the cache mode to use for this disk offering. none, writeback or writethrough") + private String cacheMode; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -262,6 +265,10 @@ public Integer getHypervisorSnapshotReserve() { return hypervisorSnapshotReserve; } + public String getCacheMode() { + return cacheMode; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index c30b43745c5c..0f03791854ac 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -178,6 +178,9 @@ public class CreateServiceOfferingCmd extends BaseCmd { since = "4.4") private Integer hypervisorSnapshotReserve; + @Parameter(name = ApiConstants.CACHE_MODE, type = CommandType.STRING, required = false, description = "the cache mode to use for this disk offering. none, writeback or writethrough") + private String cacheMode; + // Introduce 4 new optional paramaters to work custom compute offerings @Parameter(name = ApiConstants.CUSTOMIZED, type = CommandType.BOOLEAN, @@ -377,6 +380,10 @@ public Integer getHypervisorSnapshotReserve() { return hypervisorSnapshotReserve; } + public String getCacheMode() { + return cacheMode; + } + /** * If customized parameter is true, then cpuNumber, memory and cpuSpeed must be null * Check if the optional params min/max CPU/Memory have been specified diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java index 41c8645029e5..93a6913489be 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java @@ -192,6 +192,10 @@ public class ServiceOfferingResponse extends BaseResponse { @Param(description = "is true if the offering is customized", since = "4.3.0") private Boolean isCustomized; + @SerializedName("cacheMode") + @Param(description = "the cache mode to use for this disk offering. none, writeback or writethrough", since = "4.4") + private String cacheMode; + public ServiceOfferingResponse() { } @@ -448,4 +452,7 @@ public void setIscutomized(boolean iscutomized) { } + public void setCacheMode(String cacheMode) { + this.cacheMode = cacheMode; + } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 9a2fd275dd3c..5b4e8839139d 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -1171,7 +1171,7 @@ protected synchronized String attachOrDetachDisk(final Connect conn, final boole final Long bytesReadRate, final Long bytesReadRateMax, final Long bytesReadRateMaxLength, final Long bytesWriteRate, final Long bytesWriteRateMax, final Long bytesWriteRateMaxLength, final Long iopsReadRate, final Long iopsReadRateMax, final Long iopsReadRateMaxLength, - final Long iopsWriteRate, final Long iopsWriteRateMax, final Long iopsWriteRateMaxLength) throws LibvirtException, InternalErrorException { + final Long iopsWriteRate, final Long iopsWriteRateMax, final Long iopsWriteRateMaxLength, final String cacheMode) throws LibvirtException, InternalErrorException { List disks = null; Domain dm = null; DiskDef diskdef = null; @@ -1281,6 +1281,9 @@ protected synchronized String attachOrDetachDisk(final Connect conn, final boole if ((iopsWriteRateMaxLength != null) && (iopsWriteRateMaxLength > 0)) { diskdef.setIopsWriteRateMaxLength(iopsWriteRateMaxLength); } + if(cacheMode != null) { + diskdef.setCacheMode(DiskDef.DiskCacheMode.valueOf(cacheMode.toUpperCase())); + } } final String xml = diskdef.toString(); @@ -1305,12 +1308,13 @@ public Answer attachVolume(final AttachCommand cmd) { storagePoolMgr.connectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath(), disk.getDetails()); final KVMPhysicalDisk phyDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath()); + final String volCacheMode = vol.getCacheMode() == null ? null : vol.getCacheMode().toString(); attachOrDetachDisk(conn, true, vmName, phyDisk, disk.getDiskSeq().intValue(), serial, vol.getBytesReadRate(), vol.getBytesReadRateMax(), vol.getBytesReadRateMaxLength(), vol.getBytesWriteRate(), vol.getBytesWriteRateMax(), vol.getBytesWriteRateMaxLength(), vol.getIopsReadRate(), vol.getIopsReadRateMax(), vol.getIopsReadRateMaxLength(), - vol.getIopsWriteRate(), vol.getIopsWriteRateMax(), vol.getIopsWriteRateMaxLength()); + vol.getIopsWriteRate(), vol.getIopsWriteRateMax(), vol.getIopsWriteRateMaxLength(), volCacheMode); return new AttachAnswer(disk); } catch (final LibvirtException e) { @@ -1334,12 +1338,13 @@ public Answer dettachVolume(final DettachCommand cmd) { final Connect conn = LibvirtConnection.getConnectionByVmName(vmName); final KVMPhysicalDisk phyDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath()); + final String volCacheMode = vol.getCacheMode() == null ? null : vol.getCacheMode().toString(); attachOrDetachDisk(conn, false, vmName, phyDisk, disk.getDiskSeq().intValue(), serial, vol.getBytesReadRate(), vol.getBytesReadRateMax(), vol.getBytesReadRateMaxLength(), vol.getBytesWriteRate(), vol.getBytesWriteRateMax(), vol.getBytesWriteRateMaxLength(), vol.getIopsReadRate(), vol.getIopsReadRateMax(), vol.getIopsReadRateMaxLength(), - vol.getIopsWriteRate(), vol.getIopsWriteRateMax(), vol.getIopsWriteRateMaxLength()); + vol.getIopsWriteRate(), vol.getIopsWriteRateMax(), vol.getIopsWriteRateMaxLength(), volCacheMode); storagePoolMgr.disconnectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath()); diff --git a/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java index 139804414716..add64155375f 100644 --- a/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java @@ -102,6 +102,7 @@ public ServiceOfferingResponse newServiceOfferingResponse(ServiceOfferingJoinVO offeringResponse.setDetails(ApiDBUtils.getResourceDetails(offering.getId(), ResourceObjectType.ServiceOffering)); offeringResponse.setObjectName("serviceoffering"); offeringResponse.setIscutomized(offering.isDynamic()); + offeringResponse.setCacheMode(offering.getCacheMode()); return offeringResponse; } diff --git a/server/src/main/java/com/cloud/api/query/vo/ServiceOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/ServiceOfferingJoinVO.java index fa16308029e2..4f8932ad4cfb 100644 --- a/server/src/main/java/com/cloud/api/query/vo/ServiceOfferingJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/ServiceOfferingJoinVO.java @@ -172,6 +172,9 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit @Column(name = "deployment_planner") private String deploymentPlanner; + @Column(name = "cache_mode") + String cacheMode; + public ServiceOfferingJoinVO() { } @@ -349,4 +352,8 @@ public Long getIopsWriteRate() { public boolean isDynamic() { return cpu == null || speed == null || ramSize == null; } + + public String getCacheMode() { + return cacheMode; + } } diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 1f8655d40c93..4b8effb4efd2 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -153,6 +153,7 @@ import com.cloud.vm.dao.NicIpAliasVO; import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.VMInstanceDao; +import com.google.common.base.Enums; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.base.Strings; @@ -2318,6 +2319,11 @@ public ServiceOffering createServiceOffering(final CreateServiceOfferingCmd cmd) } } + // check if valid cache_mode parameter + if(cmd.getCacheMode() != null && !Enums.getIfPresent(DiskOffering.DiskCacheMode.class, cmd.getCacheMode().toUpperCase()).isPresent()){ + throw new InvalidParameterValueException("Please specify a valid cache mode parameter"); + } + final Boolean offerHA = cmd.isOfferHa(); boolean localStorageRequired = false; @@ -2398,7 +2404,7 @@ public ServiceOffering createServiceOffering(final CreateServiceOfferingCmd cmd) cmd.getBytesWriteRate(), cmd.getBytesWriteRateMax(), cmd.getBytesWriteRateMaxLength(), cmd.getIopsReadRate(), cmd.getIopsReadRateMax(), cmd.getIopsReadRateMaxLength(), cmd.getIopsWriteRate(), cmd.getIopsWriteRateMax(), cmd.getIopsWriteRateMaxLength(), - cmd.getHypervisorSnapshotReserve()); + cmd.getHypervisorSnapshotReserve(), cmd.getCacheMode()); } protected ServiceOfferingVO createServiceOffering(final long userId, final boolean isSystem, final VirtualMachine.Type vmType, @@ -2409,7 +2415,7 @@ protected ServiceOfferingVO createServiceOffering(final long userId, final boole Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength, Long iopsReadRate, Long iopsReadRateMax, Long iopsReadRateMaxLength, Long iopsWriteRate, Long iopsWriteRateMax, Long iopsWriteRateMaxLength, - final Integer hypervisorSnapshotReserve) { + final Integer hypervisorSnapshotReserve, String cacheMode) { // Filter child domains when both parent and child domains are present List filteredDomainIds = filterChildSubDomains(domainIds); @@ -2506,6 +2512,9 @@ protected ServiceOfferingVO createServiceOffering(final long userId, final boole if (iopsWriteRateMaxLength != null && iopsWriteRateMaxLength > 0) { offering.setIopsWriteRateMaxLength(iopsWriteRateMaxLength); } + if(cacheMode != null) { + offering.setCacheMode(DiskOffering.DiskCacheMode.valueOf(cacheMode.toUpperCase())); + } if (hypervisorSnapshotReserve != null && hypervisorSnapshotReserve < 0) { throw new InvalidParameterValueException("If provided, Hypervisor Snapshot Reserve must be greater than or equal to 0."); @@ -2764,7 +2773,7 @@ protected DiskOfferingVO createDiskOffering(final Long userId, final List Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength, Long iopsReadRate, Long iopsReadRateMax, Long iopsReadRateMaxLength, Long iopsWriteRate, Long iopsWriteRateMax, Long iopsWriteRateMaxLength, - final Integer hypervisorSnapshotReserve) { + final Integer hypervisorSnapshotReserve, String cacheMode) { long diskSize = 0;// special case for custom disk offerings if (numGibibytes != null && numGibibytes <= 0) { throw new InvalidParameterValueException("Please specify a disk size of at least 1 Gb."); @@ -2870,6 +2879,9 @@ protected DiskOfferingVO createDiskOffering(final Long userId, final List if (iopsWriteRateMaxLength != null && iopsWriteRateMaxLength > 0) { newDiskOffering.setIopsWriteRateMaxLength(iopsWriteRateMaxLength); } + if (cacheMode != null) { + newDiskOffering.setCacheMode(DiskOffering.DiskCacheMode.valueOf(cacheMode.toUpperCase())); + } if (hypervisorSnapshotReserve != null && hypervisorSnapshotReserve < 0) { throw new InvalidParameterValueException("If provided, Hypervisor Snapshot Reserve must be greater than or equal to 0."); @@ -2936,6 +2948,11 @@ public DiskOffering createDiskOffering(final CreateDiskOfferingCmd cmd) { throw new InvalidParameterValueException("Disksize is not allowed for a customized disk offering"); } + // check if valid cache_mode parameter + if(cmd.getCacheMode() != null && !Enums.getIfPresent(DiskOffering.DiskCacheMode.class, cmd.getCacheMode().toUpperCase()).isPresent()){ + throw new InvalidParameterValueException("Please specify a valid cache mode parameter"); + } + boolean localStorageRequired = false; final String storageType = cmd.getStorageType(); if (storageType != null) { @@ -2962,13 +2979,14 @@ public DiskOffering createDiskOffering(final CreateDiskOfferingCmd cmd) { final Long iopsWriteRateMax = cmd.getIopsWriteRateMax(); final Long iopsWriteRateMaxLength = cmd.getIopsWriteRateMaxLength(); final Integer hypervisorSnapshotReserve = cmd.getHypervisorSnapshotReserve(); + final String cacheMode = cmd.getCacheMode(); final Long userId = CallContext.current().getCallingUserId(); return createDiskOffering(userId, domainIds, zoneIds, name, description, provisioningType, numGibibytes, tags, isCustomized, localStorageRequired, isDisplayOfferingEnabled, isCustomizedIops, minIops, maxIops, bytesReadRate, bytesReadRateMax, bytesReadRateMaxLength, bytesWriteRate, bytesWriteRateMax, bytesWriteRateMaxLength, iopsReadRate, iopsReadRateMax, iopsReadRateMaxLength, iopsWriteRate, iopsWriteRateMax, iopsWriteRateMaxLength, - hypervisorSnapshotReserve); + hypervisorSnapshotReserve, cacheMode); } @Override diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index 62a602263f44..6e57e9adb538 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -137,6 +137,28 @@ }); } }, + cacheMode: { + label: 'label.cache.mode', + docID: 'helpDiskOfferingCacheMode', + select: function (args) { + var items = []; + items.push({ + id: 'none', + description: 'No disk cache' + }); + items.push({ + id: 'writeback', + description: 'Write-back disk caching' + }); + items.push({ + id: "writethrough", + description: 'Write-through' + }); + args.response.success({ + data: items + }) + } + }, offeringType: { label: 'label.compute.offering.type', docID: 'helpComputeOfferingType', @@ -731,7 +753,8 @@ displaytext: args.data.description, storageType: args.data.storageType, provisioningType :args.data.provisioningType, - customized: !isFixedOfferingType + customized: !isFixedOfferingType, + cacheMode: args.data.cacheMode }; //custom fields (begin) @@ -1221,6 +1244,9 @@ provisioningtype: { label: 'label.disk.provisioningtype' }, + cacheMode: { + label: 'label.cache.mode' + }, cpunumber: { label: 'label.num.cpu.cores' }, @@ -1481,6 +1507,28 @@ }); } }, + cacheMode: { + label: 'label.cache.mode', + docID: 'helpDiskOfferingCacheMode', + select: function(args) { + var items = []; + items.push({ + id: 'none', + description: 'No disk cache' + }); + items.push({ + id: 'writeback', + description: 'Write-back disk caching' + }); + items.push({ + id: 'writethrough', + description: 'Write-through disk caching' + }); + args.response.success({ + data: items + }) + } + }, cpuNumber: { label: 'label.num.cpu.cores', docID: 'helpSystemOfferingCPUCores', @@ -1694,7 +1742,8 @@ provisioningType: args.data.provisioningType, cpuNumber: args.data.cpuNumber, cpuSpeed: args.data.cpuSpeed, - memory: args.data.memory + memory: args.data.memory, + cacheMode: args.data.cacheMode }; if (args.data.networkRate != null && args.data.networkRate.length > 0) { @@ -1920,6 +1969,9 @@ provisioningtype: { label: 'label.disk.provisioningtype' }, + cacheMode: { + label: 'label.cache.mode' + }, cpunumber: { label: 'label.num.cpu.cores' },