mirror of https://github.com/apache/cloudstack.git
Add support to clone existing offerings and update them
This commit is contained in:
parent
da85858e93
commit
e13104bfea
|
|
@ -24,6 +24,7 @@ import com.cloud.network.Network;
|
|||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.command.admin.config.ResetCfgCmd;
|
||||
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CloneNetworkOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
|
||||
|
|
@ -33,6 +34,8 @@ import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
|
|||
import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CloneDiskOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CloneServiceOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd;
|
||||
|
|
@ -105,6 +108,33 @@ public interface ConfigurationService {
|
|||
*/
|
||||
ServiceOffering createServiceOffering(CreateServiceOfferingCmd cmd);
|
||||
|
||||
/**
|
||||
* Clones a service offering with optional parameter overrides
|
||||
*
|
||||
* @param cmd
|
||||
* the command object that specifies the source offering ID and optional parameter overrides
|
||||
* @return the newly created service offering cloned from source, null otherwise
|
||||
*/
|
||||
ServiceOffering cloneServiceOffering(CloneServiceOfferingCmd cmd);
|
||||
|
||||
/**
|
||||
* Clones a disk offering with optional parameter overrides
|
||||
*
|
||||
* @param cmd
|
||||
* the command object that specifies the source offering ID and optional parameter overrides
|
||||
* @return the newly created disk offering cloned from source, null otherwise
|
||||
*/
|
||||
DiskOffering cloneDiskOffering(CloneDiskOfferingCmd cmd);
|
||||
|
||||
/**
|
||||
* Clones a network offering with optional parameter overrides
|
||||
*
|
||||
* @param cmd
|
||||
* the command object that specifies the source offering ID and optional parameter overrides
|
||||
* @return the newly created network offering cloned from source, null otherwise
|
||||
*/
|
||||
NetworkOffering cloneNetworkOffering(CloneNetworkOfferingCmd cmd);
|
||||
|
||||
/**
|
||||
* Updates a service offering
|
||||
*
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ public class EventTypes {
|
|||
|
||||
// Service Offerings
|
||||
public static final String EVENT_SERVICE_OFFERING_CREATE = "SERVICE.OFFERING.CREATE";
|
||||
public static final String EVENT_SERVICE_OFFERING_CLONE = "SERVICE.OFFERING.CLONE";
|
||||
public static final String EVENT_SERVICE_OFFERING_EDIT = "SERVICE.OFFERING.EDIT";
|
||||
public static final String EVENT_SERVICE_OFFERING_DELETE = "SERVICE.OFFERING.DELETE";
|
||||
|
||||
|
|
|
|||
|
|
@ -555,6 +555,7 @@ public class ApiConstants {
|
|||
public static final String USE_STORAGE_REPLICATION = "usestoragereplication";
|
||||
|
||||
public static final String SOURCE_CIDR_LIST = "sourcecidrlist";
|
||||
public static final String SOURCE_OFFERING_ID = "sourceofferingid";
|
||||
public static final String SOURCE_ZONE_ID = "sourcezoneid";
|
||||
public static final String SSL_VERIFICATION = "sslverification";
|
||||
public static final String START_ASN = "startasn";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.admin.network;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.NetworkOfferingResponse;
|
||||
|
||||
import com.cloud.offering.NetworkOffering;
|
||||
|
||||
@APICommand(name = "cloneNetworkOffering",
|
||||
description = "Clones a network offering. All parameters are copied from the source offering unless explicitly overridden. " +
|
||||
"Use 'addServices' and 'dropServices' to modify the service list without respecifying everything.",
|
||||
responseObject = NetworkOfferingResponse.class,
|
||||
requestHasSensitiveInfo = false,
|
||||
responseHasSensitiveInfo = false,
|
||||
since = "4.23.0")
|
||||
public class CloneNetworkOfferingCmd extends CreateNetworkOfferingCmd {
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name = ApiConstants.SOURCE_OFFERING_ID,
|
||||
type = BaseCmd.CommandType.UUID,
|
||||
entityType = NetworkOfferingResponse.class,
|
||||
required = true,
|
||||
description = "The ID of the network offering to clone")
|
||||
private Long sourceOfferingId;
|
||||
|
||||
@Parameter(name = "addservices",
|
||||
type = CommandType.LIST,
|
||||
collectionType = CommandType.STRING,
|
||||
description = "Services to add to the cloned offering (in addition to source offering services). " +
|
||||
"If specified along with 'supportedservices', this parameter is ignored.")
|
||||
private List<String> addServices;
|
||||
|
||||
@Parameter(name = "dropservices",
|
||||
type = CommandType.LIST,
|
||||
collectionType = CommandType.STRING,
|
||||
description = "Services to remove from the cloned offering (that exist in source offering). " +
|
||||
"If specified along with 'supportedservices', this parameter is ignored.")
|
||||
private List<String> dropServices;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public Long getSourceOfferingId() {
|
||||
return sourceOfferingId;
|
||||
}
|
||||
|
||||
public List<String> getAddServices() {
|
||||
return addServices;
|
||||
}
|
||||
|
||||
public List<String> getDropServices() {
|
||||
return dropServices;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
NetworkOffering result = _configService.cloneNetworkOffering(this);
|
||||
if (result != null) {
|
||||
NetworkOfferingResponse response = _responseGenerator.createNetworkOfferingResponse(result);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clone network offering");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.admin.offering;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.DiskOfferingResponse;
|
||||
|
||||
import com.cloud.offering.DiskOffering;
|
||||
|
||||
@APICommand(name = "cloneDiskOffering",
|
||||
description = "Clones a disk offering. All parameters from createDiskOffering are available. If not specified, values will be copied from the source offering.",
|
||||
responseObject = DiskOfferingResponse.class,
|
||||
requestHasSensitiveInfo = false,
|
||||
responseHasSensitiveInfo = false,
|
||||
since = "4.23.0")
|
||||
public class CloneDiskOfferingCmd extends CreateDiskOfferingCmd {
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name = ApiConstants.SOURCE_OFFERING_ID,
|
||||
type = BaseCmd.CommandType.UUID,
|
||||
entityType = DiskOfferingResponse.class,
|
||||
required = true,
|
||||
description = "The ID of the disk offering to clone")
|
||||
private Long sourceOfferingId;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public Long getSourceOfferingId() {
|
||||
return sourceOfferingId;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
DiskOffering result = _configService.cloneDiskOffering(this);
|
||||
if (result != null) {
|
||||
DiskOfferingResponse response = _responseGenerator.createDiskOfferingResponse(result);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clone disk offering");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.admin.offering;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
|
||||
@APICommand(name = "cloneServiceOffering",
|
||||
description = "Clones a service offering. All parameters from createServiceOffering are available. If not specified, values will be copied from the source offering.",
|
||||
responseObject = ServiceOfferingResponse.class,
|
||||
requestHasSensitiveInfo = false,
|
||||
responseHasSensitiveInfo = false,
|
||||
since = "4.23.0")
|
||||
public class CloneServiceOfferingCmd extends CreateServiceOfferingCmd {
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name = ApiConstants.SOURCE_OFFERING_ID,
|
||||
type = CommandType.UUID,
|
||||
entityType = ServiceOfferingResponse.class,
|
||||
required = true,
|
||||
description = "The ID of the service offering to clone")
|
||||
private Long sourceOfferingId;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public Long getSourceOfferingId() {
|
||||
return sourceOfferingId;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
ServiceOffering result = _configService.cloneServiceOffering(this);
|
||||
if (result != null) {
|
||||
ServiceOfferingResponse response = _responseGenerator.createServiceOfferingResponse(result);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clone service offering");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +67,7 @@ import org.apache.cloudstack.api.ApiCommandResourceType;
|
|||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.command.admin.config.ResetCfgCmd;
|
||||
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CloneNetworkOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
|
||||
|
|
@ -76,6 +77,8 @@ import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
|
|||
import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CloneDiskOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CloneServiceOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd;
|
||||
|
|
@ -3854,6 +3857,458 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CLONE, eventDescription = "cloning service offering")
|
||||
public ServiceOffering cloneServiceOffering(final CloneServiceOfferingCmd cmd) {
|
||||
final long userId = CallContext.current().getCallingUserId();
|
||||
final ServiceOfferingVO sourceOffering = getAndValidateSourceOffering(cmd.getSourceOfferingId());
|
||||
final DiskOfferingVO sourceDiskOffering = getSourceDiskOffering(sourceOffering);
|
||||
final Map<String, String> requestParams = cmd.getFullUrlParams();
|
||||
|
||||
final String name = cmd.getServiceOfferingName();
|
||||
final String displayText = getOrDefault(cmd.getDisplayText(), sourceOffering.getDisplayText());
|
||||
final Integer cpuNumber = getOrDefault(cmd.getCpuNumber(), sourceOffering.getCpu());
|
||||
final Integer cpuSpeed = getOrDefault(cmd.getCpuSpeed(), sourceOffering.getSpeed());
|
||||
final Integer memory = getOrDefault(cmd.getMemory(), sourceOffering.getRamSize());
|
||||
final String provisioningType = resolveProvisioningType(cmd, sourceDiskOffering);
|
||||
|
||||
final Boolean offerHa = resolveBooleanParam(requestParams, ApiConstants.OFFER_HA, cmd::isOfferHa, sourceOffering.isOfferHA());
|
||||
final Boolean limitCpuUse = resolveBooleanParam(requestParams, ApiConstants.LIMIT_CPU_USE, cmd::isLimitCpuUse, sourceOffering.getLimitCpuUse());
|
||||
final Boolean isVolatile = resolveBooleanParam(requestParams, ApiConstants.IS_VOLATILE, cmd::isVolatileVm, sourceOffering.isVolatileVm());
|
||||
final Boolean isCustomized = resolveBooleanParam(requestParams, ApiConstants.CUSTOMIZED, cmd::isCustomized, sourceOffering.isCustomized());
|
||||
final Boolean dynamicScalingEnabled = resolveBooleanParam(requestParams, ApiConstants.DYNAMIC_SCALING_ENABLED, cmd::getDynamicScalingEnabled, sourceOffering.isDynamicScalingEnabled());
|
||||
final Boolean diskOfferingStrictness = resolveBooleanParam(requestParams, ApiConstants.DISK_OFFERING_STRICTNESS, cmd::getDiskOfferingStrictness, sourceOffering.getDiskOfferingStrictness());
|
||||
final Boolean encryptRoot = resolveBooleanParam(requestParams, ApiConstants.ENCRYPT_ROOT, cmd::getEncryptRoot, sourceDiskOffering != null && sourceDiskOffering.getEncrypt());
|
||||
final Boolean gpuDisplay = resolveBooleanParam(requestParams, ApiConstants.GPU_DISPLAY, cmd::getGpuDisplay, sourceOffering.getGpuDisplay());
|
||||
|
||||
final String storageType = resolveStorageType(cmd, sourceDiskOffering);
|
||||
final String tags = getOrDefault(cmd.getTags(), sourceDiskOffering != null ? sourceDiskOffering.getTags() : null);
|
||||
final List<Long> domainIds = resolveDomainIds(cmd, sourceOffering);
|
||||
final List<Long> zoneIds = resolveZoneIds(cmd, sourceOffering);
|
||||
final String hostTag = getOrDefault(cmd.getHostTag(), sourceOffering.getHostTag());
|
||||
final Integer networkRate = getOrDefault(cmd.getNetworkRate(), sourceOffering.getRateMbps());
|
||||
final String deploymentPlanner = getOrDefault(cmd.getDeploymentPlanner(), sourceOffering.getDeploymentPlanner());
|
||||
|
||||
final ClonedDiskOfferingParams diskParams = resolveDiskOfferingParams(cmd, sourceDiskOffering);
|
||||
|
||||
final CustomOfferingParams customParams = resolveCustomOfferingParams(cmd, sourceOffering, isCustomized);
|
||||
|
||||
final Long vgpuProfileId = getOrDefault(cmd.getVgpuProfileId(), sourceOffering.getVgpuProfileId());
|
||||
final Integer gpuCount = getOrDefault(cmd.getGpuCount(), sourceOffering.getGpuCount());
|
||||
|
||||
final Boolean purgeResources = resolvePurgeResources(cmd, requestParams, sourceOffering);
|
||||
final LeaseParams leaseParams = resolveLeaseParams(cmd, sourceOffering);
|
||||
|
||||
if (cmd.getCacheMode() != null) {
|
||||
validateCacheMode(cmd.getCacheMode());
|
||||
}
|
||||
final Integer finalGpuCount = validateVgpuProfileAndGetGpuCount(vgpuProfileId, gpuCount);
|
||||
|
||||
final Map<String, String> mergedDetails = mergeOfferingDetails(cmd, sourceOffering, customParams);
|
||||
|
||||
final boolean localStorageRequired = ServiceOffering.StorageType.local.toString().equalsIgnoreCase(storageType);
|
||||
|
||||
final boolean systemUse = sourceOffering.isSystemUse();
|
||||
final VirtualMachine.Type vmType = resolveVmType(sourceOffering);
|
||||
|
||||
final Long diskOfferingId = getOrDefault(cmd.getDiskOfferingId(), sourceOffering.getDiskOfferingId());
|
||||
|
||||
return createServiceOffering(userId, systemUse, vmType,
|
||||
name, cpuNumber, memory, cpuSpeed, displayText, provisioningType, localStorageRequired,
|
||||
offerHa, limitCpuUse, isVolatile, tags, domainIds, zoneIds, hostTag, networkRate,
|
||||
deploymentPlanner, mergedDetails, diskParams.rootDiskSize, diskParams.isCustomizedIops,
|
||||
diskParams.minIops, diskParams.maxIops,
|
||||
diskParams.bytesReadRate, diskParams.bytesReadRateMax, diskParams.bytesReadRateMaxLength,
|
||||
diskParams.bytesWriteRate, diskParams.bytesWriteRateMax, diskParams.bytesWriteRateMaxLength,
|
||||
diskParams.iopsReadRate, diskParams.iopsReadRateMax, diskParams.iopsReadRateMaxLength,
|
||||
diskParams.iopsWriteRate, diskParams.iopsWriteRateMax, diskParams.iopsWriteRateMaxLength,
|
||||
diskParams.hypervisorSnapshotReserve, diskParams.cacheMode, customParams.storagePolicy, dynamicScalingEnabled,
|
||||
diskOfferingId, diskOfferingStrictness, isCustomized, encryptRoot,
|
||||
vgpuProfileId, finalGpuCount, gpuDisplay, purgeResources, leaseParams.leaseDuration, leaseParams.leaseExpiryAction);
|
||||
}
|
||||
|
||||
private ServiceOfferingVO getAndValidateSourceOffering(Long sourceOfferingId) {
|
||||
final ServiceOfferingVO sourceOffering = _serviceOfferingDao.findById(sourceOfferingId);
|
||||
if (sourceOffering == null) {
|
||||
throw new InvalidParameterValueException("Unable to find service offering with ID: " + sourceOfferingId);
|
||||
}
|
||||
return sourceOffering;
|
||||
}
|
||||
|
||||
private DiskOfferingVO getSourceDiskOffering(ServiceOfferingVO sourceOffering) {
|
||||
final Long sourceDiskOfferingId = sourceOffering.getDiskOfferingId();
|
||||
return sourceDiskOfferingId != null ? _diskOfferingDao.findById(sourceDiskOfferingId) : null;
|
||||
}
|
||||
|
||||
private <T> T getOrDefault(T cmdValue, T defaultValue) {
|
||||
return cmdValue != null ? cmdValue : defaultValue;
|
||||
}
|
||||
|
||||
private Boolean resolveBooleanParam(Map<String, String> requestParams, String paramKey,
|
||||
java.util.function.Supplier<Boolean> cmdValueSupplier, Boolean defaultValue) {
|
||||
return requestParams != null && requestParams.containsKey(paramKey) ? cmdValueSupplier.get() : defaultValue;
|
||||
}
|
||||
|
||||
private String resolveProvisioningType(CloneServiceOfferingCmd cmd, DiskOfferingVO sourceDiskOffering) {
|
||||
if (cmd.getProvisioningType() != null) {
|
||||
return cmd.getProvisioningType();
|
||||
}
|
||||
if (sourceDiskOffering != null) {
|
||||
return sourceDiskOffering.getProvisioningType().toString();
|
||||
}
|
||||
return Storage.ProvisioningType.THIN.toString();
|
||||
}
|
||||
|
||||
private String resolveStorageType(CloneServiceOfferingCmd cmd, DiskOfferingVO sourceDiskOffering) {
|
||||
if (cmd.getStorageType() != null) {
|
||||
return cmd.getStorageType();
|
||||
}
|
||||
if (sourceDiskOffering != null && sourceDiskOffering.isUseLocalStorage()) {
|
||||
return ServiceOffering.StorageType.local.toString();
|
||||
}
|
||||
return ServiceOffering.StorageType.shared.toString();
|
||||
}
|
||||
|
||||
private List<Long> resolveDomainIds(CloneServiceOfferingCmd cmd, ServiceOfferingVO sourceOffering) {
|
||||
List<Long> domainIds = cmd.getDomainIds();
|
||||
if (domainIds == null || domainIds.isEmpty()) {
|
||||
domainIds = _serviceOfferingDetailsDao.findDomainIds(sourceOffering.getId());
|
||||
}
|
||||
return domainIds;
|
||||
}
|
||||
|
||||
private List<Long> resolveZoneIds(CloneServiceOfferingCmd cmd, ServiceOfferingVO sourceOffering) {
|
||||
List<Long> zoneIds = cmd.getZoneIds();
|
||||
if (zoneIds == null || zoneIds.isEmpty()) {
|
||||
zoneIds = _serviceOfferingDetailsDao.findZoneIds(sourceOffering.getId());
|
||||
}
|
||||
return zoneIds;
|
||||
}
|
||||
|
||||
private ClonedDiskOfferingParams resolveDiskOfferingParams(CloneServiceOfferingCmd cmd, DiskOfferingVO sourceDiskOffering) {
|
||||
final ClonedDiskOfferingParams params = new ClonedDiskOfferingParams();
|
||||
|
||||
params.rootDiskSize = getOrDefault(cmd.getRootDiskSize(), sourceDiskOffering != null ? sourceDiskOffering.getDiskSize() : null);
|
||||
params.bytesReadRate = getOrDefault(cmd.getBytesReadRate(), sourceDiskOffering != null ? sourceDiskOffering.getBytesReadRate() : null);
|
||||
params.bytesReadRateMax = getOrDefault(cmd.getBytesReadRateMax(), sourceDiskOffering != null ? sourceDiskOffering.getBytesReadRateMax() : null);
|
||||
params.bytesReadRateMaxLength = getOrDefault(cmd.getBytesReadRateMaxLength(), sourceDiskOffering != null ? sourceDiskOffering.getBytesReadRateMaxLength() : null);
|
||||
params.bytesWriteRate = getOrDefault(cmd.getBytesWriteRate(), sourceDiskOffering != null ? sourceDiskOffering.getBytesWriteRate() : null);
|
||||
params.bytesWriteRateMax = getOrDefault(cmd.getBytesWriteRateMax(), sourceDiskOffering != null ? sourceDiskOffering.getBytesWriteRateMax() : null);
|
||||
params.bytesWriteRateMaxLength = getOrDefault(cmd.getBytesWriteRateMaxLength(), sourceDiskOffering != null ? sourceDiskOffering.getBytesWriteRateMaxLength() : null);
|
||||
params.iopsReadRate = getOrDefault(cmd.getIopsReadRate(), sourceDiskOffering != null ? sourceDiskOffering.getIopsReadRate() : null);
|
||||
params.iopsReadRateMax = getOrDefault(cmd.getIopsReadRateMax(), sourceDiskOffering != null ? sourceDiskOffering.getIopsReadRateMax() : null);
|
||||
params.iopsReadRateMaxLength = getOrDefault(cmd.getIopsReadRateMaxLength(), sourceDiskOffering != null ? sourceDiskOffering.getIopsReadRateMaxLength() : null);
|
||||
params.iopsWriteRate = getOrDefault(cmd.getIopsWriteRate(), sourceDiskOffering != null ? sourceDiskOffering.getIopsWriteRate() : null);
|
||||
params.iopsWriteRateMax = getOrDefault(cmd.getIopsWriteRateMax(), sourceDiskOffering != null ? sourceDiskOffering.getIopsWriteRateMax() : null);
|
||||
params.iopsWriteRateMaxLength = getOrDefault(cmd.getIopsWriteRateMaxLength(), sourceDiskOffering != null ? sourceDiskOffering.getIopsWriteRateMaxLength() : null);
|
||||
params.isCustomizedIops = getOrDefault(cmd.isCustomizedIops(), sourceDiskOffering != null ? sourceDiskOffering.isCustomizedIops() : null);
|
||||
params.minIops = getOrDefault(cmd.getMinIops(), sourceDiskOffering != null ? sourceDiskOffering.getMinIops() : null);
|
||||
params.maxIops = getOrDefault(cmd.getMaxIops(), sourceDiskOffering != null ? sourceDiskOffering.getMaxIops() : null);
|
||||
params.hypervisorSnapshotReserve = getOrDefault(cmd.getHypervisorSnapshotReserve(), sourceDiskOffering != null ? sourceDiskOffering.getHypervisorSnapshotReserve() : null);
|
||||
|
||||
if (cmd.getCacheMode() != null) {
|
||||
params.cacheMode = cmd.getCacheMode();
|
||||
} else if (sourceDiskOffering != null && sourceDiskOffering.getCacheMode() != null) {
|
||||
params.cacheMode = sourceDiskOffering.getCacheMode().toString();
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private CustomOfferingParams resolveCustomOfferingParams(CloneServiceOfferingCmd cmd, ServiceOfferingVO sourceOffering, Boolean isCustomized) {
|
||||
final CustomOfferingParams params = new CustomOfferingParams();
|
||||
|
||||
params.maxCPU = resolveDetailParameter(cmd.getMaxCPUs(), sourceOffering.getId(), ApiConstants.MAX_CPU_NUMBER);
|
||||
params.minCPU = resolveDetailParameter(cmd.getMinCPUs(), sourceOffering.getId(), ApiConstants.MIN_CPU_NUMBER);
|
||||
params.maxMemory = resolveDetailParameter(cmd.getMaxMemory(), sourceOffering.getId(), ApiConstants.MAX_MEMORY);
|
||||
params.minMemory = resolveDetailParameter(cmd.getMinMemory(), sourceOffering.getId(), ApiConstants.MIN_MEMORY);
|
||||
params.storagePolicy = resolveDetailParameterAsLong(cmd.getStoragePolicy(), sourceOffering.getId(), ApiConstants.STORAGE_POLICY);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private Integer resolveDetailParameter(Integer cmdValue, Long offeringId, String detailKey) {
|
||||
if (cmdValue != null) {
|
||||
return cmdValue;
|
||||
}
|
||||
String detailValue = _serviceOfferingDetailsDao.getDetail(offeringId, detailKey);
|
||||
return detailValue != null ? Integer.parseInt(detailValue) : null;
|
||||
}
|
||||
|
||||
private Long resolveDetailParameterAsLong(Long cmdValue, Long offeringId, String detailKey) {
|
||||
if (cmdValue != null) {
|
||||
return cmdValue;
|
||||
}
|
||||
String detailValue = _serviceOfferingDetailsDao.getDetail(offeringId, detailKey);
|
||||
return detailValue != null ? Long.parseLong(detailValue) : null;
|
||||
}
|
||||
|
||||
private Boolean resolvePurgeResources(CloneServiceOfferingCmd cmd, Map<String, String> requestParams, ServiceOfferingVO sourceOffering) {
|
||||
if (requestParams != null && requestParams.containsKey(ApiConstants.PURGE_RESOURCES)) {
|
||||
return cmd.isPurgeResources();
|
||||
}
|
||||
String purgeResourcesStr = _serviceOfferingDetailsDao.getDetail(sourceOffering.getId(), ServiceOffering.PURGE_DB_ENTITIES_KEY);
|
||||
return Boolean.parseBoolean(purgeResourcesStr);
|
||||
}
|
||||
|
||||
private LeaseParams resolveLeaseParams(CloneServiceOfferingCmd cmd, ServiceOfferingVO sourceOffering) {
|
||||
final LeaseParams params = new LeaseParams();
|
||||
|
||||
params.leaseDuration = resolveDetailParameter(cmd.getLeaseDuration(), sourceOffering.getId(), ApiConstants.INSTANCE_LEASE_DURATION);
|
||||
|
||||
if (cmd.getLeaseExpiryAction() != null) {
|
||||
params.leaseExpiryAction = cmd.getLeaseExpiryAction();
|
||||
} else {
|
||||
String leaseExpiryActionStr = _serviceOfferingDetailsDao.getDetail(sourceOffering.getId(), ApiConstants.INSTANCE_LEASE_EXPIRY_ACTION);
|
||||
if (leaseExpiryActionStr != null) {
|
||||
params.leaseExpiryAction = VMLeaseManager.ExpiryAction.valueOf(leaseExpiryActionStr);
|
||||
}
|
||||
}
|
||||
|
||||
params.leaseExpiryAction = validateAndGetLeaseExpiryAction(params.leaseDuration, params.leaseExpiryAction);
|
||||
return params;
|
||||
}
|
||||
|
||||
private Map<String, String> mergeOfferingDetails(CloneServiceOfferingCmd cmd, ServiceOfferingVO sourceOffering, CustomOfferingParams customParams) {
|
||||
final Map<String, String> cmdDetails = cmd.getDetails();
|
||||
final Map<String, String> mergedDetails = new HashMap<>();
|
||||
|
||||
if (cmdDetails == null || cmdDetails.isEmpty()) {
|
||||
Map<String, String> sourceDetails = _serviceOfferingDetailsDao.listDetailsKeyPairs(sourceOffering.getId());
|
||||
if (sourceDetails != null) {
|
||||
mergedDetails.putAll(sourceDetails);
|
||||
}
|
||||
} else {
|
||||
mergedDetails.putAll(cmdDetails);
|
||||
}
|
||||
|
||||
if (customParams.minCPU != null && customParams.maxCPU != null &&
|
||||
customParams.minMemory != null && customParams.maxMemory != null) {
|
||||
mergedDetails.put(ApiConstants.MIN_MEMORY, customParams.minMemory.toString());
|
||||
mergedDetails.put(ApiConstants.MAX_MEMORY, customParams.maxMemory.toString());
|
||||
mergedDetails.put(ApiConstants.MIN_CPU_NUMBER, customParams.minCPU.toString());
|
||||
mergedDetails.put(ApiConstants.MAX_CPU_NUMBER, customParams.maxCPU.toString());
|
||||
}
|
||||
|
||||
return mergedDetails;
|
||||
}
|
||||
|
||||
private VirtualMachine.Type resolveVmType(ServiceOfferingVO sourceOffering) {
|
||||
if (sourceOffering.getVmType() == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return VirtualMachine.Type.valueOf(sourceOffering.getVmType());
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.warn("Invalid VM type in source offering: {}", sourceOffering.getVmType());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClonedDiskOfferingParams {
|
||||
Long rootDiskSize;
|
||||
Long bytesReadRate;
|
||||
Long bytesReadRateMax;
|
||||
Long bytesReadRateMaxLength;
|
||||
Long bytesWriteRate;
|
||||
Long bytesWriteRateMax;
|
||||
Long bytesWriteRateMaxLength;
|
||||
Long iopsReadRate;
|
||||
Long iopsReadRateMax;
|
||||
Long iopsReadRateMaxLength;
|
||||
Long iopsWriteRate;
|
||||
Long iopsWriteRateMax;
|
||||
Long iopsWriteRateMaxLength;
|
||||
Boolean isCustomizedIops;
|
||||
Long minIops;
|
||||
Long maxIops;
|
||||
Integer hypervisorSnapshotReserve;
|
||||
String cacheMode;
|
||||
}
|
||||
|
||||
private static class CustomOfferingParams {
|
||||
Integer maxCPU;
|
||||
Integer minCPU;
|
||||
Integer maxMemory;
|
||||
Integer minMemory;
|
||||
Long storagePolicy;
|
||||
}
|
||||
|
||||
private static class LeaseParams {
|
||||
Integer leaseDuration;
|
||||
VMLeaseManager.ExpiryAction leaseExpiryAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiskOffering cloneDiskOffering(final CloneDiskOfferingCmd cmd) {
|
||||
final long userId = CallContext.current().getCallingUserId();
|
||||
final DiskOfferingVO sourceOffering = getAndValidateSourceDiskOffering(cmd.getSourceOfferingId());
|
||||
final Map<String, String> requestParams = cmd.getFullUrlParams();
|
||||
|
||||
final String name = cmd.getOfferingName();
|
||||
final String displayText = getOrDefault(cmd.getDisplayText(), sourceOffering.getDisplayText());
|
||||
final String provisioningType = getOrDefault(cmd.getProvisioningType(), sourceOffering.getProvisioningType().toString());
|
||||
final Long diskSize = getOrDefault(cmd.getDiskSize(), sourceOffering.getDiskSize());
|
||||
final String tags = getOrDefault(cmd.getTags(), sourceOffering.getTags());
|
||||
|
||||
final Boolean isCustomized = resolveBooleanParam(requestParams, ApiConstants.CUSTOMIZED, cmd::isCustomized, sourceOffering.isCustomized());
|
||||
final Boolean displayOffering = resolveBooleanParam(requestParams, ApiConstants.DISPLAY_OFFERING, cmd::getDisplayOffering, sourceOffering.getDisplayOffering());
|
||||
final Boolean isCustomizedIops = getOrDefault(cmd.isCustomizedIops(), sourceOffering.isCustomizedIops());
|
||||
final Boolean diskSizeStrictness = resolveBooleanParam(requestParams, ApiConstants.DISK_SIZE_STRICTNESS, cmd::getDiskSizeStrictness, sourceOffering.getDiskSizeStrictness());
|
||||
final Boolean encrypt = resolveBooleanParam(requestParams, ApiConstants.ENCRYPT, cmd::getEncrypt, sourceOffering.getEncrypt());
|
||||
|
||||
final List<Long> domainIds = resolveDomainIdsForDiskOffering(cmd, sourceOffering);
|
||||
final List<Long> zoneIds = resolveZoneIdsForDiskOffering(cmd, sourceOffering);
|
||||
|
||||
final boolean localStorageRequired = resolveLocalStorageRequired(cmd, sourceOffering);
|
||||
|
||||
final ClonedDiskIopsParams iopsParams = resolveDiskIopsParams(cmd, sourceOffering);
|
||||
|
||||
final ClonedDiskRateParams rateParams = resolveDiskRateParams(cmd, sourceOffering);
|
||||
|
||||
final Integer hypervisorSnapshotReserve = getOrDefault(cmd.getHypervisorSnapshotReserve(), sourceOffering.getHypervisorSnapshotReserve());
|
||||
final String cacheMode = resolveCacheMode(cmd, sourceOffering);
|
||||
final Long storagePolicy = resolveStoragePolicyForDiskOffering(cmd, sourceOffering);
|
||||
|
||||
final Map<String, String> mergedDetails = mergeDiskOfferingDetails(cmd, sourceOffering);
|
||||
|
||||
if (cmd.getCacheMode() != null) {
|
||||
validateCacheMode(cmd.getCacheMode());
|
||||
}
|
||||
|
||||
validateMaxRateEqualsOrGreater(iopsParams.iopsReadRate, iopsParams.iopsReadRateMax, IOPS_READ_RATE);
|
||||
validateMaxRateEqualsOrGreater(iopsParams.iopsWriteRate, iopsParams.iopsWriteRateMax, IOPS_WRITE_RATE);
|
||||
validateMaxRateEqualsOrGreater(rateParams.bytesReadRate, rateParams.bytesReadRateMax, BYTES_READ_RATE);
|
||||
validateMaxRateEqualsOrGreater(rateParams.bytesWriteRate, rateParams.bytesWriteRateMax, BYTES_WRITE_RATE);
|
||||
validateMaximumIopsAndBytesLength(iopsParams.iopsReadRateMaxLength, iopsParams.iopsWriteRateMaxLength,
|
||||
rateParams.bytesReadRateMaxLength, rateParams.bytesWriteRateMaxLength);
|
||||
|
||||
return createDiskOffering(userId, domainIds, zoneIds, name, displayText, provisioningType, diskSize, tags,
|
||||
isCustomized, localStorageRequired, displayOffering, isCustomizedIops, iopsParams.minIops, iopsParams.maxIops,
|
||||
rateParams.bytesReadRate, rateParams.bytesReadRateMax, rateParams.bytesReadRateMaxLength,
|
||||
rateParams.bytesWriteRate, rateParams.bytesWriteRateMax, rateParams.bytesWriteRateMaxLength,
|
||||
iopsParams.iopsReadRate, iopsParams.iopsReadRateMax, iopsParams.iopsReadRateMaxLength,
|
||||
iopsParams.iopsWriteRate, iopsParams.iopsWriteRateMax, iopsParams.iopsWriteRateMaxLength,
|
||||
hypervisorSnapshotReserve, cacheMode, mergedDetails, storagePolicy, diskSizeStrictness, encrypt);
|
||||
}
|
||||
|
||||
private DiskOfferingVO getAndValidateSourceDiskOffering(Long sourceOfferingId) {
|
||||
final DiskOfferingVO sourceOffering = _diskOfferingDao.findById(sourceOfferingId);
|
||||
if (sourceOffering == null) {
|
||||
throw new InvalidParameterValueException("Unable to find disk offering with ID: " + sourceOfferingId);
|
||||
}
|
||||
return sourceOffering;
|
||||
}
|
||||
|
||||
private List<Long> resolveDomainIdsForDiskOffering(CloneDiskOfferingCmd cmd, DiskOfferingVO sourceOffering) {
|
||||
List<Long> domainIds = cmd.getDomainIds();
|
||||
if (domainIds == null || domainIds.isEmpty()) {
|
||||
domainIds = diskOfferingDetailsDao.findDomainIds(sourceOffering.getId());
|
||||
}
|
||||
return domainIds;
|
||||
}
|
||||
|
||||
private List<Long> resolveZoneIdsForDiskOffering(CloneDiskOfferingCmd cmd, DiskOfferingVO sourceOffering) {
|
||||
List<Long> zoneIds = cmd.getZoneIds();
|
||||
if (zoneIds == null || zoneIds.isEmpty()) {
|
||||
zoneIds = diskOfferingDetailsDao.findZoneIds(sourceOffering.getId());
|
||||
}
|
||||
return zoneIds;
|
||||
}
|
||||
|
||||
private boolean resolveLocalStorageRequired(CloneDiskOfferingCmd cmd, DiskOfferingVO sourceOffering) {
|
||||
if (cmd.getStorageType() != null) {
|
||||
return ServiceOffering.StorageType.local.toString().equalsIgnoreCase(cmd.getStorageType());
|
||||
}
|
||||
return sourceOffering.isUseLocalStorage();
|
||||
}
|
||||
|
||||
private String resolveCacheMode(CloneDiskOfferingCmd cmd, DiskOfferingVO sourceOffering) {
|
||||
if (cmd.getCacheMode() != null) {
|
||||
return cmd.getCacheMode();
|
||||
}
|
||||
if (sourceOffering.getCacheMode() != null) {
|
||||
return sourceOffering.getCacheMode().toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Long resolveStoragePolicyForDiskOffering(CloneDiskOfferingCmd cmd, DiskOfferingVO sourceOffering) {
|
||||
Long storagePolicy = cmd.getStoragePolicy();
|
||||
if (storagePolicy == null) {
|
||||
String storagePolicyStr = diskOfferingDetailsDao.getDetail(sourceOffering.getId(), ApiConstants.STORAGE_POLICY);
|
||||
if (storagePolicyStr != null) {
|
||||
storagePolicy = Long.parseLong(storagePolicyStr);
|
||||
}
|
||||
}
|
||||
return storagePolicy;
|
||||
}
|
||||
|
||||
private ClonedDiskIopsParams resolveDiskIopsParams(CloneDiskOfferingCmd cmd, DiskOfferingVO sourceOffering) {
|
||||
final ClonedDiskIopsParams params = new ClonedDiskIopsParams();
|
||||
|
||||
params.minIops = getOrDefault(cmd.getMinIops(), sourceOffering.getMinIops());
|
||||
params.maxIops = getOrDefault(cmd.getMaxIops(), sourceOffering.getMaxIops());
|
||||
params.iopsReadRate = getOrDefault(cmd.getIopsReadRate(), sourceOffering.getIopsReadRate());
|
||||
params.iopsReadRateMax = getOrDefault(cmd.getIopsReadRateMax(), sourceOffering.getIopsReadRateMax());
|
||||
params.iopsReadRateMaxLength = getOrDefault(cmd.getIopsReadRateMaxLength(), sourceOffering.getIopsReadRateMaxLength());
|
||||
params.iopsWriteRate = getOrDefault(cmd.getIopsWriteRate(), sourceOffering.getIopsWriteRate());
|
||||
params.iopsWriteRateMax = getOrDefault(cmd.getIopsWriteRateMax(), sourceOffering.getIopsWriteRateMax());
|
||||
params.iopsWriteRateMaxLength = getOrDefault(cmd.getIopsWriteRateMaxLength(), sourceOffering.getIopsWriteRateMaxLength());
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private ClonedDiskRateParams resolveDiskRateParams(CloneDiskOfferingCmd cmd, DiskOfferingVO sourceOffering) {
|
||||
final ClonedDiskRateParams params = new ClonedDiskRateParams();
|
||||
|
||||
params.bytesReadRate = getOrDefault(cmd.getBytesReadRate(), sourceOffering.getBytesReadRate());
|
||||
params.bytesReadRateMax = getOrDefault(cmd.getBytesReadRateMax(), sourceOffering.getBytesReadRateMax());
|
||||
params.bytesReadRateMaxLength = getOrDefault(cmd.getBytesReadRateMaxLength(), sourceOffering.getBytesReadRateMaxLength());
|
||||
params.bytesWriteRate = getOrDefault(cmd.getBytesWriteRate(), sourceOffering.getBytesWriteRate());
|
||||
params.bytesWriteRateMax = getOrDefault(cmd.getBytesWriteRateMax(), sourceOffering.getBytesWriteRateMax());
|
||||
params.bytesWriteRateMaxLength = getOrDefault(cmd.getBytesWriteRateMaxLength(), sourceOffering.getBytesWriteRateMaxLength());
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private Map<String, String> mergeDiskOfferingDetails(CloneDiskOfferingCmd cmd, DiskOfferingVO sourceOffering) {
|
||||
final Map<String, String> cmdDetails = cmd.getDetails();
|
||||
final Map<String, String> mergedDetails = new HashMap<>();
|
||||
|
||||
if (cmdDetails == null || cmdDetails.isEmpty()) {
|
||||
Map<String, String> sourceDetails = diskOfferingDetailsDao.listDetailsKeyPairs(sourceOffering.getId());
|
||||
if (sourceDetails != null) {
|
||||
mergedDetails.putAll(sourceDetails);
|
||||
}
|
||||
} else {
|
||||
mergedDetails.putAll(cmdDetails);
|
||||
}
|
||||
|
||||
return mergedDetails;
|
||||
}
|
||||
|
||||
// Helper classes for disk offering parameters
|
||||
private static class ClonedDiskIopsParams {
|
||||
Long minIops;
|
||||
Long maxIops;
|
||||
Long iopsReadRate;
|
||||
Long iopsReadRateMax;
|
||||
Long iopsReadRateMaxLength;
|
||||
Long iopsWriteRate;
|
||||
Long iopsWriteRateMax;
|
||||
Long iopsWriteRateMaxLength;
|
||||
}
|
||||
|
||||
private static class ClonedDiskRateParams {
|
||||
Long bytesReadRate;
|
||||
Long bytesReadRateMax;
|
||||
Long bytesReadRateMaxLength;
|
||||
Long bytesWriteRate;
|
||||
Long bytesWriteRateMax;
|
||||
Long bytesWriteRateMaxLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_EDIT, eventDescription = "updating service offering")
|
||||
public ServiceOffering updateServiceOffering(final UpdateServiceOfferingCmd cmd) {
|
||||
|
|
@ -7827,6 +8282,212 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_OFFERING_CREATE, eventDescription = "cloning network offering")
|
||||
public NetworkOffering cloneNetworkOffering(final CloneNetworkOfferingCmd cmd) {
|
||||
final Long sourceOfferingId = cmd.getSourceOfferingId();
|
||||
|
||||
final NetworkOfferingVO sourceOffering = _networkOfferingDao.findById(sourceOfferingId);
|
||||
if (sourceOffering == null) {
|
||||
throw new InvalidParameterValueException("Unable to find network offering with id " + sourceOfferingId);
|
||||
}
|
||||
|
||||
String name = cmd.getNetworkOfferingName();
|
||||
if (name == null || name.isEmpty()) {
|
||||
throw new InvalidParameterValueException("Name is required when cloning a network offering");
|
||||
}
|
||||
|
||||
NetworkOfferingVO existing = _networkOfferingDao.findByUniqueName(name);
|
||||
if (existing != null) {
|
||||
throw new InvalidParameterValueException("Network offering with name '" + name + "' already exists");
|
||||
}
|
||||
|
||||
logger.info("Cloning network offering {} (id: {}) to new offering with name: {}",
|
||||
sourceOffering.getName(), sourceOfferingId, name);
|
||||
|
||||
// Resolve parameters from source offering and apply add/drop logic
|
||||
applySourceOfferingValuesToCloneCmd(cmd, sourceOffering);
|
||||
|
||||
return createNetworkOffering(cmd);
|
||||
}
|
||||
|
||||
private void applySourceOfferingValuesToCloneCmd(CloneNetworkOfferingCmd cmd, NetworkOfferingVO sourceOffering) {
|
||||
Long sourceOfferingId = sourceOffering.getId();
|
||||
|
||||
Map<Network.Service, Set<Network.Provider>> sourceServiceProviderMap =
|
||||
_networkModel.getNetworkOfferingServiceProvidersMap(sourceOfferingId);
|
||||
|
||||
// Build final services list with add/drop support
|
||||
List<String> finalServices = resolveFinalServicesList(cmd, sourceServiceProviderMap);
|
||||
|
||||
Map finalServiceProviderMap = resolveServiceProviderMap(cmd, sourceServiceProviderMap, finalServices);
|
||||
|
||||
Map<String, String> sourceDetailsMap = getSourceOfferingDetails(sourceOfferingId);
|
||||
|
||||
List<Long> sourceDomainIds = networkOfferingDetailsDao.findDomainIds(sourceOfferingId);
|
||||
List<Long> sourceZoneIds = networkOfferingDetailsDao.findZoneIds(sourceOfferingId);
|
||||
|
||||
applyResolvedValuesToCommand(cmd, sourceOffering, finalServices, finalServiceProviderMap,
|
||||
sourceDetailsMap, sourceDomainIds, sourceZoneIds);
|
||||
}
|
||||
|
||||
private Map<String, String> getSourceOfferingDetails(Long sourceOfferingId) {
|
||||
List<NetworkOfferingDetailsVO> sourceDetailsVOs = networkOfferingDetailsDao.listDetails(sourceOfferingId);
|
||||
Map<String, String> sourceDetailsMap = new HashMap<>();
|
||||
for (NetworkOfferingDetailsVO detailVO : sourceDetailsVOs) {
|
||||
sourceDetailsMap.put(detailVO.getName(), detailVO.getValue());
|
||||
}
|
||||
return sourceDetailsMap;
|
||||
}
|
||||
|
||||
private List<String> resolveFinalServicesList(CloneNetworkOfferingCmd cmd,
|
||||
Map<Network.Service, Set<Network.Provider>> sourceServiceProviderMap) {
|
||||
|
||||
List<String> cmdServices = cmd.getSupportedServices();
|
||||
List<String> addServices = cmd.getAddServices();
|
||||
List<String> dropServices = cmd.getDropServices();
|
||||
|
||||
if (cmdServices != null && !cmdServices.isEmpty()) {
|
||||
return cmdServices;
|
||||
}
|
||||
|
||||
List<String> finalServices = new ArrayList<>();
|
||||
for (Network.Service service : sourceServiceProviderMap.keySet()) {
|
||||
finalServices.add(service.getName());
|
||||
}
|
||||
|
||||
if (dropServices != null && !dropServices.isEmpty()) {
|
||||
finalServices.removeAll(dropServices);
|
||||
logger.debug("Dropped services from clone: {}", dropServices);
|
||||
}
|
||||
|
||||
if (addServices != null && !addServices.isEmpty()) {
|
||||
for (String service : addServices) {
|
||||
if (!finalServices.contains(service)) {
|
||||
finalServices.add(service);
|
||||
}
|
||||
}
|
||||
logger.debug("Added services to clone: {}", addServices);
|
||||
}
|
||||
|
||||
return finalServices;
|
||||
}
|
||||
|
||||
private Map<String, List<String>> resolveServiceProviderMap(CloneNetworkOfferingCmd cmd,
|
||||
Map<Network.Service, Set<Network.Provider>> sourceServiceProviderMap, List<String> finalServices) {
|
||||
|
||||
if (cmd.getServiceProviders() != null && !cmd.getServiceProviders().isEmpty()) {
|
||||
return cmd.getServiceProviders();
|
||||
}
|
||||
|
||||
Map<String, List<String>> finalMap = new HashMap<>();
|
||||
for (Map.Entry<Network.Service, Set<Network.Provider>> entry : sourceServiceProviderMap.entrySet()) {
|
||||
String serviceName = entry.getKey().getName();
|
||||
if (finalServices.contains(serviceName)) {
|
||||
List<String> providers = new ArrayList<>();
|
||||
for (Network.Provider provider : entry.getValue()) {
|
||||
providers.add(provider.getName());
|
||||
}
|
||||
finalMap.put(serviceName, providers);
|
||||
}
|
||||
}
|
||||
|
||||
return finalMap;
|
||||
}
|
||||
|
||||
private void applyResolvedValuesToCommand(CloneNetworkOfferingCmd cmd, NetworkOfferingVO sourceOffering,
|
||||
List<String> finalServices, Map finalServiceProviderMap, Map<String, String> sourceDetailsMap,
|
||||
List<Long> sourceDomainIds, List<Long> sourceZoneIds) {
|
||||
|
||||
try {
|
||||
Map<String, String> requestParams = cmd.getFullUrlParams();
|
||||
|
||||
if (cmd.getSupportedServices() == null || cmd.getSupportedServices().isEmpty()) {
|
||||
setField(cmd, "supportedServices", finalServices);
|
||||
}
|
||||
if (cmd.getServiceProviders() == null || cmd.getServiceProviders().isEmpty()) {
|
||||
setField(cmd, "serviceProviderList", finalServiceProviderMap);
|
||||
}
|
||||
|
||||
|
||||
applyIfNotProvided(cmd, requestParams, "displayText", ApiConstants.DISPLAY_TEXT, cmd.getDisplayText(), sourceOffering.getDisplayText());
|
||||
applyIfNotProvided(cmd, requestParams, "traffictype", ApiConstants.TRAFFIC_TYPE, cmd.getTraffictype(), sourceOffering.getTrafficType().toString());
|
||||
applyIfNotProvided(cmd, requestParams, "tags", ApiConstants.TAGS, cmd.getTags(), sourceOffering.getTags());
|
||||
applyIfNotProvided(cmd, requestParams, "availability", ApiConstants.AVAILABILITY, cmd.getAvailability(), sourceOffering.getAvailability().toString());
|
||||
applyIfNotProvided(cmd, requestParams, "networkRate", ApiConstants.NETWORKRATE, cmd.getNetworkRate(), sourceOffering.getRateMbps());
|
||||
applyIfNotProvided(cmd, requestParams, "serviceOfferingId", ApiConstants.SERVICE_OFFERING_ID, cmd.getServiceOfferingId(), sourceOffering.getServiceOfferingId());
|
||||
applyIfNotProvided(cmd, requestParams, "guestIptype", ApiConstants.GUEST_IP_TYPE, cmd.getGuestIpType(), sourceOffering.getGuestType().toString());
|
||||
applyIfNotProvided(cmd, requestParams, "maxConnections", ApiConstants.MAX_CONNECTIONS, cmd.getMaxconnections(), sourceOffering.getConcurrentConnections());
|
||||
|
||||
applyBooleanIfNotProvided(cmd, requestParams, "specifyVlan", ApiConstants.SPECIFY_VLAN, sourceOffering.isSpecifyVlan());
|
||||
applyBooleanIfNotProvided(cmd, requestParams, "conserveMode", ApiConstants.CONSERVE_MODE, sourceOffering.isConserveMode());
|
||||
applyBooleanIfNotProvided(cmd, requestParams, "specifyIpRanges", ApiConstants.SPECIFY_IP_RANGES, sourceOffering.isSpecifyIpRanges());
|
||||
applyBooleanIfNotProvided(cmd, requestParams, "isPersistent", ApiConstants.IS_PERSISTENT, sourceOffering.isPersistent());
|
||||
applyBooleanIfNotProvided(cmd, requestParams, "forVpc", ApiConstants.FOR_VPC, sourceOffering.isForVpc());
|
||||
applyBooleanIfNotProvided(cmd, requestParams, "egressDefaultPolicy", ApiConstants.EGRESS_DEFAULT_POLICY, sourceOffering.isEgressDefaultPolicy());
|
||||
applyBooleanIfNotProvided(cmd, requestParams, "keepAliveEnabled", ApiConstants.KEEPALIVE_ENABLED, sourceOffering.isKeepAliveEnabled());
|
||||
applyBooleanIfNotProvided(cmd, requestParams, "enable", ApiConstants.ENABLE, sourceOffering.getState() == NetworkOffering.State.Enabled);
|
||||
applyBooleanIfNotProvided(cmd, requestParams, "specifyAsNumber", ApiConstants.SPECIFY_AS_NUMBER, sourceOffering.isSpecifyAsNumber());
|
||||
|
||||
if (!requestParams.containsKey(ApiConstants.INTERNET_PROTOCOL)) {
|
||||
String internetProtocol = networkOfferingDetailsDao.getDetail(sourceOffering.getId(), Detail.internetProtocol);
|
||||
if (internetProtocol != null) {
|
||||
setField(cmd, "internetProtocol", internetProtocol);
|
||||
}
|
||||
}
|
||||
|
||||
if (!requestParams.containsKey(ApiConstants.NETWORK_MODE) && sourceOffering.getNetworkMode() != null) {
|
||||
setField(cmd, "networkMode", sourceOffering.getNetworkMode().toString());
|
||||
}
|
||||
|
||||
if (!requestParams.containsKey(ApiConstants.ROUTING_MODE) && sourceOffering.getRoutingMode() != null) {
|
||||
setField(cmd, "routingMode", sourceOffering.getRoutingMode().toString());
|
||||
}
|
||||
|
||||
if (cmd.getDetails() == null || cmd.getDetails().isEmpty()) {
|
||||
if (!sourceDetailsMap.isEmpty()) {
|
||||
setField(cmd, "details", sourceDetailsMap);
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd.getDomainIds() == null || cmd.getDomainIds().isEmpty()) {
|
||||
if (sourceDomainIds != null && !sourceDomainIds.isEmpty()) {
|
||||
setField(cmd, "domainIds", sourceDomainIds);
|
||||
}
|
||||
}
|
||||
if (cmd.getZoneIds() == null || cmd.getZoneIds().isEmpty()) {
|
||||
if (sourceZoneIds != null && !sourceZoneIds.isEmpty()) {
|
||||
setField(cmd, "zoneIds", sourceZoneIds);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to apply some source offering parameters during clone: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void applyIfNotProvided(Object cmd, Map<String, String> requestParams, String fieldName,
|
||||
String apiConstant, Object currentValue, Object sourceValue) throws Exception {
|
||||
// If parameter was not provided in request and source has a value, use source value
|
||||
if (!requestParams.containsKey(apiConstant) && sourceValue != null) {
|
||||
setField(cmd, fieldName, sourceValue);
|
||||
}
|
||||
// If parameter WAS provided in request, the framework already set it correctly
|
||||
}
|
||||
|
||||
private void applyBooleanIfNotProvided(Object cmd, Map<String, String> requestParams,
|
||||
String fieldName, String apiConstant, Boolean sourceValue) throws Exception {
|
||||
if (!requestParams.containsKey(apiConstant) && sourceValue != null) {
|
||||
setField(cmd, fieldName, sourceValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void setField(Object obj, String fieldName, Object value) throws Exception {
|
||||
java.lang.reflect.Field field = obj.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(obj, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_OFFERING_EDIT, eventDescription = "updating network offering")
|
||||
public NetworkOffering updateNetworkOffering(final UpdateNetworkOfferingCmd cmd) {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ import org.apache.cloudstack.api.command.admin.management.ListMgmtsCmd;
|
|||
import org.apache.cloudstack.api.command.admin.management.RemoveManagementServerCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.AddNetworkDeviceCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.AddNetworkServiceProviderCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CloneNetworkOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateNetworkCmdByAdmin;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
|
||||
|
|
@ -161,6 +162,8 @@ import org.apache.cloudstack.api.command.admin.network.UpdateNetworkServiceProvi
|
|||
import org.apache.cloudstack.api.command.admin.network.UpdatePhysicalNetworkCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.UpdateStorageNetworkIpRangeCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CloneDiskOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CloneServiceOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd;
|
||||
|
|
@ -3856,6 +3859,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||
cmdList.add(AddNetworkDeviceCmd.class);
|
||||
cmdList.add(AddNetworkServiceProviderCmd.class);
|
||||
cmdList.add(CreateNetworkOfferingCmd.class);
|
||||
cmdList.add(CloneNetworkOfferingCmd.class);
|
||||
cmdList.add(CreatePhysicalNetworkCmd.class);
|
||||
cmdList.add(CreateStorageNetworkIpRangeCmd.class);
|
||||
cmdList.add(DeleteNetworkDeviceCmd.class);
|
||||
|
|
@ -3876,7 +3880,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||
cmdList.add(ListDedicatedGuestVlanRangesCmd.class);
|
||||
cmdList.add(ReleaseDedicatedGuestVlanRangeCmd.class);
|
||||
cmdList.add(CreateDiskOfferingCmd.class);
|
||||
cmdList.add(CloneDiskOfferingCmd.class);
|
||||
cmdList.add(CreateServiceOfferingCmd.class);
|
||||
cmdList.add(CloneServiceOfferingCmd.class);
|
||||
cmdList.add(DeleteDiskOfferingCmd.class);
|
||||
cmdList.add(DeleteServiceOfferingCmd.class);
|
||||
cmdList.add(IsAccountAllowedToCreateOfferingsWithTagsCmd.class);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import com.cloud.utils.component.ManagerBase;
|
|||
import com.cloud.utils.net.NetUtils;
|
||||
import org.apache.cloudstack.api.command.admin.config.ResetCfgCmd;
|
||||
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CloneNetworkOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
|
||||
|
|
@ -60,6 +61,8 @@ import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
|
|||
import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CloneDiskOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CloneServiceOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd;
|
||||
|
|
@ -117,6 +120,24 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceOffering cloneServiceOffering(CloneServiceOfferingCmd cmd) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiskOffering cloneDiskOffering(CloneDiskOfferingCmd cmd) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkOffering cloneNetworkOffering(CloneNetworkOfferingCmd cmd) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.cloud.configuration.ConfigurationService#updateServiceOffering(org.apache.cloudstack.api.commands.UpdateServiceOfferingCmd)
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue