Skip to content

Commit

Permalink
VNF: create SG or SNAT/FW for ssh/http/https ports
Browse files Browse the repository at this point in the history
  • Loading branch information
weizhouapache committed Oct 12, 2023
1 parent 61e55ae commit 88c81a5
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 4 deletions.
2 changes: 2 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 @@ -1048,6 +1048,8 @@ public class ApiConstants {
public static final String VNF_DETAILS = "vnfdetails";
public static final String CLEAN_UP_VNF_DETAILS = "cleanupvnfdetails";
public static final String CLEAN_UP_VNF_NICS = "cleanupvnfnics";
public static final String VNF_CONFIGURE_MANAGEMENT = "vnfconfiguremanagement";
public static final String VNF_CIDR_LIST = "vnfcidrlist";

/**
* This enum specifies IO Drivers, each option controls specific policies on I/O.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@
// under the License.
package org.apache.cloudstack.api.command.user.vm;

import com.cloud.exception.ResourceAllocationException;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.command.user.UserCmd;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.storage.template.VnfTemplateUtils;

import java.util.ArrayList;
import java.util.List;

@APICommand(name = "deployVnfAppliance",
description = "Creates and automatically starts a VNF appliance based on a service offering, disk offering, and template.",
Expand All @@ -32,4 +40,33 @@
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
since = "4.19.0")
public class DeployVnfApplianceCmd extends DeployVMCmd implements UserCmd {

@Parameter(name = ApiConstants.VNF_CONFIGURE_MANAGEMENT, type = CommandType.BOOLEAN, required = false,
description = "True by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. False otherwise.")
private Boolean vnfConfigureManagement;

@Parameter(name = ApiConstants.VNF_CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING,
description = "the CIDR list to forward traffic from to the VNF management interface. Multiple entries must be separated by a single comma character (,).")
private List<String> vnfCidrlist;

public Boolean getVnfConfigureManagement() {
return vnfConfigureManagement == null || vnfConfigureManagement;
}

public List<String> getVnfCidrlist() {
if (vnfCidrlist != null) {
return vnfCidrlist;
} else {
List<String> defaultCidrList = new ArrayList<String>();
defaultCidrList.add(NetUtils.ALL_IP4_CIDRS);
return defaultCidrList;
}
}

@Override
public void create() throws ResourceAllocationException {
VnfTemplateUtils.validateVnfCidrList(this.getVnfCidrlist());

super.create();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@
// under the License.
package org.apache.cloudstack.storage.template;

import com.cloud.dc.DataCenter;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.security.SecurityGroup;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
import com.cloud.uservm.UserVm;
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
import org.apache.cloudstack.framework.config.ConfigKey;
import java.util.List;

Expand All @@ -35,4 +43,10 @@ public interface VnfTemplateManager {
void updateVnfTemplate(long templateId, UpdateVnfTemplateCmd cmd);

void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds);

SecurityGroup createSecurityGroupForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner, DeployVnfApplianceCmd cmd);

void createIsolatedNetworkRulesForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner,
UserVm vm, DeployVnfApplianceCmd cmd)
throws InsufficientAddressCapacityException, ResourceAllocationException, ResourceUnavailableException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
import com.cloud.network.VNF;
import com.cloud.storage.Storage;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.utils.net.NetUtils;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.command.user.template.DeleteVnfTemplateCmd;
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -109,7 +111,7 @@ public static void validateVnfNics(List<VNF.VnfNic> nicsList) {
throw new InvalidParameterValueException(String.format("deviceid must be consecutive and start from 0. Nic deviceid should be %s but actual is %s.", deviceId, nic.getDeviceId()));
}
if (!required && nic.isRequired()) {
throw new InvalidParameterValueException(String.format("required cannot be true if a precedent nic is optional. Nic with deviceid %s should be required but actual is optional.", deviceId));
throw new InvalidParameterValueException(String.format("required cannot be true if a preceding nic is optional. Nic with deviceid %s should be required but actual is optional.", deviceId));
}
deviceId ++;
required = nic.isRequired();
Expand All @@ -133,4 +135,15 @@ public static void validateApiCommandParams(BaseCmd cmd, VirtualMachineTemplate
}
}
}

public static void validateVnfCidrList(List<String> cidrList) {
if (CollectionUtils.isEmpty(cidrList)) {
return;
}
for (String cidr : cidrList) {
if (!NetUtils.isValidIp4Cidr(cidr)) {
throw new InvalidParameterValueException(String.format("Invalid cidr for VNF appliance: %s", cidr));
}
}
}
}
2 changes: 2 additions & 0 deletions engine/schema/src/main/java/com/cloud/vm/NicVO.java
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ public String toString() {
.append("-")
.append(instanceId)
.append("-")
.append(deviceId)
.append("-")
.append(reservationId)
.append("-")
.append(iPv4Address)
Expand Down
21 changes: 19 additions & 2 deletions server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd;
Expand Down Expand Up @@ -5863,6 +5864,8 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE
}
if (TemplateType.VNF.equals(template.getTemplateType())) {
vnfTemplateManager.validateVnfApplianceNics(template, cmd.getNetworkIds());
} else if (cmd instanceof DeployVnfApplianceCmd) {
throw new InvalidParameterValueException("Can't deploy VNF appliance from a non-VNF template");
}

ServiceOfferingJoinVO svcOffering = serviceOfferingJoinDao.findById(serviceOfferingId);
Expand Down Expand Up @@ -5945,14 +5948,14 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE
if (networkIds != null) {
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
} else {
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId,
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd, zone, template, owner), owner, name, displayName, diskOfferingId,
size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId);
}
} else {
if (zone.isSecurityGroupEnabled()) {
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd), owner, name,
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd, zone, template, owner), owner, name,
displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard,
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId, null);
Expand All @@ -5964,6 +5967,9 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, group,
cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId);
if (cmd instanceof DeployVnfApplianceCmd) {
vnfTemplateManager.createIsolatedNetworkRulesForVnfAppliance(zone, template, owner, vm, (DeployVnfApplianceCmd) cmd);
}
}
}

Expand Down Expand Up @@ -6230,6 +6236,17 @@ protected List<Long> getSecurityGroupIdList(SecurityGroupAction cmd) {
}
}

protected List<Long> getSecurityGroupIdList(SecurityGroupAction cmd, DataCenter zone, VirtualMachineTemplate template, Account owner) {
List<Long> securityGroupIdList = getSecurityGroupIdList(cmd);
if (cmd instanceof DeployVnfApplianceCmd) {
SecurityGroup securityGroup = vnfTemplateManager.createSecurityGroupForVnfAppliance(zone, template, owner, (DeployVnfApplianceCmd) cmd);
if (securityGroup != null) {
securityGroupIdList.add(securityGroup.getId());
}
}
return securityGroupIdList;
}

// this is an opportunity to verify that parameters that came in via the Details Map are OK
// for example, minIops and maxIops should either both be specified or neither be specified and,
// if specified, minIops should be <= maxIops
Expand Down
Loading

0 comments on commit 88c81a5

Please sign in to comment.