Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ public class ApiConstants {
public static final String MAX = "max";
public static final String MAC_ADDRESS = "macaddress";
public static final String MAX_SNAPS = "maxsnaps";
public static final String MAX_CPU_NUMBER = "maxcpunumber";
public static final String MAX_MEMORY = "maxmemory";
public static final String MIN_CPU_NUMBER = "mincpunumber";
public static final String MIN_MEMORY = "minmemory";
public static final String MEMORY = "memory";
public static final String MODE = "mode";
public static final String KEEPALIVE_ENABLED = "keepaliveenabled";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@

import java.util.Collection;
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;
Expand All @@ -30,10 +28,14 @@
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.commons.collections.MapUtils;
import org.apache.log4j.Logger;

import com.cloud.exception.InvalidParameterValueException;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.Storage;
import com.cloud.user.Account;
import com.google.common.base.Strings;

@APICommand(name = "createServiceOffering", description = "Creates a service offering.", responseObject = ServiceOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
Expand Down Expand Up @@ -162,6 +164,37 @@ public class CreateServiceOfferingCmd extends BaseCmd {
since = "4.4")
private Integer hypervisorSnapshotReserve;

// Introduce 4 new optional paramaters to work custom compute offerings
@Parameter(name = ApiConstants.CUSTOMIZED,
type = CommandType.BOOLEAN,
since = "4.13",
description = "Whether service offering size is custom or not")
private Boolean customized;

@Parameter(name = ApiConstants.MAX_CPU_NUMBER,
type = CommandType.INTEGER,
description = "The maximum number of CPUs to be set with Custom Computer Offering",
since = "4.13")
private Integer maxCPU;

@Parameter(name = ApiConstants.MIN_CPU_NUMBER,
type = CommandType.INTEGER,
description = "The minimum number of CPUs to be set with Custom Computer Offering",
since = "4.13")
private Integer minCPU;

@Parameter(name = ApiConstants.MAX_MEMORY,
type = CommandType.INTEGER,
description = "The maximum memroy size of the custom service offering in MB",
since = "4.13")
private Integer maxMemory;

@Parameter(name = ApiConstants.MIN_MEMORY,
type = CommandType.INTEGER,
description = "The minimum memroy size of the custom service offering in MB",
since = "4.13")
private Integer minMemory;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
Expand All @@ -175,6 +208,9 @@ public Integer getCpuSpeed() {
}

public String getDisplayText() {
if (Strings.isNullOrEmpty(displayText)) {
throw new InvalidParameterValueException("Failed to create service offering because the offering display text has not been spified.");
}
return displayText;
}

Expand All @@ -187,6 +223,9 @@ public Integer getMemory() {
}

public String getServiceOfferingName() {
if (Strings.isNullOrEmpty(serviceOfferingName)) {
throw new InvalidParameterValueException("Failed to create service offering because offering name has not been spified.");
}
return serviceOfferingName;
}

Expand Down Expand Up @@ -234,18 +273,12 @@ public String getDeploymentPlanner() {
return deploymentPlanner;
}

public boolean isCustomized() {
return (cpuNumber == null || memory == null || cpuSpeed == null);
}

public Map<String, String> getDetails() {
Map<String, String> detailsMap = null;
if (details != null && !details.isEmpty()) {
detailsMap = new HashMap<String, String>();
Map<String, String> detailsMap = new HashMap<>();
if (MapUtils.isNotEmpty(details)) {
Collection<?> props = details.values();
Iterator<?> iter = props.iterator();
while (iter.hasNext()) {
HashMap<String, String> detail = (HashMap<String, String>) iter.next();
for (Object prop : props) {
HashMap<String, String> detail = (HashMap<String, String>) prop;
detailsMap.put(detail.get("key"), detail.get("value"));
}
}
Expand Down Expand Up @@ -316,6 +349,36 @@ public Integer getHypervisorSnapshotReserve() {
return hypervisorSnapshotReserve;
}

/**
* 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
* @return true if the following conditions are satisfied;
* - cpuNumber, memory and cpuSpeed are all null when customized parameter is set to true
* - min/max CPU/Memory params are all null or all set
*/
public boolean isCustomized() {
if (customized != null){
return customized;
}
return (cpuNumber == null || memory == null);
}

public Integer getMaxCPUs() {
return maxCPU;
}

public Integer getMinCPUs() {
return minCPU;
}

public Integer getMaxMemory() {
return maxMemory;
}

public Integer getMinMemory() {
return minMemory;
}

/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,4 +331,8 @@ public boolean isDynamic() {
public void setDynamicFlag(boolean isdynamic) {
isDynamic = isdynamic;
}

public boolean isCustomCpuSpeedSupported() {
return isCustomized() && getDetail("minCPU") != null;
}
}
24 changes: 18 additions & 6 deletions server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,15 @@ public void updateCapacityForHost(final Host host) {
usedMemory +=
((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.memory.name())) * 1024L * 1024L) / ramOvercommitRatio) *
clusterRamOvercommitRatio;
usedCpu +=
((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuSpeed.name()))) / cpuOvercommitRatio) *
clusterCpuOvercommitRatio;
if(vmDetails.containsKey(UsageEventVO.DynamicParameters.cpuSpeed.name())) {
usedCpu +=
((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuSpeed.name()))) / cpuOvercommitRatio) *
clusterCpuOvercommitRatio;
} else {
usedCpu +=
((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * so.getSpeed()) / cpuOvercommitRatio) *
clusterCpuOvercommitRatio;
}
usedCpuCore += Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name()));
} else {
usedMemory += ((so.getRamSize() * 1024L * 1024L) / ramOvercommitRatio) * clusterRamOvercommitRatio;
Expand Down Expand Up @@ -645,9 +651,15 @@ public void updateCapacityForHost(final Host host) {
reservedMemory +=
((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.memory.name())) * 1024L * 1024L) / ramOvercommitRatio) *
clusterRamOvercommitRatio;
reservedCpu +=
((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuSpeed.name()))) / cpuOvercommitRatio) *
clusterCpuOvercommitRatio;
if(vmDetails.containsKey(UsageEventVO.DynamicParameters.cpuSpeed.name())) {
reservedCpu +=
((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuSpeed.name()))) / cpuOvercommitRatio) *
clusterCpuOvercommitRatio;
} else {
reservedCpu +=
((Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name())) * so.getSpeed()) / cpuOvercommitRatio) *
clusterCpuOvercommitRatio;
}
reservedCpuCore += Integer.parseInt(vmDetails.get(UsageEventVO.DynamicParameters.cpuNumber.name()));
} else {
reservedMemory += ((so.getRamSize() * 1024L * 1024L) / ramOvercommitRatio) * clusterRamOvercommitRatio;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,11 @@
import javax.inject.Inject;
import javax.naming.ConfigurationException;

import com.google.common.collect.Sets;

import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
Expand Down Expand Up @@ -232,6 +231,7 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;

public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable {
public static final Logger s_logger = Logger.getLogger(ConfigurationManagerImpl.class);
Expand Down Expand Up @@ -2218,6 +2218,8 @@ public DataCenter createZone(final CreateZoneCmd cmd) {
@ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CREATE, eventDescription = "creating service offering")
public ServiceOffering createServiceOffering(final CreateServiceOfferingCmd cmd) {
final Long userId = CallContext.current().getCallingUserId();
final Map<String, String> details = cmd.getDetails();
final String offeringName = cmd.getServiceOfferingName();

final String name = cmd.getServiceOfferingName();
if (name == null || name.length() == 0) {
Expand All @@ -2233,21 +2235,54 @@ public ServiceOffering createServiceOffering(final CreateServiceOfferingCmd cmd)
final Integer cpuSpeed = cmd.getCpuSpeed();
final Integer memory = cmd.getMemory();

//restricting the createserviceoffering to allow setting all or none of the dynamic parameters to null
if (cpuNumber == null || cpuSpeed == null || memory == null) {
if (cpuNumber != null || cpuSpeed != null || memory != null) {
throw new InvalidParameterValueException("For creating a custom compute offering cpu, cpu speed and memory all should be null");
// Optional Custom Parameters
Integer maxCPU = cmd.getMaxCPUs();
Integer minCPU = cmd.getMinCPUs();
Integer maxMemory = cmd.getMaxMemory();
Integer minMemory = cmd.getMinMemory();

// Check if service offering is Custom,
// If Customized, the following conditions must hold
// 1. cpuNumber, cpuSpeed and memory should be all null
// 2. minCPU, maxCPU, minMemory and maxMemory should all be null or all specified
boolean isCustomized = cmd.isCustomized();
if (isCustomized) {
// validate specs
//restricting the createserviceoffering to allow setting all or none of the dynamic parameters to null
if (cpuNumber != null || memory != null) {
throw new InvalidParameterValueException("For creating a custom compute offering cpu and memory all should be null");
}
// if any of them is null, then all of them shoull be null
if (maxCPU == null || minCPU == null || maxMemory == null || minMemory == null) {
if (maxCPU != null || minCPU != null || maxMemory != null || minMemory != null) {
throw new InvalidParameterValueException("For creating a custom compute offering min/max cpu and min/max memory should all be specified");
}
} else {
if (cpuSpeed != null && (cpuSpeed.intValue() < 0 || cpuSpeed.longValue() > Integer.MAX_VALUE)) {
throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the cpu speed value between 1 and " + Integer.MAX_VALUE);
}
if ((maxCPU <= 0 || maxCPU.longValue() > Integer.MAX_VALUE) || (minCPU <= 0 || minCPU.longValue() > Integer.MAX_VALUE ) ) {
throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the minimum or minimum cpu number value between 1 and " + Integer.MAX_VALUE);
}
if (minMemory < 32 || (minMemory.longValue() > Integer.MAX_VALUE) || (maxMemory.longValue() > Integer.MAX_VALUE)) {
throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the memory value between 32 and " + Integer.MAX_VALUE + " MB");
}
// Persist min/max CPU and Memory parameters in the service_offering_details table
details.put(ApiConstants.MIN_MEMORY, minMemory.toString());
details.put(ApiConstants.MAX_MEMORY, maxMemory.toString());
details.put(ApiConstants.MIN_CPU_NUMBER, minCPU.toString());
details.put(ApiConstants.MAX_CPU_NUMBER, maxCPU.toString());
}
} else {
if (cpuNumber != null && (cpuNumber.intValue() <= 0 || cpuNumber.longValue() > Integer.MAX_VALUE)) {
throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the cpu number value between 1 and " + Integer.MAX_VALUE);
}
if (cpuSpeed != null && (cpuSpeed.intValue() < 0 || cpuSpeed.longValue() > Integer.MAX_VALUE)) {
throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the cpu speed value between 0 and " + Integer.MAX_VALUE);
}
if (memory != null && (memory.intValue() < 32 || memory.longValue() > Integer.MAX_VALUE)) {
throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the memory value between 32 and " + Integer.MAX_VALUE + " MB");
}
}

if (cpuNumber != null && (cpuNumber.intValue() <= 0 || cpuNumber.longValue() > Integer.MAX_VALUE)) {
throw new InvalidParameterValueException("Failed to create service offering " + name + ": specify the cpu number value between 1 and " + Integer.MAX_VALUE);
}
if (cpuSpeed != null && (cpuSpeed.intValue() < 0 || cpuSpeed.longValue() > Integer.MAX_VALUE)) {
throw new InvalidParameterValueException("Failed to create service offering " + name + ": specify the cpu speed value between 0 and " + Integer.MAX_VALUE);
}
if (memory != null && (memory.intValue() < 32 || memory.longValue() > Integer.MAX_VALUE)) {
throw new InvalidParameterValueException("Failed to create service offering " + name + ": specify the memory value between 32 and " + Integer.MAX_VALUE + " MB");
}

// check if valid domain
Expand Down Expand Up @@ -2330,7 +2365,7 @@ public ServiceOffering createServiceOffering(final CreateServiceOfferingCmd cmd)

return createServiceOffering(userId, cmd.isSystem(), 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(), isCustomizedIops, cmd.getMinIops(), cmd.getMaxIops(),
cmd.getNetworkRate(), cmd.getDeploymentPlanner(), details, isCustomizedIops, cmd.getMinIops(), cmd.getMaxIops(),
cmd.getBytesReadRate(), cmd.getBytesReadRateMax(), cmd.getBytesReadRateMaxLength(),
cmd.getBytesWriteRate(), cmd.getBytesWriteRateMax(), cmd.getBytesWriteRateMaxLength(),
cmd.getIopsReadRate(), cmd.getIopsReadRateMax(), cmd.getIopsReadRateMaxLength(),
Expand Down
Loading