Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
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;
Expand All @@ -33,6 +34,8 @@
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;
Expand Down Expand Up @@ -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
*
Expand Down
2 changes: 2 additions & 0 deletions api/src/main/java/com/cloud/event/EventTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -628,6 +629,7 @@ public class EventTypes {

// Backup and Recovery events
public static final String EVENT_VM_BACKUP_IMPORT_OFFERING = "BACKUP.IMPORT.OFFERING";
public static final String EVENT_VM_BACKUP_CLONE_OFFERING = "BACKUP.CLONE.OFFERING";
public static final String EVENT_VM_BACKUP_OFFERING_ASSIGN = "BACKUP.OFFERING.ASSIGN";
public static final String EVENT_VM_BACKUP_OFFERING_REMOVE = "BACKUP.OFFERING.REMOVE";
public static final String EVENT_VM_BACKUP_CREATE = "BACKUP.CREATE";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.List;
import java.util.Map;

import org.apache.cloudstack.api.command.admin.vpc.CloneVPCOfferingCmd;
import org.apache.cloudstack.api.command.admin.vpc.CreateVPCOfferingCmd;
import org.apache.cloudstack.api.command.admin.vpc.UpdateVPCOfferingCmd;
import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd;
Expand All @@ -34,6 +35,8 @@ public interface VpcProvisioningService {

VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd);

VpcOffering cloneVPCOffering(CloneVPCOfferingCmd cmd);

VpcOffering createVpcOffering(String name, String displayText, List<String> supportedServices,
Map<String, List<String>> serviceProviders,
Map serviceCapabilitystList, NetUtils.InternetProtocol internetProtocol,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,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";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 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.backup;

import org.apache.cloudstack.acl.RoleType;
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.BackupOfferingResponse;
import org.apache.cloudstack.backup.BackupOffering;

import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;

@APICommand(name = "cloneBackupOffering",
description = "Clones an existing backup offering with updated values. " +
"All parameters are copied from the source offering unless explicitly overridden.",
responseObject = BackupOfferingResponse.class,
since = "4.23.0",
authorized = {RoleType.Admin})
public class CloneBackupOfferingCmd extends ImportBackupOfferingCmd {

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////

@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = BackupOfferingResponse.class,
required = true,
description = "The ID of the backup offering to clone")
private Long id;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////

public Long getId() {
return id;
}


/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException,
ServerApiException, ConcurrentOperationException, ResourceAllocationException,
NetworkRuleConflictException {
try {
BackupOffering clonedOffering = backupManager.cloneBackupOffering(this);
if (clonedOffering != null) {
BackupOfferingResponse response = _responseGenerator.createBackupOfferingResponse(clonedOffering);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clone backup offering");
}
} catch (InvalidParameterValueException e) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage());
} catch (CloudRuntimeException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}

@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_CLONE_OFFERING;
}

@Override
public String getEventDescription() {
return "Cloning backup offering from ID: " + id + " to new offering: " + getName();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
public class ImportBackupOfferingCmd extends BaseAsyncCmd {

@Inject
private BackupManager backupManager;
protected BackupManager backupManager;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// 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;
}

/**
* Override to provide placeholder values that will be replaced with source offering values.
* This allows API validation to pass even though these are marked as required in the parent class.
*/
@Override
public String getGuestIpType() {
String value = super.getGuestIpType();
// Return placeholder if not provided - will be overwritten from source offering
return value != null ? value : "Isolated";
}

@Override
public String getTraffictype() {
String value = super.getTraffictype();
// Return placeholder if not provided - will be overwritten from source offering
return value != null ? value : "Guest";
}

/////////////////////////////////////////////////////
/////////////// 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");
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public class CreateNetworkOfferingCmd extends BaseCmd {
private Map serviceProviderList;

@Parameter(name = ApiConstants.SERVICE_CAPABILITY_LIST, type = CommandType.MAP, description = "Desired service capabilities as part of network offering")
private Map serviceCapabilitystList;
private Map serviceCapabilitiesList;

@Parameter(name = ApiConstants.SPECIFY_IP_RANGES,
type = CommandType.BOOLEAN,
Expand Down Expand Up @@ -423,9 +423,9 @@ else if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMo
public Map<Capability, String> getServiceCapabilities(Service service) {
Map<Capability, String> capabilityMap = null;

if (serviceCapabilitystList != null && !serviceCapabilitystList.isEmpty()) {
if (serviceCapabilitiesList != null && !serviceCapabilitiesList.isEmpty()) {
capabilityMap = new HashMap<Capability, String>();
Collection serviceCapabilityCollection = serviceCapabilitystList.values();
Collection serviceCapabilityCollection = serviceCapabilitiesList.values();
Iterator iter = serviceCapabilityCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> svcCapabilityMap = (HashMap<String, String>) iter.next();
Expand Down
Loading
Loading