diff --git a/api/src/main/java/com/cloud/network/guru/NetworkGuru.java b/api/src/main/java/com/cloud/network/guru/NetworkGuru.java index a0e856daea5..cbadbb18a8f 100644 --- a/api/src/main/java/com/cloud/network/guru/NetworkGuru.java +++ b/api/src/main/java/com/cloud/network/guru/NetworkGuru.java @@ -96,6 +96,8 @@ public interface NetworkGuru extends Adapter { */ Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner); + void setup(Network network, long networkId); + /** * For guest networks that are in Allocated state after the design stage, * resources are allocated when the guest network is actually being used diff --git a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java index c64b9320245..3aab57d5d3d 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java @@ -29,7 +29,8 @@ public interface VpcOffering extends InternalIdentity, Identity { public static final String defaultVPCOfferingName = "Default VPC offering"; public static final String defaultVPCNSOfferingName = "Default VPC offering with Netscaler"; public static final String redundantVPCOfferingName = "Redundant VPC offering"; - public static final String DEFAULT_VPC_NSX_OFFERING_NAME = "VPC offering with NSX"; + public static final String DEFAULT_VPC_NAT_NSX_OFFERING_NAME = "VPC offering with NSX - NAT Mode"; + public static final String DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME = "VPC offering with NSX - Route Mode"; /** * @@ -54,6 +55,10 @@ public interface VpcOffering extends InternalIdentity, Identity { */ boolean isDefault(); + boolean isForNsx(); + + String getNsxMode(); + /** * @return service offering id used by VPC virtual router */ diff --git a/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java b/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java index 5cccd6c5a82..1ce3cf8ab0e 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java @@ -36,7 +36,8 @@ public interface VpcProvisioningService { VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders, Map serviceCapabilitystList, NetUtils.InternetProtocol internetProtocol, - Long serviceOfferingId, List domainIds, List zoneIds, VpcOffering.State state); + Long serviceOfferingId, Boolean forNsx, String mode, + List domainIds, List zoneIds, VpcOffering.State state); Pair,Integer> listVpcOfferings(ListVPCOfferingsCmd cmd); diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java index afe2a255f5b..6a68ab1246a 100644 --- a/api/src/main/java/com/cloud/offering/NetworkOffering.java +++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java @@ -43,6 +43,11 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RelatedNetworkOffering, domainid, zoneid, pvlanType, internetProtocol } + public enum NsxMode { + NATTED, + ROUTED + } + public final static String SystemPublicNetwork = "System-Public-Network"; public final static String SystemControlNetwork = "System-Control-Network"; public final static String SystemManagementNetwork = "System-Management-Network"; @@ -52,7 +57,8 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, public final static String DefaultSharedNetworkOfferingWithSGService = "DefaultSharedNetworkOfferingWithSGService"; public static final String DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE = "DefaultTungstenSharedNetworkOfferingWithSGService"; - public static final String DEFAULT_NSX_OFFERING = "DefaultNSXNetworkOffering"; + public static final String DEFAULT_NAT_NSX_OFFERING = "DefaultNATNSXNetworkOffering"; + public static final String DEFAULT_ROUTER_NSX_OFFERING = "DefaultRouteNSXNetworkOffering"; public final static String QuickCloudNoServices = "QuickCloudNoServices"; public final static String DefaultIsolatedNetworkOfferingWithSourceNatService = "DefaultIsolatedNetworkOfferingWithSourceNatService"; public final static String OvsIsolatedNetworkOfferingWithSourceNatService = "OvsIsolatedNetworkOfferingWithSourceNatService"; @@ -93,6 +99,8 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, boolean isForNsx(); + String getNsxMode(); + TrafficType getTrafficType(); boolean isSpecifyVlan(); diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index c9861f0dff8..7a023633546 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -294,6 +294,7 @@ public class ApiConstants { public static final String MIGRATION_TYPE = "migrationtype"; public static final String MEMORY = "memory"; public static final String MODE = "mode"; + public static final String NSX_MODE = "nsxmode"; public static final String NAME = "name"; public static final String METHOD_NAME = "methodname"; public static final String NETWORK_DOMAIN = "networkdomain"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index 8bf6fce881c..e12ab53c073 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -24,7 +24,10 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import com.cloud.network.Network; +import com.cloud.network.VirtualRouterProvider; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.commons.collections.CollectionUtils; @@ -47,6 +50,15 @@ import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.user.Account; +import static com.cloud.network.Network.Service.Dhcp; +import static com.cloud.network.Network.Service.Dns; +import static com.cloud.network.Network.Service.Lb; +import static com.cloud.network.Network.Service.StaticNat; +import static com.cloud.network.Network.Service.SourceNat; +import static com.cloud.network.Network.Service.PortForwarding; +import static com.cloud.network.Network.Service.NetworkACL; +import static com.cloud.network.Network.Service.UserData; + @APICommand(name = "createNetworkOffering", description = "Creates a network offering.", responseObject = NetworkOfferingResponse.class, since = "3.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class CreateNetworkOfferingCmd extends BaseCmd { @@ -127,6 +139,18 @@ public class CreateNetworkOfferingCmd extends BaseCmd { description = "true if network offering is meant to be used for VPC, false otherwise.") private Boolean forVpc; + @Parameter(name = ApiConstants.FOR_NSX, + type = CommandType.BOOLEAN, + description = "true if network offering is meant to be used for NSX, false otherwise.", + since = "4.20.0") + private Boolean forNsx; + + @Parameter(name = ApiConstants.NSX_MODE, + type = CommandType.STRING, + description = "Indicates the mode with which the network will operate. Valid option: NATTED or ROUTED", + since = "4.20.0") + private String nsxMode; + @Parameter(name = ApiConstants.FOR_TUNGSTEN, type = CommandType.BOOLEAN, description = "true if network offering is meant to be used for Tungsten-Fabric, false otherwise.") @@ -211,7 +235,24 @@ public class CreateNetworkOfferingCmd extends BaseCmd { } public List getSupportedServices() { - return supportedServices == null ? new ArrayList() : supportedServices; + if (!forNsx) { + return supportedServices == null ? new ArrayList() : supportedServices; + } else { + List services = new ArrayList<>(List.of( + Dhcp.getName(), + Dns.getName(), + StaticNat.getName(), + SourceNat.getName(), + PortForwarding.getName(), + UserData.getName(), + Lb.getName() + )); + if (Boolean.TRUE.equals(forVpc)) { + services.add(NetworkACL.getName()); + return services; + } + return services; + } } public String getGuestIpType() { @@ -241,6 +282,14 @@ public class CreateNetworkOfferingCmd extends BaseCmd { return forVpc; } + public Boolean isForNsx() { + return forNsx; + } + + public String getNsxMode() { + return nsxMode; + } + public Boolean getForTungsten() { return forTungsten; } @@ -261,9 +310,8 @@ public class CreateNetworkOfferingCmd extends BaseCmd { } public Map> getServiceProviders() { - Map> serviceProviderMap = null; - if (serviceProviderList != null && !serviceProviderList.isEmpty()) { - serviceProviderMap = new HashMap>(); + Map> serviceProviderMap = new HashMap>(); + if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isForNsx()) { Collection servicesCollection = serviceProviderList.values(); Iterator iter = servicesCollection.iterator(); while (iter.hasNext()) { @@ -279,11 +327,29 @@ public class CreateNetworkOfferingCmd extends BaseCmd { providerList.add(provider); serviceProviderMap.put(service, providerList); } + } else if (Boolean.TRUE.equals(forNsx)) { + getServiceProviderMapForNsx(serviceProviderMap); } - return serviceProviderMap; } + private void getServiceProviderMapForNsx(Map> serviceProviderMap) { + String routerProvider = Boolean.TRUE.equals(getForVpc()) ? VirtualRouterProvider.Type.VPCVirtualRouter.name() : + VirtualRouterProvider.Type.VirtualRouter.name(); + List unsupportedServices = List.of("Vpn", "SecurityGroup", "Connectivity", + "Gateway", "Firewall", "BaremetalPxeService"); + List routerSupported = List.of("Dhcp", "Dns", "UserData"); + List allServices = Service.listAllServices().stream().map(Service::getName).collect(Collectors.toList()); + for (String service : allServices) { + if (unsupportedServices.contains(service)) + continue; + if (routerSupported.contains(service)) + serviceProviderMap.put(service, List.of(routerProvider)); + else + serviceProviderMap.put(service, List.of(Network.Provider.Nsx.getName())); + } + } + public Map getServiceCapabilities(Service service) { Map capabilityMap = null; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java index b69e7f4a828..c55a4571733 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java @@ -23,8 +23,13 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; +import com.cloud.network.VirtualRouterProvider; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.commons.collections.CollectionUtils; @@ -45,6 +50,15 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.network.vpc.VpcOffering; import com.cloud.user.Account; +import static com.cloud.network.Network.Service.Dhcp; +import static com.cloud.network.Network.Service.Dns; +import static com.cloud.network.Network.Service.Lb; +import static com.cloud.network.Network.Service.StaticNat; +import static com.cloud.network.Network.Service.SourceNat; +import static com.cloud.network.Network.Service.PortForwarding; +import static com.cloud.network.Network.Service.NetworkACL; +import static com.cloud.network.Network.Service.UserData; + @APICommand(name = "createVPCOffering", description = "Creates VPC offering", responseObject = VpcOfferingResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { @@ -62,7 +76,6 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.SUPPORTED_SERVICES, type = CommandType.LIST, - required = true, collectionType = CommandType.STRING, description = "services supported by the vpc offering") private List supportedServices; @@ -101,6 +114,18 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { since = "4.13") private List zoneIds; + @Parameter(name = ApiConstants.FOR_NSX, + type = CommandType.BOOLEAN, + description = "true if network offering is meant to be used for NSX, false otherwise.", + since = "4.20.0") + private Boolean forNsx; + + @Parameter(name = ApiConstants.NSX_MODE, + type = CommandType.STRING, + description = "Indicates the mode with which the network will operate. Valid option: NATTED or ROUTED", + since = "4.20.0") + private String nsxMode; + @Parameter(name = ApiConstants.ENABLE, type = CommandType.BOOLEAN, description = "set to true if the offering is to be enabled during creation. Default is false", @@ -120,13 +145,35 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { } public List getSupportedServices() { + if (!forNsx && CollectionUtils.isEmpty(supportedServices)) { + throw new InvalidParameterValueException("Supported services needs to be provided"); + } + if (forNsx) { + return List.of( + Dhcp.getName(), + Dns.getName(), + Lb.getName(), + StaticNat.getName(), + SourceNat.getName(), + NetworkACL.getName(), + PortForwarding.getName(), + UserData.getName() + ); + } return supportedServices; } + public Boolean isForNsx() { + return !Objects.isNull(forNsx) && forNsx; + } + + public String getNsxMode() { + return nsxMode; + } + public Map> getServiceProviders() { - Map> serviceProviderMap = null; - if (serviceProviderList != null && !serviceProviderList.isEmpty()) { - serviceProviderMap = new HashMap>(); + Map> serviceProviderMap = new HashMap>();; + if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isForNsx()) { Collection> servicesCollection = serviceProviderList.values(); Iterator> iter = servicesCollection.iterator(); while (iter.hasNext()) { @@ -134,7 +181,7 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { if (s_logger.isTraceEnabled()) { s_logger.trace("service provider entry specified: " + obj); } - HashMap services = (HashMap)obj; + HashMap services = (HashMap) obj; String service = services.get("service"); String provider = services.get("provider"); List providerList = null; @@ -146,11 +193,28 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { providerList.add(provider); serviceProviderMap.put(service, providerList); } + } else if (Boolean.TRUE.equals(forNsx)) { + getServiceProviderMapForNsx(serviceProviderMap); } return serviceProviderMap; } + private void getServiceProviderMapForNsx(Map> serviceProviderMap) { + List unsupportedServices = List.of("Vpn", "BaremetalPxeService", "SecurityGroup", "Connectivity", + "Gateway", "Firewall"); + List routerSupported = List.of("Dhcp", "Dns", "UserData"); + List allServices = Network.Service.listAllServices().stream().map(Network.Service::getName).collect(Collectors.toList()); + for (String service : allServices) { + if (unsupportedServices.contains(service)) + continue; + if (routerSupported.contains(service)) + serviceProviderMap.put(service, List.of(VirtualRouterProvider.Type.VPCVirtualRouter.name())); + else + serviceProviderMap.put(service, List.of(Network.Provider.Nsx.getName())); + } + } + public Map> getServiceCapabilityList() { return serviceCapabilityList; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java index 4685580e4b5..2594488c5be 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java @@ -107,6 +107,10 @@ public class NetworkOfferingResponse extends BaseResponseWithAnnotations { @Param(description = "true if network offering can be used by Tungsten-Fabric networks only") private Boolean forTungsten; + @SerializedName(ApiConstants.NSX_MODE) + @Param(description = "Mode in which the network will operate. This parameter is only relevant for NSX offerings") + private String nsxMode; + @SerializedName(ApiConstants.IS_PERSISTENT) @Param(description = "true if network offering supports persistent networks, false otherwise") private Boolean isPersistent; @@ -227,6 +231,10 @@ public class NetworkOfferingResponse extends BaseResponseWithAnnotations { this.forTungsten = forTungsten; } + public void setNsxMode(String nsxMode) { + this.nsxMode = nsxMode; + } + public void setIsPersistent(Boolean isPersistent) { this.isPersistent = isPersistent; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java index 6881969646b..ce00827f06d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java @@ -63,9 +63,17 @@ public class VpcOfferingResponse extends BaseResponse { private Boolean supportsDistributedRouter; @SerializedName((ApiConstants.SUPPORTS_REGION_LEVEL_VPC)) - @Param(description = " indicated if the offering can support region level vpc", since = "4.4") + @Param(description = "indicated if the offering can support region level vpc", since = "4.4") private Boolean supportsRegionLevelVpc; + @SerializedName(ApiConstants.FOR_NSX) + @Param(description = "true if vpc offering can be used by NSX networks only") + private Boolean forNsx; + + @SerializedName(ApiConstants.NSX_MODE) + @Param(description = "Mode in which the network will operate. This parameter is only relevant for NSX offerings") + private String nsxMode; + @SerializedName(ApiConstants.DOMAIN_ID) @Param(description = "the domain ID(s) this disk offering belongs to. Ignore this information as it is not currently applicable.") private String domainId; @@ -138,6 +146,14 @@ public class VpcOfferingResponse extends BaseResponse { this.domain = domain; } + public void setForNsx(Boolean forNsx) { + this.forNsx = forNsx; + } + + public void setNsxMode(String nsxMode) { + this.nsxMode = nsxMode; + } + public String getZoneId() { return zoneId; } diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmdTest.java index 16b716d7d63..290a2850c9a 100644 --- a/api/src/test/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmdTest.java +++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmdTest.java @@ -52,15 +52,15 @@ public class CreateVPCOfferingCmdTest { IllegalAccessException { CreateVPCOfferingCmd cmd = new CreateVPCOfferingCmd(); ApiCmdTestUtil.set(cmd, ApiConstants.SERVICE_PROVIDER_LIST, new HashMap>()); - Assert.assertNull(cmd.getServiceProviders()); + Assert.assertTrue(cmd.getServiceProviders().isEmpty()); } @Test - public void getDetailsNull() throws IllegalArgumentException, + public void getDetailsEmpty() throws IllegalArgumentException, IllegalAccessException { CreateVPCOfferingCmd cmd = new CreateVPCOfferingCmd(); ApiCmdTestUtil.set(cmd, ApiConstants.SERVICE_PROVIDER_LIST, null); - Assert.assertNull(cmd.getServiceProviders()); + Assert.assertTrue(cmd.getServiceProviders().isEmpty()); } @Test diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 1146a33861d..b0fbd30691a 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -225,7 +225,7 @@ public interface ConfigurationManager { Integer networkRate, Map> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, - Boolean forTungsten, Boolean forNsx, List domainIds, List zoneIds, boolean enableOffering, final NetUtils.InternetProtocol internetProtocol); + Boolean forTungsten, Boolean forNsx, String mode, List domainIds, List zoneIds, boolean enableOffering, final NetUtils.InternetProtocol internetProtocol); Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 36ec427735d..5feb1099673 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -48,6 +48,8 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import javax.persistence.EntityExistsException; +import com.cloud.domain.Domain; +import com.cloud.domain.dao.DomainDao; import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.user.dao.AccountDao; @@ -392,6 +394,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac private AccountDao accountDao; @Inject private VpcDao vpcDao; + @Inject + private DomainDao domainDao; VmWorkJobHandlerProxy _jobHandlerProxy = new VmWorkJobHandlerProxy(this); @@ -1470,7 +1474,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } - private void setVmNetworkDetails(VMInstanceVO vm, VirtualMachineTO vmTO) { + public void setVmNetworkDetails(VMInstanceVO vm, VirtualMachineTO vmTO) { if (VirtualMachine.Type.User.equals(vm.getType())) { List userVmJoinVOs = userVmJoinDao.searchByIds(vm.getId()); Map networkToNetworkNameMap = new HashMap<>(); @@ -1478,12 +1482,26 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac for (UserVmJoinVO userVmJoinVO : userVmJoinVOs) { NetworkVO networkVO = _networkDao.findById(userVmJoinVO.getNetworkId()); Account acc = accountDao.findById(networkVO.getAccountId()); - String networkName = acc.getAccountName() + "-" ; + Domain domain = domainDao.findById(networkVO.getDomainId()); + DataCenter zone = _dcDao.findById(vm.getDataCenterId()); + if (Objects.isNull(zone)) { + throw new CloudRuntimeException(String.format("Failed to find zone with ID: %s", vm.getDataCenterId())); + } + if (Objects.isNull(acc)) { + throw new CloudRuntimeException(String.format("Failed to find account with ID: %s", networkVO.getAccountId())); + } + if (Objects.isNull(domain)) { + throw new CloudRuntimeException(String.format("Failed to find domain with ID: %s", networkVO.getDomainId())); + } + String networkName = String.format("D%s-A%s-Z%s", domain.getId(), acc.getId(), zone.getId()); if (Objects.isNull(networkVO.getVpcId())) { - networkName += networkVO.getName(); + networkName += "-S"+networkVO.getId(); } else { VpcVO vpc = vpcDao.findById(networkVO.getVpcId()); - networkName += (vpc.getName() + "-" + networkVO.getName()); + if (Objects.isNull(vpc)) { + throw new CloudRuntimeException(String.format("Failed to find VPC with ID: %s", networkVO.getVpcId())); + } + networkName = String.format("%s-V%s-S%s", networkName, vpc.getId(), networkVO.getId()); } networkToNetworkNameMap.put(networkVO.getId(), networkName); } diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index accb10d1e1c..b2ed53b2cef 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -540,27 +540,27 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap>(), true, Network.GuestType.Shared, false, null, true, null, true, - false, null, false, null, true, false, false, false, null, null, true, null); + false, null, false, null, true, false, false, false, null, null, null, true, null); } //#2 - SG enabled network offering if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, false, false, null, null, true, null); + null, true, false, null, false, null, true, false, false, false, null, null, null, true, null); } //#3 - shared network offering with no SG service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null, false, - null, true, false, false, false, null, null, true, null); + null, true, false, false, false, null,null, null, true, null); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE, "Offering for Tungsten Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultTungstenSharedSGEnabledNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, true, false, null, null, true, null); + null, true, false, null, false, null, true, false, true, false, null, null,null, true, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -570,14 +570,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, - true, false, false, false, null, null, true, null); + true, false, false, false, null, null,null, true, null); } //#5 - default vpc offering with LB service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, - defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, true, null); + defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null,true, null); } //#6 - default vpc offering with no LB service @@ -586,14 +586,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra defaultVPCOffProviders.remove(Service.Lb); offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, - null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, true, null); + null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null,true, null); } //#7 - isolated offering with source nat disabled if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, - true, null, true, false, null, false, null, true, false, false, false, null, null, true, null); + true, null, true, false, null, false, null, true, false, false, false, null, null, null, true, null); } //#8 - network offering with internal lb service @@ -615,7 +615,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB, "Offering for Isolated VPC networks with Internal Lb support", TrafficType.Guest, null, false, Availability.Optional, null, internalLbOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, true, null); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null, true, null); offering.setInternalLb(true); offering.setPublicLb(false); _networkOfferingDao.update(offering.getId(), offering); @@ -646,7 +646,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, null, - netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, false, false, null, null, true, null); + netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, false, false, null, null, null, true, null); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); } @@ -812,6 +812,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } } }); + guru.setup(network, relatedFile); } if (networks.size() < 1) { diff --git a/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java b/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java index 15a2f2c0ac1..1e7cc124643 100644 --- a/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java +++ b/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java @@ -35,6 +35,18 @@ import java.util.Map; import java.util.Random; import java.util.stream.Collectors; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.api.query.vo.UserVmJoinVO; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -155,6 +167,16 @@ public class VirtualMachineManagerImplTest { private UserVmDao userVmDaoMock; @Mock private UserVmVO userVmMock; + @Mock + private NetworkDao networkDao; + @Mock + private AccountDao accountDao; + @Mock + private DomainDao domainDao; + @Mock + private DataCenterDao dcDao; + @Mock + private VpcDao vpcDao; @Before public void setup() { @@ -895,4 +917,45 @@ public class VirtualMachineManagerImplTest { map.put(Mockito.mock(Volume.class), pool2); virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, destinationClusterId, map); } + + @Test + public void checkIfVmNetworkDetailsReturnedIsCorrect() { + VMInstanceVO vm = new VMInstanceVO(1L, 1L, "VM1", "i-2-2-VM", + VirtualMachine.Type.User, 1L, HypervisorType.KVM, 1L, 1L, 1L, + 1L, false, false); + + VirtualMachineTO vmTO = new VirtualMachineTO() {}; + UserVmJoinVO userVm = new UserVmJoinVO(); + NetworkVO networkVO = mock(NetworkVO.class); + AccountVO accountVO = mock(AccountVO.class); + DomainVO domainVO = mock(DomainVO.class); + domainVO.setName("testDomain"); + DataCenterVO dataCenterVO = mock(DataCenterVO.class); + VpcVO vpcVO = mock(VpcVO.class); + + networkVO.setAccountId(1L); + networkVO.setName("testNet"); + networkVO.setVpcId(1L); + + accountVO.setAccountName("testAcc"); + + vpcVO.setName("VPC1"); + + + List userVms = List.of(userVm); + Mockito.when(userVmJoinDaoMock.searchByIds(anyLong())).thenReturn(userVms); + Mockito.when(networkDao.findById(anyLong())).thenReturn(networkVO); + Mockito.when(accountDao.findById(anyLong())).thenReturn(accountVO); + Mockito.when(domainDao.findById(anyLong())).thenReturn(domainVO); + Mockito.when(dcDao.findById(anyLong())).thenReturn(dataCenterVO); + Mockito.when(vpcDao.findById(anyLong())).thenReturn(vpcVO); + Mockito.when(dataCenterVO.getId()).thenReturn(1L); + when(accountVO.getId()).thenReturn(2L); + Mockito.when(domainVO.getId()).thenReturn(3L); + Mockito.when(vpcVO.getId()).thenReturn(4L); + Mockito.when(networkVO.getId()).thenReturn(5L); + virtualMachineManagerImpl.setVmNetworkDetails(vm, vmTO); + assertEquals(vmTO.getNetworkIdToNetworkNameMap().size(), 1); + assertEquals(vmTO.getNetworkIdToNetworkNameMap().get(5L), "D3-A2-Z1-V4-S5"); + } } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java index aa26f16568a..350dda3f3b8 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java @@ -58,6 +58,12 @@ public class VpcOfferingVO implements VpcOffering { @Column(name = "default") boolean isDefault = false; + @Column(name = "for_nsx") + boolean forNsx = false; + + @Column(name = "nsx_mode") + String nsxMode; + @Column(name = GenericDao.REMOVED_COLUMN) Date removed; @@ -144,6 +150,22 @@ public class VpcOfferingVO implements VpcOffering { return isDefault; } + public boolean isForNsx() { + return forNsx; + } + + public void setForNsx(boolean forNsx) { + this.forNsx = forNsx; + } + + public String getNsxMode() { + return nsxMode; + } + + public void setNsxMode(String nsxMode) { + this.nsxMode = nsxMode; + } + public void setUniqueName(String uniqueName) { this.uniqueName = uniqueName; } diff --git a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java index edc89f3cb9a..b2fabf2e3cd 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java @@ -139,6 +139,9 @@ public class NetworkOfferingVO implements NetworkOffering { @Column(name = "for_nsx") boolean forNsx = false; + @Column(name = "nsx_mode") + String nsxMode; + @Column(name = "egress_default_policy") boolean egressdefaultpolicy; @@ -207,6 +210,15 @@ public class NetworkOfferingVO implements NetworkOffering { this.forNsx = forNsx; } + @Override + public String getNsxMode() { + return nsxMode; + } + + public void setNsxMode(String nsxMode) { + this.nsxMode = nsxMode; + } + @Override public long getId() { return id; diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql b/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql index 75b588f95a6..e36a74a87e8 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql @@ -214,8 +214,11 @@ BEGIN -- NSX Plugin -- CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings','for_nsx', 'int(1) unsigned DEFAULT "0" COMMENT "is nsx enabled for the resource"'); +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings','nsx_mode', 'varchar(32) COMMENT "mode in which the network would route traffic"'); +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','for_nsx', 'int(1) unsigned DEFAULT "0" COMMENT "is nsx enabled for the resource"'); +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','nsx_mode', 'varchar(32) COMMENT "mode in which the network would route traffic"'); --- Network offering with multi-domains and multi-zones +-- Network offering with NSX related columns DROP VIEW IF EXISTS `cloud`.`network_offering_view`; CREATE VIEW `cloud`.`network_offering_view` AS SELECT @@ -259,6 +262,7 @@ SELECT `network_offerings`.`for_vpc` AS `for_vpc`, `network_offerings`.`for_tungsten` AS `for_tungsten`, `network_offerings`.`for_nsx` AS `for_nsx`, + `network_offerings`.`nsx_mode` AS `nsx_mode`, `network_offerings`.`service_package_id` AS `service_package_id`, GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, @@ -398,3 +402,46 @@ CREATE VIEW `cloud`.`snapshot_view` AS OR (`snapshot_zone_ref`.`zone_id` = `data_center`.`id`)))) LEFT JOIN `resource_tags` ON ((`resource_tags`.`resource_id` = `snapshots`.`id`) AND (`resource_tags`.`resource_type` = 'Snapshot'))); + +-- VPC offering with NSX related columns +DROP VIEW IF EXISTS `cloud`.`vpc_offering_view`; +CREATE VIEW `cloud`.`vpc_offering_view` AS +SELECT + `vpc_offerings`.`id` AS `id`, + `vpc_offerings`.`uuid` AS `uuid`, + `vpc_offerings`.`name` AS `name`, + `vpc_offerings`.`unique_name` AS `unique_name`, + `vpc_offerings`.`display_text` AS `display_text`, + `vpc_offerings`.`state` AS `state`, + `vpc_offerings`.`default` AS `default`, + `vpc_offerings`.`for_nsx` AS `for_nsx`, + `vpc_offerings`.`nsx_mode` AS `nsx_mode`, + `vpc_offerings`.`created` AS `created`, + `vpc_offerings`.`removed` AS `removed`, + `vpc_offerings`.`service_offering_id` AS `service_offering_id`, + `vpc_offerings`.`supports_distributed_router` AS `supports_distributed_router`, + `vpc_offerings`.`supports_region_level_vpc` AS `supports_region_level_vpc`, + `vpc_offerings`.`redundant_router_service` AS `redundant_router_service`, + `vpc_offerings`.`sort_key` AS `sort_key`, + GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, + GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, + GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name, + GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path, + GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id, + GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid, + GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name, + `offering_details`.value AS internet_protocol +FROM + `cloud`.`vpc_offerings` + LEFT JOIN + `cloud`.`vpc_offering_details` AS `domain_details` ON `domain_details`.`offering_id` = `vpc_offerings`.`id` AND `domain_details`.`name`='domainid' + LEFT JOIN + `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`) + LEFT JOIN + `cloud`.`vpc_offering_details` AS `zone_details` ON `zone_details`.`offering_id` = `vpc_offerings`.`id` AND `zone_details`.`name`='zoneid' + LEFT JOIN + `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`) + LEFT JOIN + `cloud`.`vpc_offering_details` AS `offering_details` ON `offering_details`.`offering_id` = `vpc_offerings`.`id` AND `offering_details`.`name`='internetprotocol' +GROUP BY + `vpc_offerings`.`id`; diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailGuru.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailGuru.java index bae6e8664a8..9b7d835dce3 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailGuru.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailGuru.java @@ -138,6 +138,11 @@ public class ContrailGuru extends AdapterBase implements NetworkGuru { return network; } + @Override + public void setup(Network network, long networkId) { + // do nothing + } + @Override public Network implement(Network network, NetworkOffering offering, DeployDestination destination, ReservationContext context) throws InsufficientVirtualNetworkCapacityException { diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java index 372e268a2ff..6ce4c91bea6 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java @@ -219,7 +219,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager ConfigurationManager configMgr = (ConfigurationManager) _configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Public, null, true, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, false, false, null, null, true, null); + Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, false, false, null, null, null, true, null); long id = voffer.getId(); _networkOfferingDao.update(id, voffer); return _networkOfferingDao.findById(id); @@ -254,7 +254,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager ConfigurationManager configMgr = (ConfigurationManager)_configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Guest, null, false, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), false, false, null, null, true, null); + Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), false, false, null, null, null, true, null); if (offeringName.equals(vpcRouterOfferingName)) { voffer.setInternalLb(true); } @@ -295,7 +295,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager } serviceProviderMap.put(svc, providerSet); } - vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, null, null, VpcOffering.State.Enabled); + vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, false, null, null, null, VpcOffering.State.Enabled); long id = vpcOffer.getId(); _vpcOffDao.update(id, (VpcOfferingVO)vpcOffer); return _vpcOffDao.findById(id); diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDhcpRelayConfigCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDhcpRelayConfigCommand.java index f8b9d1d6710..5b986628628 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDhcpRelayConfigCommand.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDhcpRelayConfigCommand.java @@ -20,22 +20,35 @@ import java.util.List; public class CreateNsxDhcpRelayConfigCommand extends NsxCommand { + private Long vpcId; private String vpcName; + private long networkId; private String networkName; private List addresses; - public CreateNsxDhcpRelayConfigCommand(String zoneName, Long zoneId, String accountName, Long accountId, - String vpcName, String networkName, List addresses) { - super(zoneName, zoneId, accountName, accountId); + public CreateNsxDhcpRelayConfigCommand(long domainId, long accountId, long zoneId, + Long vpcId, String vpcName, long networkId, String networkName, + List addresses) { + super(domainId, accountId, zoneId); + this.vpcId = vpcId; this.vpcName = vpcName; + this.networkId = networkId; this.networkName = networkName; this.addresses = addresses; } + public Long getVpcId() { + return vpcId; + } + public String getVpcName() { return vpcName; } + public long getNetworkId() { + return networkId; + } + public String getNetworkName() { return networkName; } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxSegmentCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxSegmentCommand.java index 0f39272a889..b4b86bd640a 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxSegmentCommand.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxSegmentCommand.java @@ -16,23 +16,51 @@ // under the License. package org.apache.cloudstack.agent.api; -import com.cloud.network.dao.NetworkVO; - import java.util.Objects; -public class CreateNsxSegmentCommand extends CreateNsxTier1GatewayCommand { - private NetworkVO tierNetwork; - public CreateNsxSegmentCommand(String zoneName, Long zoneId, String accountName, Long accountId, String vpcName, NetworkVO tierNetwork) { - super(zoneName, zoneId, accountName, accountId, vpcName); - this.tierNetwork = tierNetwork; +public class CreateNsxSegmentCommand extends NsxCommand { + + private Long vpcId; + private String vpcName; + private long networkId; + private String networkName; + private String networkGateway; + private String networkCidr; + + public CreateNsxSegmentCommand(long domainId, long accountId, long zoneId, + Long vpcId, String vpcName, long networkId, String networkName, + String networkGateway, String networkCidr) { + super(domainId, accountId, zoneId); + this.vpcId = vpcId; + this.vpcName = vpcName; + this.networkId = networkId; + this.networkName = networkName; + this.networkGateway = networkGateway; + this.networkCidr = networkCidr; } - public NetworkVO getTierNetwork() { - return tierNetwork; + public Long getVpcId() { + return vpcId; } - public void setTierNetwork(NetworkVO tierNetwork) { - this.tierNetwork = tierNetwork; + public String getVpcName() { + return vpcName; + } + + public long getNetworkId() { + return networkId; + } + + public String getNetworkName() { + return networkName; + } + + public String getNetworkGateway() { + return networkGateway; + } + + public String getNetworkCidr() { + return networkCidr; } @Override @@ -41,11 +69,11 @@ public class CreateNsxSegmentCommand extends CreateNsxTier1GatewayCommand { if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; CreateNsxSegmentCommand command = (CreateNsxSegmentCommand) o; - return Objects.equals(tierNetwork, command.tierNetwork); + return Objects.equals(networkName, command.networkName); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), tierNetwork); + return Objects.hash(super.hashCode(), networkName); } } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxTier1GatewayCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxTier1GatewayCommand.java index 03e57362f17..02616585f98 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxTier1GatewayCommand.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxTier1GatewayCommand.java @@ -19,21 +19,23 @@ package org.apache.cloudstack.agent.api; import java.util.Objects; public class CreateNsxTier1GatewayCommand extends NsxCommand { + private long vpcId; private String vpcName; - public CreateNsxTier1GatewayCommand(String zoneName, Long zoneId, String accountName, Long accountId, String vpcName) { - super(zoneName, zoneId, accountName, accountId); + public CreateNsxTier1GatewayCommand(long domainId, long accountId, long zoneId, long vpcId, String vpcName) { + super(domainId, accountId, zoneId); + this.vpcId = vpcId; this.vpcName = vpcName; } + public long getVpcId() { + return vpcId; + } + public String getVpcName() { return vpcName; } - public void setVpcName(String vpcName) { - this.vpcName = vpcName; - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxSegmentCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxSegmentCommand.java index a1b30582118..06af4d8c31d 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxSegmentCommand.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxSegmentCommand.java @@ -16,10 +16,36 @@ // under the License. package org.apache.cloudstack.agent.api; -import com.cloud.network.dao.NetworkVO; +public class DeleteNsxSegmentCommand extends NsxCommand { -public class DeleteNsxSegmentCommand extends CreateNsxSegmentCommand { - public DeleteNsxSegmentCommand(String accountName, String vpcName, NetworkVO network) { - super(null, network.getDataCenterId(), accountName, network.getAccountId(), vpcName, network); + private Long vpcId; + private String vpcName; + + private long networkId; + private String networkName; + + public DeleteNsxSegmentCommand(long domainId, long accountId, long zoneId, Long vpcId, + String vpcName, long networkId, String networkName) { + super(domainId, accountId, zoneId); + this.vpcId = vpcId; + this.vpcName = vpcName; + this.networkId = networkId; + this.networkName = networkName; + } + + public Long getVpcId() { + return vpcId; + } + + public String getVpcName() { + return vpcName; + } + + public long getNetworkId() { + return networkId; + } + + public String getNetworkName() { + return networkName; } } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxTier1GatewayCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxTier1GatewayCommand.java index 12a64b8ee04..3b684f28487 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxTier1GatewayCommand.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxTier1GatewayCommand.java @@ -16,9 +16,22 @@ // under the License. package org.apache.cloudstack.agent.api; -public class DeleteNsxTier1GatewayCommand extends CreateNsxTier1GatewayCommand { +public class DeleteNsxTier1GatewayCommand extends NsxCommand { - public DeleteNsxTier1GatewayCommand(String zoneName, Long zoneId, String accountName, Long accountId, String vpcName) { - super(zoneName, zoneId, accountName, accountId, vpcName); + private Long vpcId; + private String vpcName; + + public DeleteNsxTier1GatewayCommand(long domainId, long accountId, long zoneId, Long vpcId, String vpcName) { + super(domainId, accountId, zoneId); + this.vpcId = vpcId; + this.vpcName = vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public String getVpcName() { + return vpcName; } } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxCommand.java index 6ad4edfc680..7c5e3a1d9fa 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxCommand.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxCommand.java @@ -21,49 +21,31 @@ import com.cloud.agent.api.Command; import java.util.Objects; public class NsxCommand extends Command { - private String zoneName; - private Long zoneId; - private String accountName; - private Long accountId; + private long zoneId; + private long accountId; + private long domainId; - public NsxCommand(String zoneName, Long zoneId, String accountName, Long accountId) { - this.zoneName = zoneName; + public NsxCommand() { + } + + public NsxCommand(long domainId, long accountId, long zoneId) { this.zoneId = zoneId; - this.accountName = accountName; this.accountId = accountId; + this.domainId = domainId; } - public String getZoneName() { - return zoneName; - } - - public void setZoneName(String zoneName) { - this.zoneName = zoneName; - } - - public Long getZoneId() { + public long getZoneId() { return zoneId; } - public void setZoneId(Long zoneId) { - this.zoneId = zoneId; - } - - public String getAccountName() { - return accountName; - } - - public void setAccountName(String accountName) { - this.accountName = accountName; - } - - public Long getAccountId() { + public long getAccountId() { return accountId; } - public void setAccountId(Long accountId) { - this.accountId = accountId; + public long getDomainId() { + return domainId; } + @Override public boolean executeInSequence() { return false; @@ -75,11 +57,11 @@ public class NsxCommand extends Command { if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; NsxCommand that = (NsxCommand) o; - return Objects.equals(zoneName, that.zoneName) && Objects.equals(zoneId, that.zoneId) && Objects.equals(accountName, that.accountName) && Objects.equals(accountId, that.accountId); + return Objects.equals(zoneId, that.zoneId) && Objects.equals(accountId, that.accountId) && Objects.equals(domainId, that.domainId); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), zoneName, zoneId, accountName, accountId); + return Objects.hash(super.hashCode(), zoneId, accountId, domainId); } } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java index 9724c7bc926..ad5ea2b7067 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java @@ -16,7 +16,6 @@ // under the License. package org.apache.cloudstack.resource; -import com.amazonaws.util.CollectionUtils; import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; @@ -24,29 +23,15 @@ import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.ReadyAnswer; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.StartupCommand; -import com.cloud.exception.InvalidParameterValueException; import com.cloud.host.Host; import com.cloud.resource.ServerResource; import com.cloud.utils.exception.CloudRuntimeException; import com.vmware.nsx.model.TransportZone; import com.vmware.nsx.model.TransportZoneListResult; -import com.vmware.nsx_policy.infra.DhcpRelayConfigs; -import com.vmware.nsx_policy.infra.Segments; -import com.vmware.nsx_policy.infra.Sites; -import com.vmware.nsx_policy.infra.Tier1s; -import com.vmware.nsx_policy.infra.sites.EnforcementPoints; -import com.vmware.nsx_policy.infra.tier_0s.LocaleServices; -import com.vmware.nsx_policy.model.ApiError; -import com.vmware.nsx_policy.model.DhcpRelayConfig; import com.vmware.nsx_policy.model.EnforcementPointListResult; -import com.vmware.nsx_policy.model.LocaleServicesListResult; import com.vmware.nsx_policy.model.Segment; -import com.vmware.nsx_policy.model.SegmentSubnet; import com.vmware.nsx_policy.model.SiteListResult; -import com.vmware.nsx_policy.model.Tier1; -import com.vmware.vapi.bindings.Service; -import com.vmware.vapi.std.errors.Error; import org.apache.cloudstack.NsxAnswer; import org.apache.cloudstack.StartupNsxCommand; import org.apache.cloudstack.agent.api.CreateNsxDhcpRelayConfigCommand; @@ -54,36 +39,21 @@ import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand; import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand; import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand; -import org.apache.cloudstack.service.NsxApi; -import org.apache.cloudstack.utils.NsxApiClientUtils; +import org.apache.cloudstack.service.NsxApiClient; +import org.apache.cloudstack.utils.NsxControllerUtils; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import javax.naming.ConfigurationException; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; import java.util.stream.Collectors; -import static java.util.Objects.isNull; -import static org.apache.cloudstack.utils.NsxApiClientUtils.RouteAdvertisementType.TIER1_CONNECTED; -import static org.apache.cloudstack.utils.NsxApiClientUtils.RouteAdvertisementType.TIER1_IPSEC_LOCAL_ENDPOINT; -import static org.apache.cloudstack.utils.NsxApiClientUtils.HAMode.ACTIVE_STANDBY; -import static org.apache.cloudstack.utils.NsxApiClientUtils.FailoverMode.PREEMPTIVE; -import static org.apache.cloudstack.utils.NsxApiClientUtils.PoolAllocation.ROUTING; -import static org.apache.cloudstack.utils.NsxApiClientUtils.TransportType.OVERLAY; -import static org.apache.cloudstack.utils.NsxApiClientUtils.createApiClient; - public class NsxResource implements ServerResource { private static final Logger LOGGER = Logger.getLogger(NsxResource.class); - private static final String TIER_0_GATEWAY_PATH_PREFIX = "/infra/tier-0s/"; - private static final String TIER_1_GATEWAY_PATH_PREFIX = "/infra/tier-1s/"; private static final String DHCP_RELAY_CONFIGS_PATH_PREFIX = "/infra/dhcp-relay-configs"; - private static final String Tier_1_LOCALE_SERVICE_ID = "default"; - private static final String TIER_1_RESOURCE_TYPE = "Tier1"; - private static final String SEGMENT_RESOURCE_TYPE = "Segment"; - private String name; protected String hostname; protected String username; @@ -95,13 +65,12 @@ public class NsxResource implements ServerResource { protected String transportZone; protected String zoneId; - protected NsxApi nsxApi; + protected NsxApiClient nsxApiClient; @Override public Host.Type getType() { return Host.Type.Routing; } - @Override public StartupCommand[] initialize() { StartupNsxCommand sc = new StartupNsxCommand(); @@ -236,56 +205,44 @@ public class NsxResource implements ServerResource { throw new ConfigurationException("Missing NSX transportZone"); } - nsxApi = new NsxApi(); - nsxApi.setApiClient(createApiClient(hostname, port, username, password.toCharArray())); + nsxApiClient = new NsxApiClient(hostname, port, username, password.toCharArray()); return true; } - private String getDhcpRelayConfig(String zoneName, String accountName, String vpcName, String networkName) { - return String.format("%s-%s-%s-%s-Relay", zoneName, accountName, vpcName, networkName); - } - private Answer executeRequest(CreateNsxDhcpRelayConfigCommand cmd) { - String zoneName = cmd.getZoneName(); - String accountName = cmd.getAccountName(); + long zoneId = cmd.getZoneId(); + long domainId = cmd.getDomainId(); + long accountId = cmd.getAccountId(); + long vpcId = cmd.getVpcId(); + long networkId = cmd.getNetworkId(); String vpcName = cmd.getVpcName(); String networkName = cmd.getNetworkName(); List addresses = cmd.getAddresses(); - String dhcpRelayConfigName = getDhcpRelayConfig(zoneName, accountName, vpcName, networkName); + String dhcpRelayConfigName = NsxControllerUtils.getNsxDhcpRelayConfigId(zoneId, domainId, accountId, vpcId, networkId); String msg = String.format("Creating DHCP relay config with name %s on network %s of VPC %s", dhcpRelayConfigName, networkName, vpcName); LOGGER.debug(msg); try { - DhcpRelayConfigs service = (DhcpRelayConfigs) nsxService.apply(DhcpRelayConfigs.class); - DhcpRelayConfig config = new DhcpRelayConfig.Builder() - .setServerAddresses(addresses) - .setId(dhcpRelayConfigName) - .setDisplayName(dhcpRelayConfigName) - .build(); - service.patch(dhcpRelayConfigName, config); - } catch (Error error) { - ApiError ae = error.getData()._convertTo(ApiError.class); - msg = String.format("Error creating the DHCP relay config with name %s: %s", dhcpRelayConfigName, ae.getErrorMessage()); - LOGGER.error(msg); - return new NsxAnswer(cmd, new CloudRuntimeException(ae.getErrorMessage())); + nsxApiClient.createDhcpRelayConfig(dhcpRelayConfigName, addresses); + } catch (CloudRuntimeException e) { + msg = String.format("Error creating the DHCP relay config with name %s: %s", dhcpRelayConfigName, e.getMessage()); + LOGGER.error(msg, e); + return new NsxAnswer(cmd, e); } - String segmentName = String.format("%s-%s-%s", accountName, vpcName, networkName); + String segmentName = NsxControllerUtils.getNsxSegmentId(domainId, accountId, zoneId, vpcId, networkId); String dhcpConfigPath = String.format("%s/%s", DHCP_RELAY_CONFIGS_PATH_PREFIX, dhcpRelayConfigName); try { - LOGGER.debug(String.format("Adding the creating DHCP relay config %s to the segment %s", dhcpConfigPath, segmentName)); - Segments segmentService = (Segments) nsxService.apply(Segments.class); - Segment segment = segmentService.get(segmentName); + Segment segment = nsxApiClient.getSegmentById(segmentName); segment.setDhcpConfigPath(dhcpConfigPath); - segmentService.patch(segmentName, segment); - } catch (Error error) { - ApiError ae = error.getData()._convertTo(ApiError.class); - msg = String.format("Error adding the DHCP relay config with name %s to the segment %s: %s", dhcpRelayConfigName, segmentName, ae.getErrorMessage()); + nsxApiClient.updateSegment(segmentName, segment); + } catch (CloudRuntimeException e) { + msg = String.format("Error adding the DHCP relay config with name %s to the segment %s: %s", dhcpRelayConfigName, segmentName, e.getMessage()); LOGGER.error(msg); - return new NsxAnswer(cmd, new CloudRuntimeException(ae.getErrorMessage())); + return new NsxAnswer(cmd, e); } return new NsxAnswer(cmd, true, ""); @@ -295,63 +252,21 @@ public class NsxResource implements ServerResource { return new ReadyAnswer(cmd); } - private Function, Service> nsxService = svcClass -> nsxApi.getApiClient().createStub(svcClass); private Answer executeRequest(CreateNsxTier1GatewayCommand cmd) { - String name = getTier1GatewayName(cmd); - Tier1 tier1 = getTier1Gateway(name); - if (tier1 != null) { - throw new InvalidParameterValueException(String.format("VPC network with name %s exists in NSX zone: %s and account %s", name, cmd.getZoneName(), cmd.getAccountName())); - } - - - String tier0GatewayPath = TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway; - - Tier1s tier1service = (Tier1s) nsxService.apply(Tier1s.class); - tier1 = new Tier1.Builder() - .setTier0Path(tier0GatewayPath) - .setResourceType(TIER_1_RESOURCE_TYPE) - .setPoolAllocation(ROUTING.name()) - .setHaMode(ACTIVE_STANDBY.name()) - .setFailoverMode(PREEMPTIVE.name()) - .setRouteAdvertisementTypes(List.of(TIER1_CONNECTED.name(), TIER1_IPSEC_LOCAL_ENDPOINT.name())) - .setId(name) - .setDisplayName(name) - .build(); + String name = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), cmd.getVpcId()); try { - tier1service.patch(name, tier1); - createTier1LocaleServices(name, edgeCluster); - } catch (Error error) { - ApiError ae = error.getData()._convertTo(ApiError.class); - return new NsxAnswer(cmd, new CloudRuntimeException(ae.getErrorMessage())); - } - return new NsxAnswer(cmd, true, ""); - } - - /** - * To instantiate Tier-1 in Edge Cluster - * @return - */ - private boolean createTier1LocaleServices(String tier1Id, String edgeCluster) { - try { - List localeServices = getTier0LocalServices(tier0Gateway); - com.vmware.nsx_policy.infra.tier_1s.LocaleServices tier1LocalService = (com.vmware.nsx_policy.infra.tier_1s.LocaleServices) nsxService.apply(com.vmware.nsx_policy.infra.tier_1s.LocaleServices.class); - com.vmware.nsx_policy.model.LocaleServices localeService = new com.vmware.nsx_policy.model.LocaleServices.Builder() - .setEdgeClusterPath(localeServices.get(0).getEdgeClusterPath()).build(); - tier1LocalService.patch(tier1Id, Tier_1_LOCALE_SERVICE_ID, localeService); - return true; - } catch (Error error) { - throw new CloudRuntimeException(String.format("Failed to instantiate tier-1 gateway %s in edge cluster %s", tier1Id, edgeCluster)); + nsxApiClient.createTier1Gateway(name, tier0Gateway, edgeCluster); + return new NsxAnswer(cmd, true, ""); + } catch (CloudRuntimeException e) { + LOGGER.error(String.format("Cannot create tier 1 gateway %s (VPC: %s): %s", name, cmd.getVpcName(), e.getMessage())); + return new NsxAnswer(cmd, e); } } private Answer executeRequest(DeleteNsxTier1GatewayCommand cmd) { + String tier1Id = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), cmd.getVpcId()); try { - String tier1Id = getTier1GatewayName(cmd); - com.vmware.nsx_policy.infra.tier_1s.LocaleServices localeService = (com.vmware.nsx_policy.infra.tier_1s.LocaleServices) - nsxService.apply(com.vmware.nsx_policy.infra.tier_1s.LocaleServices.class); - localeService.delete(tier1Id, Tier_1_LOCALE_SERVICE_ID); - Tier1s tier1service = (Tier1s) nsxService.apply(Tier1s.class); - tier1service.delete(tier1Id); + nsxApiClient.deleteTier1Gateway(tier1Id); } catch (Exception e) { return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); } @@ -360,140 +275,62 @@ public class NsxResource implements ServerResource { private Answer executeRequest(CreateNsxSegmentCommand cmd) { try { - SiteListResult sites = getSites(); - String errorMsg = null; - if (CollectionUtils.isNullOrEmpty(sites.getResults())) { - errorMsg = String.format("Failed to create network: %s as no sites are found in the linked NSX infrastructure", cmd.getTierNetwork().getName()); + SiteListResult sites = nsxApiClient.getSites(); + String errorMsg; + String networkName = cmd.getNetworkName(); + if (CollectionUtils.isEmpty(sites.getResults())) { + errorMsg = String.format("Failed to create network: %s as no sites are found in the linked NSX infrastructure", networkName); LOGGER.error(errorMsg); return new NsxAnswer(cmd, new CloudRuntimeException(errorMsg)); } String siteId = sites.getResults().get(0).getId(); - EnforcementPointListResult epList = getEnforcementPoints(siteId); - if (CollectionUtils.isNullOrEmpty(epList.getResults())) { - errorMsg = String.format("Failed to create network: %s as no enforcement points are found in the linked NSX infrastructure", cmd.getTierNetwork().getName()); + EnforcementPointListResult epList = nsxApiClient.getEnforcementPoints(siteId); + if (CollectionUtils.isEmpty(epList.getResults())) { + errorMsg = String.format("Failed to create network: %s as no enforcement points are found in the linked NSX infrastructure", networkName); LOGGER.error(errorMsg); return new NsxAnswer(cmd, new CloudRuntimeException(errorMsg)); } String enforcementPointPath = epList.getResults().get(0).getPath(); - TransportZoneListResult transportZoneListResult = getTransportZones(); - if (CollectionUtils.isNullOrEmpty(transportZoneListResult.getResults())) { - errorMsg = String.format("Failed to create network: %s as no transport zones were found in the linked NSX infrastructure", cmd.getTierNetwork().getName()); + TransportZoneListResult transportZoneListResult = nsxApiClient.getTransportZones(); + if (CollectionUtils.isEmpty(transportZoneListResult.getResults())) { + errorMsg = String.format("Failed to create network: %s as no transport zones were found in the linked NSX infrastructure", networkName); LOGGER.error(errorMsg); return new NsxAnswer(cmd, new CloudRuntimeException(errorMsg)); } List transportZones = transportZoneListResult.getResults().stream().filter(tz -> tz.getDisplayName().equals(transportZone)).collect(Collectors.toList()); - if (CollectionUtils.isNullOrEmpty(transportZones)) { - errorMsg = String.format("Failed to create network: %s as no transport zone of name %s was found in the linked NSX infrastructure", cmd.getTierNetwork().getName(), transportZone); + if (CollectionUtils.isEmpty(transportZones)) { + errorMsg = String.format("Failed to create network: %s as no transport zone of name %s was found in the linked NSX infrastructure", networkName, transportZone); LOGGER.error(errorMsg); return new NsxAnswer(cmd, new CloudRuntimeException(errorMsg)); } - String segmentName = getSegmentName(cmd.getAccountName(), cmd.getTierNetwork().getName(), cmd.getVpcName()); - Segments segmentService = (Segments) nsxService.apply(Segments.class); - SegmentSubnet subnet = new SegmentSubnet.Builder() - .setGatewayAddress(cmd.getTierNetwork().getGateway() + "/" + cmd.getTierNetwork().getCidr().split("/")[1]).build(); - Segment segment = new Segment.Builder() - .setResourceType(SEGMENT_RESOURCE_TYPE) - .setId(segmentName) - .setDisplayName(segmentName) - .setConnectivityPath(isNull(cmd.getVpcName()) ? TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway - : TIER_1_GATEWAY_PATH_PREFIX + getTier1GatewayName(cmd)) - .setAdminState(NsxApiClientUtils.AdminState.UP.name()) - .setSubnets(List.of(subnet)) - .setTransportZonePath(enforcementPointPath + "/transport-zones/" + transportZones.get(0).getId()) - .build(); - segmentService.patch(segmentName, segment); + String segmentName = NsxControllerUtils.getNsxSegmentId(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), cmd.getVpcId(), cmd.getNetworkId()); + String gatewayAddress = cmd.getNetworkGateway() + "/" + cmd.getNetworkCidr().split("/")[1]; + + nsxApiClient.createSegment(cmd.getZoneId(), cmd.getDomainId(), cmd.getAccountId(), cmd.getVpcId(), + segmentName, gatewayAddress, tier0Gateway, enforcementPointPath, transportZones); } catch (Exception e) { - LOGGER.error(String.format("Failed to create network: %s", cmd.getTierNetwork().getName())); + LOGGER.error(String.format("Failed to create network: %s", cmd.getNetworkName())); return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); } return new NsxAnswer(cmd, true, null); } private NsxAnswer executeRequest(DeleteNsxSegmentCommand cmd) { + String segmentName = NsxControllerUtils.getNsxSegmentId(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), + cmd.getVpcId(), cmd.getNetworkId()); try { Thread.sleep(30*1000); - String segmentName = getSegmentName(cmd.getAccountName(), cmd.getTierNetwork().getName(), cmd.getVpcName()); - Segments segmentService = (Segments) nsxService.apply(Segments.class); - segmentService.delete(segmentName); - DhcpRelayConfigs dhcpRelayConfig = (DhcpRelayConfigs) nsxService.apply(DhcpRelayConfigs.class); - dhcpRelayConfig.delete(getDhcpRelayId(cmd.getZoneName(), cmd.getAccountName(), cmd.getVpcName(), cmd.getTierNetwork().getName())); + nsxApiClient.deleteSegment(cmd.getZoneId(), cmd.getDomainId(), cmd.getAccountId(), cmd.getVpcId(), cmd.getNetworkId(), segmentName); } catch (Exception e) { - LOGGER.error(String.format("Failed to delete NSX segment: %s", getSegmentName(cmd.getAccountName(), cmd.getTierNetwork().getName(), cmd.getVpcName()))); + LOGGER.error(String.format("Failed to delete NSX segment: %s", segmentName)); return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); } return new NsxAnswer(cmd, true, null); } - private List getTier0LocalServices(String tier0Gateway) { - try { - LocaleServices tier0LocaleServices = (LocaleServices) nsxService.apply(LocaleServices.class); - LocaleServicesListResult result = tier0LocaleServices.list(tier0Gateway, null, false, null, null, null, null); - return result.getResults(); - } catch (Exception e) { - throw new CloudRuntimeException(String.format("Failed to fetch locale services for tier gateway %s due to %s", tier0Gateway, e.getMessage())); - } - } - - private Tier1 getTier1Gateway(String tier1GatewayId) { - try { - Tier1s tier1service = (Tier1s) nsxService.apply(Tier1s.class); - return tier1service.get(tier1GatewayId); - } catch (Exception e) { - LOGGER.debug(String.format("NSX Tier-1 gateway with name: %s not found", tier1GatewayId)); - } - return null; - } - - private SiteListResult getSites() { - try { - Sites sites = (Sites) nsxService.apply(Sites.class); - return sites.list(null, false, null, null, null, null); - } catch (Exception e) { - throw new CloudRuntimeException(String.format("Failed to fetch service segment list due to %s", e.getMessage())); - } - } - - private EnforcementPointListResult getEnforcementPoints(String siteId) { - try { - EnforcementPoints enforcementPoints = (EnforcementPoints) nsxService.apply(EnforcementPoints.class); - return enforcementPoints.list(siteId, null, false, null, null, null, null); - } catch (Exception e) { - throw new CloudRuntimeException(String.format("Failed to fetch service segment list due to %s", e.getMessage())); - } - } - - private TransportZoneListResult getTransportZones() { - try { - com.vmware.nsx.TransportZones transportZones = (com.vmware.nsx.TransportZones) nsxService.apply(com.vmware.nsx.TransportZones.class); - return transportZones.list(null, null, true, null, true, null, null, null, OVERLAY.name(), null); - } catch (Exception e) { - throw new CloudRuntimeException(String.format("Failed to fetch service segment list due to %s", e.getMessage())); - } - } - - private String getTier1GatewayName(CreateNsxTier1GatewayCommand cmd) { - return cmd.getZoneName() + "-" + cmd.getAccountName() + "-" + cmd.getVpcName(); - } - - private String getSegmentName(String accountName, String tierNetworkName, String vpcName) { - String segmentName = accountName + "-"; - if (isNull(vpcName)) { - return segmentName + tierNetworkName; - } - return segmentName + vpcName + "-" + tierNetworkName; - } - - private String getDhcpRelayId(String zoneName, String accountName, String vpcName, String networkName) { - String suffix = "-Relay"; - if (isNull(vpcName)) { - return zoneName + "-" + accountName + "-" + networkName + suffix; - } - return String.format("%s-%s-%s-%s%s", zoneName, accountName, vpcName, networkName, suffix); - } - @Override public boolean start() { return true; diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApi.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApi.java deleted file mode 100644 index 1d6b3e8867d..00000000000 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApi.java +++ /dev/null @@ -1,32 +0,0 @@ -// 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.service; - -import com.vmware.vapi.client.ApiClient; - -public class NsxApi { - - ApiClient apiClient; - - public ApiClient getApiClient() { - return apiClient; - } - - public void setApiClient(ApiClient apiClient) { - this.apiClient = apiClient; - } -} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java new file mode 100644 index 00000000000..973650db09c --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java @@ -0,0 +1,293 @@ +// 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.service; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.exception.CloudRuntimeException; +import com.vmware.nsx.model.TransportZone; +import com.vmware.nsx.model.TransportZoneListResult; +import com.vmware.nsx_policy.infra.DhcpRelayConfigs; +import com.vmware.nsx_policy.infra.Segments; +import com.vmware.nsx_policy.infra.Sites; +import com.vmware.nsx_policy.infra.Tier1s; +import com.vmware.nsx_policy.infra.sites.EnforcementPoints; +import com.vmware.nsx_policy.infra.tier_0s.LocaleServices; +import com.vmware.nsx_policy.model.ApiError; +import com.vmware.nsx_policy.model.DhcpRelayConfig; +import com.vmware.nsx_policy.model.EnforcementPointListResult; +import com.vmware.nsx_policy.model.LocaleServicesListResult; +import com.vmware.nsx_policy.model.Segment; +import com.vmware.nsx_policy.model.SegmentSubnet; +import com.vmware.nsx_policy.model.SiteListResult; +import com.vmware.nsx_policy.model.Tier1; +import com.vmware.vapi.bindings.Service; +import com.vmware.vapi.bindings.StubConfiguration; +import com.vmware.vapi.cis.authn.SecurityContextFactory; +import com.vmware.vapi.client.ApiClient; +import com.vmware.vapi.client.ApiClients; +import com.vmware.vapi.client.Configuration; +import com.vmware.vapi.core.ExecutionContext; +import com.vmware.vapi.internal.protocol.RestProtocol; +import com.vmware.vapi.internal.protocol.client.rest.authn.BasicAuthenticationAppender; +import com.vmware.vapi.protocol.HttpConfiguration; +import com.vmware.vapi.std.errors.Error; +import org.apache.cloudstack.utils.NsxControllerUtils; +import org.apache.log4j.Logger; + +import java.util.List; +import java.util.function.Function; + +import static java.util.Objects.isNull; + +public class NsxApiClient { + + private final Function, Service> nsxService; + + public static final int RESPONSE_TIMEOUT_SECONDS = 60; + private static final Logger LOGGER = Logger.getLogger(NsxApiClient.class); + + // Constants + private static final String TIER_1_RESOURCE_TYPE = "Tier1"; + private static final String Tier_1_LOCALE_SERVICE_ID = "default"; + private static final String SEGMENT_RESOURCE_TYPE = "Segment"; + private static final String TIER_0_GATEWAY_PATH_PREFIX = "/infra/tier-0s/"; + private static final String TIER_1_GATEWAY_PATH_PREFIX = "/infra/tier-1s/"; + + private enum PoolAllocation { ROUTING, LB_SMALL, LB_MEDIUM, LB_LARGE, LB_XLARGE } + + private enum TYPE { ROUTED, NATTED } + + private enum HAMode { ACTIVE_STANDBY, ACTIVE_ACTIVE } + + private enum FailoverMode { PREEMPTIVE, NON_PREEMPTIVE } + + private enum AdminState { UP, DOWN } + + private enum TransportType { OVERLAY, VLAN } + + public enum RouteAdvertisementType { TIER1_STATIC_ROUTES, TIER1_CONNECTED, TIER1_NAT, + TIER1_LB_VIP, TIER1_LB_SNAT, TIER1_DNS_FORWARDER_IP, TIER1_IPSEC_LOCAL_ENDPOINT + } + + public NsxApiClient(String hostname, String port, String username, char[] password) { + String controllerUrl = String.format("https://%s:%s", hostname, port); + HttpConfiguration.SslConfiguration.Builder sslConfigBuilder = new HttpConfiguration.SslConfiguration.Builder(); + sslConfigBuilder + .disableCertificateValidation() + .disableHostnameVerification(); + HttpConfiguration.SslConfiguration sslConfig = sslConfigBuilder.getConfig(); + + HttpConfiguration httpConfig = new HttpConfiguration.Builder() + .setSoTimeout(RESPONSE_TIMEOUT_SECONDS * 1000) + .setSslConfiguration(sslConfig).getConfig(); + + StubConfiguration stubConfig = new StubConfiguration(); + ExecutionContext.SecurityContext securityContext = SecurityContextFactory + .createUserPassSecurityContext(username, password); + stubConfig.setSecurityContext(securityContext); + + Configuration.Builder configBuilder = new Configuration.Builder() + .register(Configuration.HTTP_CONFIG_CFG, httpConfig) + .register(Configuration.STUB_CONFIG_CFG, stubConfig) + .register(RestProtocol.REST_REQUEST_AUTHENTICATOR_CFG, new BasicAuthenticationAppender()); + Configuration config = configBuilder.build(); + ApiClient apiClient = ApiClients.newRestClient(controllerUrl, config); + nsxService = apiClient::createStub; + } + + public void createDhcpRelayConfig(String dhcpRelayConfigName, List addresses) { + try { + DhcpRelayConfigs service = (DhcpRelayConfigs) nsxService.apply(DhcpRelayConfigs.class); + DhcpRelayConfig config = new DhcpRelayConfig.Builder() + .setServerAddresses(addresses) + .setId(dhcpRelayConfigName) + .setDisplayName(dhcpRelayConfigName) + .build(); + service.patch(dhcpRelayConfigName, config); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Error creating the DHCP relay config with name %s: %s", dhcpRelayConfigName, ae.getErrorMessage()); + LOGGER.error(msg); + throw new CloudRuntimeException(ae.getErrorMessage()); + } + } + + public Segment getSegmentById(String segmentName) { + try { + Segments segmentService = (Segments) nsxService.apply(Segments.class); + return segmentService.get(segmentName); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Error obtaining the segment with name %s: %s", segmentName, ae.getErrorMessage()); + LOGGER.error(msg); + throw new CloudRuntimeException(ae.getErrorMessage()); + } + } + + public void updateSegment(String segmentName, Segment segment) { + try { + Segments segmentService = (Segments) nsxService.apply(Segments.class); + segmentService.patch(segmentName, segment); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Error updating the segment with name %s: %s", segmentName, ae.getErrorMessage()); + LOGGER.error(msg); + throw new CloudRuntimeException(ae.getErrorMessage()); + } + } + + private Tier1 getTier1Gateway(String tier1GatewayId) { + try { + Tier1s tier1service = (Tier1s) nsxService.apply(Tier1s.class); + return tier1service.get(tier1GatewayId); + } catch (Exception e) { + LOGGER.debug(String.format("NSX Tier-1 gateway with name: %s not found", tier1GatewayId)); + } + return null; + } + + private List getTier0LocalServices(String tier0Gateway) { + try { + LocaleServices tier0LocaleServices = (LocaleServices) nsxService.apply(LocaleServices.class); + LocaleServicesListResult result = tier0LocaleServices.list(tier0Gateway, null, false, null, null, null, null); + return result.getResults(); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to fetch locale services for tier gateway %s due to %s", tier0Gateway, e.getMessage())); + } + } + + /** + * To instantiate Tier-1 in Edge Cluster + */ + private void createTier1LocaleServices(String tier1Id, String edgeCluster, String tier0Gateway) { + try { + List localeServices = getTier0LocalServices(tier0Gateway); + com.vmware.nsx_policy.infra.tier_1s.LocaleServices tier1LocalService = (com.vmware.nsx_policy.infra.tier_1s.LocaleServices) nsxService.apply(com.vmware.nsx_policy.infra.tier_1s.LocaleServices.class); + com.vmware.nsx_policy.model.LocaleServices localeService = new com.vmware.nsx_policy.model.LocaleServices.Builder() + .setEdgeClusterPath(localeServices.get(0).getEdgeClusterPath()).build(); + tier1LocalService.patch(tier1Id, Tier_1_LOCALE_SERVICE_ID, localeService); + } catch (Error error) { + throw new CloudRuntimeException(String.format("Failed to instantiate tier-1 gateway %s in edge cluster %s", tier1Id, edgeCluster)); + } + } + + public void createTier1Gateway(String name, String tier0Gateway, String edgeCluster) { + String tier0GatewayPath = TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway; + Tier1 tier1 = getTier1Gateway(name); + if (tier1 != null) { + throw new InvalidParameterValueException(String.format("VPC network with name %s exists in NSX zone", name)); + } + + Tier1s tier1service = (Tier1s) nsxService.apply(Tier1s.class); + tier1 = new Tier1.Builder() + .setTier0Path(tier0GatewayPath) + .setResourceType(TIER_1_RESOURCE_TYPE) + .setPoolAllocation(PoolAllocation.ROUTING.name()) + .setHaMode(HAMode.ACTIVE_STANDBY.name()) + .setFailoverMode(FailoverMode.PREEMPTIVE.name()) + .setRouteAdvertisementTypes(List.of(RouteAdvertisementType.TIER1_CONNECTED.name(), RouteAdvertisementType.TIER1_IPSEC_LOCAL_ENDPOINT.name())) + .setId(name) + .setDisplayName(name) + .build(); + try { + tier1service.patch(name, tier1); + createTier1LocaleServices(name, edgeCluster, tier0Gateway); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Error creating tier 1 gateway %s: %s", name, ae.getErrorMessage()); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public void deleteTier1Gateway(String tier1Id) { + com.vmware.nsx_policy.infra.tier_1s.LocaleServices localeService = (com.vmware.nsx_policy.infra.tier_1s.LocaleServices) + nsxService.apply(com.vmware.nsx_policy.infra.tier_1s.LocaleServices.class); + localeService.delete(tier1Id, Tier_1_LOCALE_SERVICE_ID); + Tier1s tier1service = (Tier1s) nsxService.apply(Tier1s.class); + tier1service.delete(tier1Id); + } + + public SiteListResult getSites() { + try { + Sites sites = (Sites) nsxService.apply(Sites.class); + return sites.list(null, false, null, null, null, null); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to fetch service segment list due to %s", e.getMessage())); + } + } + + public EnforcementPointListResult getEnforcementPoints(String siteId) { + try { + EnforcementPoints enforcementPoints = (EnforcementPoints) nsxService.apply(EnforcementPoints.class); + return enforcementPoints.list(siteId, null, false, null, null, null, null); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to fetch service segment list due to %s", e.getMessage())); + } + } + + public TransportZoneListResult getTransportZones() { + try { + com.vmware.nsx.TransportZones transportZones = (com.vmware.nsx.TransportZones) nsxService.apply(com.vmware.nsx.TransportZones.class); + return transportZones.list(null, null, true, null, true, null, null, null, TransportType.OVERLAY.name(), null); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to fetch service segment list due to %s", e.getMessage())); + } + } + + public void createSegment(long zoneId, long domainId, long accountId, Long vpcId, String segmentName, String gatewayAddress, String tier0Gateway, String enforcementPointPath, List transportZones) { + try { + Segments segmentService = (Segments) nsxService.apply(Segments.class); + SegmentSubnet subnet = new SegmentSubnet.Builder() + .setGatewayAddress(gatewayAddress) + .build(); + Segment segment = new Segment.Builder() + .setResourceType(SEGMENT_RESOURCE_TYPE) + .setId(segmentName) + .setDisplayName(segmentName) + .setConnectivityPath(isNull(vpcId) ? TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway + : TIER_1_GATEWAY_PATH_PREFIX + NsxControllerUtils.getTier1GatewayName(domainId, accountId, zoneId, vpcId)) + .setAdminState(AdminState.UP.name()) + .setSubnets(List.of(subnet)) + .setTransportZonePath(enforcementPointPath + "/transport-zones/" + transportZones.get(0).getId()) + .build(); + segmentService.patch(segmentName, segment); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Error creating segment %s: %s", segmentName, ae.getErrorMessage()); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public void deleteSegment(long zoneId, long domainId, long accountId, long vpcId, long networkId, String segmentName) { + try { + Segments segmentService = (Segments) nsxService.apply(Segments.class); + LOGGER.debug(String.format("Removing the segment with ID %s", segmentName)); + segmentService.delete(segmentName); + DhcpRelayConfigs dhcpRelayConfig = (DhcpRelayConfigs) nsxService.apply(DhcpRelayConfigs.class); + String dhcpRelayConfigId = NsxControllerUtils.getNsxDhcpRelayConfigId(zoneId, domainId, accountId, vpcId, networkId); + LOGGER.debug(String.format("Removing the DHCP relay config with ID %s", dhcpRelayConfigId)); + dhcpRelayConfig.delete(dhcpRelayConfigId); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Error deleting segment %s: %s", segmentName, ae.getErrorMessage()); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java index 1f97cbdfa41..edbc2eebffe 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java @@ -27,6 +27,8 @@ import com.cloud.agent.api.StartupCommand; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConnectionException; import com.cloud.exception.InsufficientCapacityException; @@ -59,6 +61,7 @@ import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachineProfile; @@ -96,6 +99,8 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS PhysicalNetworkDao physicalNetworkDao; @Inject NetworkModel networkModel; + @Inject + DomainDao domainDao; private static final Logger LOGGER = Logger.getLogger(NsxElement.class); @@ -112,9 +117,10 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS dnsCapabilities.put(Network.Capability.AllowDnsSuffixModification, "true"); capabilities.put(Network.Service.Dns, dnsCapabilities); -// capabilities.put(Network.Service.Connectivity, null); capabilities.put(Network.Service.StaticNat, null); - + capabilities.put(Network.Service.Lb, null); + capabilities.put(Network.Service.PortForwarding, null); + capabilities.put(Network.Service.NetworkACL, null); Map sourceNatCapabilities = new HashMap<>(); sourceNatCapabilities.put(Network.Capability.RedundantRouter, "true"); sourceNatCapabilities.put(Network.Capability.SupportedSourceNatTypes, "peraccount"); @@ -195,7 +201,14 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { Account account = accountMgr.getAccount(network.getAccountId()); NetworkVO networkVO = networkDao.findById(network.getId()); - return nsxService.deleteNetwork(account.getAccountName(), networkVO); + DataCenterVO zone = dataCenterDao.findById(network.getDataCenterId()); + DomainVO domain = domainDao.findById(account.getDomainId()); + if (Objects.isNull(zone)) { + String msg = String.format("Cannot find zone with ID %s", network.getDataCenterId()); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + return nsxService.deleteNetwork(zone.getId(), account.getId(), domain.getId(), networkVO); } @Override @@ -215,14 +228,14 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS @Override public boolean verifyServicesCombination(Set services) { - return false; + return true; } @Override public boolean configure(String name, Map params) throws ConfigurationException { agentManager.registerForHostEvents(this, true, true, true); resourceManager.registerResourceStateAdapter(this.getClass().getSimpleName(), this); - return false; + return true; } @Override @@ -254,6 +267,16 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS return null; } + private DomainVO getDomainFromAccount(Account account) { + DomainVO domain = domainDao.findById(account.getDomainId()); + if (Objects.isNull(domain)) { + String msg = String.format("Unable to find domain with id: %s", account.getDomainId()); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + return domain; + } + @Override public boolean implementVpc(Vpc vpc, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { DataCenterVO zone = zoneFunction.apply(vpc.getZoneId()); @@ -265,7 +288,8 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS throw new InvalidParameterValueException(String.format("Failed to find account with id %s", vpc.getAccountId())); } Account account = isNsxAndAccount.second(); - return nsxService.createVpcNetwork(vpc.getZoneId(), zone.getName(), account.getAccountId(), account.getName(), vpc.getName()); + DomainVO domain = getDomainFromAccount(account); + return nsxService.createVpcNetwork(vpc.getZoneId(), account.getId(), domain.getId(), vpc.getId(), vpc.getName()); } @Override @@ -279,8 +303,8 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS throw new InvalidParameterValueException(String.format("Failed to find account with id %s", vpc.getAccountId())); } Account account = isNsxAndAccount.second(); - - return nsxService.deleteVpcNetwork(vpc.getZoneId(), zone.getName(), account.getAccountId(), account.getName(), vpc.getName()); + DomainVO domain = getDomainFromAccount(account); + return nsxService.deleteVpcNetwork(vpc.getZoneId(), account.getId(), domain.getId(), vpc.getId(), vpc.getName()); } private Pair validateVpcConfigurationAndGetAccount(DataCenterVO zone, Vpc vpc) { diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java index e4bfcf30aa4..6b0c2472b41 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java @@ -20,9 +20,10 @@ import static java.util.Objects.isNull; import static java.util.Objects.nonNull; import com.cloud.dc.DataCenter; -import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.exception.InvalidParameterValueException; @@ -48,6 +49,9 @@ import com.cloud.vm.VirtualMachineProfile; import org.apache.cloudstack.NsxAnswer; import org.apache.cloudstack.agent.api.CreateNsxDhcpRelayConfigCommand; import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand; +import org.apache.cloudstack.utils.NsxControllerUtils; + +import org.apache.cloudstack.utils.NsxHelper; import org.apache.log4j.Logger; import javax.inject.Inject; @@ -62,9 +66,9 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr @Inject NsxControllerUtils nsxControllerUtils; @Inject - DataCenterDao zoneDao; - @Inject AccountDao accountDao; + @Inject + DomainDao domainDao; public NsxGuestNetworkGuru() { super(); @@ -130,17 +134,23 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr implemented.setName(name); } implemented.setBroadcastUri(Networks.BroadcastDomainType.NSX.toUri("nsx")); + + return network; + } + + @Override + public void setup(Network network, long networkId) { try { + NetworkVO designedNetwork = _networkDao.findById(networkId); long zoneId = network.getDataCenterId(); - DataCenter zone = zoneDao.findById(zoneId); + DataCenter zone = _dcDao.findById(zoneId); if (isNull(zone)) { throw new CloudRuntimeException(String.format("Failed to find zone with id: %s", zoneId)); } - createNsxSegment(implemented, zone); + createNsxSegment(designedNetwork, zone); } catch (Exception ex) { throw new CloudRuntimeException("unable to create NSX network " + network.getUuid() + "due to: " + ex.getMessage()); } - return network; } @Override @@ -173,16 +183,6 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr implemented.setName(network.getName()); } implemented.setBroadcastUri(Networks.BroadcastDomainType.NSX.toUri("nsx")); -// try { -// long zoneId = network.getDataCenterId(); -// DataCenter zone = zoneDao.findById(zoneId); -// if (isNull(zone)) { -// throw new CloudRuntimeException(String.format("Failed to find zone with id: %s", zoneId)); -// } -// createNsxSegment(implemented, zone); -// } catch (Exception ex) { -// throw new CloudRuntimeException("unable to create NSX network " + network.getUuid() + "due to: " + ex.getMessage()); -// } return implemented; } @@ -211,12 +211,17 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr throw new CloudRuntimeException(msg); } + DomainVO domain = domainDao.findById(account.getDomainId()); + if (Objects.isNull(domain)) { + String msg = String.format("Unable to find domain with id: %s", account.getDomainId()); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + // Create the DHCP relay config for the segment String iPv4Address = nicProfile.getIPv4Address(); List addresses = List.of(iPv4Address); - CreateNsxDhcpRelayConfigCommand command = new CreateNsxDhcpRelayConfigCommand(zone.getName(), zone.getId(), - account.getAccountName(), network.getAccountId(), - vpc.getName(), network.getName(), addresses); + CreateNsxDhcpRelayConfigCommand command = NsxHelper.createNsxDhcpRelayConfigCommand(domain, account, zone, vpc, network, addresses); NsxAnswer answer = nsxControllerUtils.sendNsxCommand(command, zone.getId()); if (!answer.getResult()) { String msg = String.format("Error creating DHCP relay config for network %s and nic %s: %s", network.getName(), nic.getName(), answer.getDetails()); @@ -265,7 +270,7 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr } private void createNsxSegment(NetworkVO networkVO, DataCenter zone) { - String vpcName = null; + String vpcName = null; if (nonNull(networkVO.getVpcId())) { VpcVO vpc = _vpcDao.findById(networkVO.getVpcId()); if (isNull(vpc)) { @@ -277,8 +282,13 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr if (isNull(account)) { throw new CloudRuntimeException(String.format("Unable to find account with id: %s", networkVO.getAccountId())); } - CreateNsxSegmentCommand command = new CreateNsxSegmentCommand(zone.getName(), zone.getId(), - account.getAccountName(), networkVO.getAccountId(), vpcName, networkVO); + DomainVO domain = domainDao.findById(account.getDomainId()); + if (Objects.isNull(domain)) { + String msg = String.format("Unable to find domain with id: %s", account.getDomainId()); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + CreateNsxSegmentCommand command = NsxHelper.createNsxSegmentCommand(domain, account, zone, vpcName, networkVO); NsxAnswer answer = nsxControllerUtils.sendNsxCommand(command, zone.getId()); if (!answer.getResult()) { throw new CloudRuntimeException("can not create NSX network"); diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderServiceImpl.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderServiceImpl.java index 00069e49e45..78239b01cc2 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderServiceImpl.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderServiceImpl.java @@ -53,9 +53,6 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; - - - public class NsxProviderServiceImpl implements NsxProviderService { @Inject diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java index 2158d995208..999f28bde25 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java @@ -23,37 +23,39 @@ import org.apache.cloudstack.NsxAnswer; import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand; import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand; +import org.apache.cloudstack.utils.NsxControllerUtils; import javax.inject.Inject; import java.util.Objects; public class NsxServiceImpl implements NsxService { @Inject - private NsxControllerUtils nsxControllerUtils; + NsxControllerUtils nsxControllerUtils; @Inject - private VpcDao vpcDao; + VpcDao vpcDao; - public boolean createVpcNetwork(Long zoneId, String zoneName, Long accountId, String accountName, String vpcName) { + public boolean createVpcNetwork(Long zoneId, long accountId, long domainId, long vpcId, String vpcName) { CreateNsxTier1GatewayCommand createNsxTier1GatewayCommand = - new CreateNsxTier1GatewayCommand(zoneName, zoneId, accountName, accountId, vpcName); + new CreateNsxTier1GatewayCommand(domainId, accountId, zoneId, vpcId, vpcName); NsxAnswer result = nsxControllerUtils.sendNsxCommand(createNsxTier1GatewayCommand, zoneId); return result.getResult(); } - public boolean deleteVpcNetwork(Long zoneId, String zoneName, Long accountId, String accountName, String vpcName) { + public boolean deleteVpcNetwork(Long zoneId, long accountId, long domainId, Long vpcId, String vpcName) { DeleteNsxTier1GatewayCommand deleteNsxTier1GatewayCommand = - new DeleteNsxTier1GatewayCommand(zoneName, zoneId, accountName, accountId, vpcName); + new DeleteNsxTier1GatewayCommand(domainId, accountId, zoneId, vpcId, vpcName); NsxAnswer result = nsxControllerUtils.sendNsxCommand(deleteNsxTier1GatewayCommand, zoneId); return result.getResult(); } - public boolean deleteNetwork(String accountName, NetworkVO network) { + public boolean deleteNetwork(long zoneId, long accountId, long domainId, NetworkVO network) { String vpcName = null; if (Objects.nonNull(network.getVpcId())) { VpcVO vpc = vpcDao.findById(network.getVpcId()); vpcName = Objects.nonNull(vpc) ? vpc.getName() : null; } - DeleteNsxSegmentCommand deleteNsxSegmentCommand = new DeleteNsxSegmentCommand(accountName, vpcName, network); + DeleteNsxSegmentCommand deleteNsxSegmentCommand = new DeleteNsxSegmentCommand(domainId, accountId, zoneId, + network.getVpcId(), vpcName, network.getId(), network.getName()); NsxAnswer result = nsxControllerUtils.sendNsxCommand(deleteNsxSegmentCommand, network.getDataCenterId()); return result.getResult(); } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxApiClientUtils.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxApiClientUtils.java deleted file mode 100644 index 26aad6ad635..00000000000 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxApiClientUtils.java +++ /dev/null @@ -1,103 +0,0 @@ -// 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.utils; - -import com.vmware.vapi.bindings.StubConfiguration; -import com.vmware.vapi.cis.authn.SecurityContextFactory; -import com.vmware.vapi.client.ApiClient; -import com.vmware.vapi.client.ApiClients; -import com.vmware.vapi.client.Configuration; -import com.vmware.vapi.core.ExecutionContext.SecurityContext; -import com.vmware.vapi.internal.protocol.RestProtocol; -import com.vmware.vapi.internal.protocol.client.rest.authn.BasicAuthenticationAppender; -import com.vmware.vapi.protocol.HttpConfiguration; -import org.apache.log4j.Logger; - -public class NsxApiClientUtils { - private static final Logger S_LOGGER = Logger.getLogger(NsxApiClientUtils.class); - public static ApiClient apiClient = null; - public static final int RESPONSE_TIMEOUT_SECONDS = 60; - - public enum PoolAllocation { - ROUTING, - LB_SMALL, - LB_MEDIUM, - LB_LARGE, - LB_XLARGE - } - - public enum TYPE { - ROUTED, - NATTED - } - - public enum HAMode { - ACTIVE_STANDBY, - ACTIVE_ACTIVE - } - - public enum FailoverMode { - PREEMPTIVE, - NON_PREEMPTIVE - } - - public enum AdminState { - UP, - DOWN - } - - public enum TransportType { - OVERLAY, - VLAN - } - - public enum RouteAdvertisementType { - TIER1_STATIC_ROUTES, - TIER1_CONNECTED, - TIER1_NAT, - TIER1_LB_VIP, - TIER1_LB_SNAT, - TIER1_DNS_FORWARDER_IP, - TIER1_IPSEC_LOCAL_ENDPOINT - } - public static ApiClient createApiClient(String hostname, String port, String username, char[] password) { - String controllerUrl = String.format("https://%s:%s", hostname, port); - HttpConfiguration.SslConfiguration.Builder sslConfigBuilder = new HttpConfiguration.SslConfiguration.Builder(); - sslConfigBuilder - .disableCertificateValidation() - .disableHostnameVerification(); - HttpConfiguration.SslConfiguration sslConfig = sslConfigBuilder.getConfig(); - - HttpConfiguration httpConfig = new HttpConfiguration.Builder() - .setSoTimeout(RESPONSE_TIMEOUT_SECONDS * 1000) - .setSslConfiguration(sslConfig).getConfig(); - - StubConfiguration stubConfig = new StubConfiguration(); - SecurityContext securityContext = SecurityContextFactory - .createUserPassSecurityContext(username, password); - stubConfig.setSecurityContext(securityContext); - - Configuration.Builder configBuilder = new Configuration.Builder() - .register(Configuration.HTTP_CONFIG_CFG, httpConfig) - .register(Configuration.STUB_CONFIG_CFG, stubConfig) - .register(RestProtocol.REST_REQUEST_AUTHENTICATOR_CFG, new BasicAuthenticationAppender()); - Configuration config = configBuilder.build(); - apiClient = ApiClients.newRestClient(controllerUrl, config); - - return apiClient; - } -} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxControllerUtils.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java similarity index 66% rename from plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxControllerUtils.java rename to plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java index 944d663c5df..bef09bb0d55 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxControllerUtils.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.service; +package org.apache.cloudstack.utils; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -28,6 +28,8 @@ import org.springframework.stereotype.Component; import javax.inject.Inject; +import static java.util.Objects.isNull; + @Component public class NsxControllerUtils { private static final Logger s_logger = Logger.getLogger(NsxControllerUtils.class); @@ -53,4 +55,24 @@ public class NsxControllerUtils { return (NsxAnswer) answer; } + + public static String getTier1GatewayName(long domainId, long accountId, long zoneId, long vpcId) { + return String.format("D%s-A%s-Z%s-V%s", domainId, accountId, zoneId, vpcId); + } + + public static String getNsxSegmentId(long domainId, long accountId, long zoneId, Long vpcId, long networkId) { + String segmentName = String.format("D%s-A%s-Z%s", domainId, accountId, zoneId); + if (isNull(vpcId)) { + return String.format("%s-S%s", segmentName, networkId); + } + return String.format("%s-V%s-S%s",segmentName, vpcId, networkId); + } + + public static String getNsxDhcpRelayConfigId(long zoneId, long domainId, long accountId, Long vpcId, long networkId) { + String suffix = "Relay"; + if (isNull(vpcId)) { + return String.format("D%s-A%s-Z%s-S%s-%s", domainId, accountId, zoneId, networkId, suffix); + } + return String.format("D%s-A%s-Z%s-V%s-S%s-%s", domainId, accountId, zoneId, vpcId, networkId, suffix); + } } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxHelper.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxHelper.java new file mode 100644 index 00000000000..ec1b74cf475 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxHelper.java @@ -0,0 +1,41 @@ +// 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.utils; + +import com.cloud.dc.DataCenter; +import com.cloud.domain.DomainVO; +import com.cloud.network.Network; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.user.Account; +import org.apache.cloudstack.agent.api.CreateNsxDhcpRelayConfigCommand; +import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand; + +import java.util.List; + +public class NsxHelper { + + public static CreateNsxDhcpRelayConfigCommand createNsxDhcpRelayConfigCommand(DomainVO domain, Account account, DataCenter zone, VpcVO vpc, Network network, List addresses) { + return new CreateNsxDhcpRelayConfigCommand(domain.getId(), account.getId(), zone.getId(), + vpc.getId(), vpc.getName(), network.getId(), network.getName(), addresses); + } + + public static CreateNsxSegmentCommand createNsxSegmentCommand(DomainVO domain, Account account, DataCenter zone, String vpcName, NetworkVO networkVO) { + return new CreateNsxSegmentCommand(domain.getId(), account.getId(), zone.getId(), + networkVO.getVpcId(), vpcName, networkVO.getId(), networkVO.getName(), networkVO.getGateway(), networkVO.getCidr()); + } +} diff --git a/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml index 4e45b5fab99..43e03657b7a 100644 --- a/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml +++ b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml @@ -33,6 +33,6 @@ - + diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/resource/NsxResourceTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/resource/NsxResourceTest.java new file mode 100644 index 00000000000..9e1a98c854d --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/resource/NsxResourceTest.java @@ -0,0 +1,163 @@ +// 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.resource; + +import com.cloud.network.dao.NetworkVO; +import com.vmware.nsx.model.TransportZone; +import com.vmware.nsx.model.TransportZoneListResult; +import com.vmware.nsx_policy.model.EnforcementPoint; +import com.vmware.nsx_policy.model.EnforcementPointListResult; +import com.vmware.nsx_policy.model.Site; +import com.vmware.nsx_policy.model.SiteListResult; +import junit.framework.Assert; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand; +import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; +import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand; +import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand; +import org.apache.cloudstack.agent.api.NsxCommand; +import org.apache.cloudstack.service.NsxApiClient; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; + +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class NsxResourceTest { + + @Mock + NsxApiClient nsxApi; + + NsxResource nsxResource; + AutoCloseable closeable; + @Mock + EnforcementPointListResult enforcementPointListResult; + @Mock + SiteListResult siteListResult; + @Mock + TransportZoneListResult transportZoneListResult; + + @Before + public void setup() { + closeable = MockitoAnnotations.openMocks(this); + nsxResource = new NsxResource(); + nsxResource.nsxApiClient = nsxApi; + nsxResource.transportZone = "Overlay"; + } + + @After + public void tearDown() throws Exception { + closeable.close(); + } + + @Test + public void testConfigure() throws ConfigurationException { + Map params = new HashMap<>(); + params.put("name", "nsxController"); + params.put("guid", "5944b356-644f-11ee-b8c2-f37bc1b564ff"); + params.put("zoneId", "1"); + params.put("hostname", "host1"); + params.put("username", "admin"); + params.put("password", "password"); + params.put("tier0Gateway", "Tier0-GW01"); + params.put("edgeCluster", "EdgeCluster"); + params.put("transportZone", "Overlay"); + params.put("port", "443"); + + Assert.assertTrue(nsxResource.configure("nsx", params)); + } + + @Test + public void testConfigure_MissingParameter() throws ConfigurationException { + Map params = new HashMap<>(); + + assertThrows(ConfigurationException.class, () -> nsxResource.configure("nsx", params)); + } + + @Test + public void testCreateNsxTier1Gateway() { + NsxCommand command = new CreateNsxTier1GatewayCommand(1L, 2L, + 1L, 3L, "VPC01"); + + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertTrue(answer.getResult()); + } + + @Test + public void testDeleteTier1Gateway() { + NsxCommand command = new DeleteNsxTier1GatewayCommand(1L, 1L, + 1L, 2L, "VPC01"); + + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertTrue(answer.getResult()); + } + + @Test + public void testCreateNsxSegment() { + NetworkVO tierNetwork = new NetworkVO(); + tierNetwork.setName("tier1"); + tierNetwork.setCidr("10.0.0.0/8"); + tierNetwork.setGateway("10.0.0.1"); + Site site = mock(Site.class); + List siteList = List.of(site); + EnforcementPoint enforcementPoint = mock(EnforcementPoint.class); + List enforcementPointList = List.of(enforcementPoint); + List transportZoneList = List.of(new TransportZone.Builder().setDisplayName("Overlay").build()); + + NsxCommand command = new CreateNsxSegmentCommand(1L, 1L, + 1L, 2L, "VPC01", 3L, "Web", "10.10.10.1", "10.10.10.0/24"); + + when(nsxApi.getSites()).thenReturn(siteListResult); + when(siteListResult.getResults()).thenReturn(siteList); + when(siteList.get(0).getId()).thenReturn("site1"); + + when(nsxApi.getEnforcementPoints(anyString())).thenReturn(enforcementPointListResult); + when(enforcementPointListResult.getResults()).thenReturn(enforcementPointList); + when(enforcementPointList.get(0).getPath()).thenReturn("enforcementPointPath"); + + when(nsxApi.getTransportZones()).thenReturn(transportZoneListResult); + when(transportZoneListResult.getResults()).thenReturn(transportZoneList); + + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertTrue(answer.getResult()); + } + + @Test + public void testDeleteNsxSegment() { + NetworkVO tierNetwork = new NetworkVO(); + tierNetwork.setName("tier1"); + DeleteNsxSegmentCommand command = new DeleteNsxSegmentCommand(1L, 1L, 1L, 3L, "VPC01", 2L, "Web"); + + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertTrue(answer.getResult()); + } +} diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java new file mode 100644 index 00000000000..79367a105b4 --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java @@ -0,0 +1,132 @@ +// 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.service; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.vpc.Vpc; +import com.cloud.resource.ResourceManager; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.vm.ReservationContext; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.List; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class NsxElementTest { + + @Mock + DataCenterDao dataCenterDao; + @Mock + NsxServiceImpl nsxService; + @Mock + AccountManager accountManager; + @Mock + NetworkDao networkDao; + @Mock + ResourceManager resourceManager; + @Mock + PhysicalNetworkDao physicalNetworkDao; + @Mock + NetworkModel networkModel; + @Mock + Vpc vpc; + @Mock + DataCenterVO zone; + @Mock + DataCenterVO dataCenterVO; + @Mock + Account account; + @Mock + DomainVO domain; + + NsxElement nsxElement; + ReservationContext reservationContext; + DeployDestination deployDestination; + @Mock + DomainDao domainDao; + + @Before + public void setup() { + nsxElement = new NsxElement(); + + nsxElement.dataCenterDao = dataCenterDao; + nsxElement.nsxService = nsxService; + nsxElement.accountMgr = accountManager; + nsxElement.networkDao = networkDao; + nsxElement.resourceManager = resourceManager; + nsxElement.physicalNetworkDao = physicalNetworkDao; + nsxElement.domainDao = domainDao; + nsxElement.networkModel = networkModel; + reservationContext = mock(ReservationContext.class); + deployDestination = mock(DeployDestination.class); + + when(vpc.getZoneId()).thenReturn(1L); + when(vpc.getAccountId()).thenReturn(2L); + when(dataCenterVO.getId()).thenReturn(1L); + when(vpc.getName()).thenReturn("VPC01"); + when(accountManager.getAccount(2L)).thenReturn(account); + when(dataCenterDao.findById(anyLong())).thenReturn(dataCenterVO); + when(domainDao.findById(anyLong())).thenReturn(domain); + when(vpc.getZoneId()).thenReturn(1L); + when(vpc.getName()).thenReturn("testVPC"); + + PhysicalNetworkVO physicalNetworkVO = new PhysicalNetworkVO(); + physicalNetworkVO.setIsolationMethods(List.of("NSX")); + List physicalNetworkVOList = List.of(physicalNetworkVO); + + when(physicalNetworkDao.listByZoneAndTrafficType(1L, Networks.TrafficType.Guest)).thenReturn(physicalNetworkVOList); + } + + @Test + public void testImplementVpc() throws ResourceUnavailableException, InsufficientCapacityException { + when(nsxService.createVpcNetwork(anyLong(), anyLong(), anyLong(), anyLong(), anyString())).thenReturn(true); + + assertTrue(nsxElement.implementVpc(vpc, deployDestination, reservationContext)); + } + + @Test + public void testShutdownVpc() { + when(nsxService.deleteVpcNetwork(anyLong(), anyLong(), anyLong(), anyLong(), anyString())).thenReturn(true); + + assertTrue(nsxElement.shutdownVpc(vpc, reservationContext)); + } + + + +} diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxGuestNetworkGuruTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxGuestNetworkGuruTest.java new file mode 100644 index 00000000000..c70945aaa5e --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxGuestNetworkGuruTest.java @@ -0,0 +1,217 @@ +// 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.service; + +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.Account; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.vm.ReservationContext; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand; +import org.apache.cloudstack.agent.api.NsxCommand; +import org.apache.cloudstack.utils.NsxControllerUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.List; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.lenient; + +@RunWith(MockitoJUnitRunner.class) +public class NsxGuestNetworkGuruTest { + + @Mock + PhysicalNetworkDao physicalNetworkDao; + @Mock + DataCenterDao dcDao; + @Mock + VpcDao vpcDao; + @Mock + NetworkOfferingServiceMapDao networkOfferingServiceMapDao; + @Mock + NsxControllerUtils nsxControllerUtils; + @Mock + AccountDao accountDao; + @Mock + PhysicalNetworkVO physicalNetwork; + @Mock + DataCenterVO dataCenterVO; + @Mock + NetworkOffering offering; + @Mock + DeploymentPlan plan; + @Mock + Network network; + @Mock + Account account; + @Mock + VpcVO vpcVO; + @Mock + NetworkModel networkModel; + @Mock + DomainDao domainDao; + @Mock + NetworkDao networkDao; + + NsxGuestNetworkGuru guru; + AutoCloseable closeable; + + @Before + public void setUp() { + closeable = MockitoAnnotations.openMocks(this); + guru = new NsxGuestNetworkGuru(); + ReflectionTestUtils.setField(guru, "_physicalNetworkDao", physicalNetworkDao); + ReflectionTestUtils.setField(guru, "_dcDao", dcDao); + ReflectionTestUtils.setField(guru, "_networkDao", networkDao); + ReflectionTestUtils.setField(guru, "_networkModel", networkModel); + ReflectionTestUtils.setField(guru, "_vpcDao", vpcDao); + + guru.networkOfferingServiceMapDao = networkOfferingServiceMapDao; + guru.nsxControllerUtils = nsxControllerUtils; + guru.accountDao = accountDao; + guru.domainDao = domainDao; + + Mockito.when(dataCenterVO.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced); + + when(physicalNetwork.getIsolationMethods()).thenReturn(List.of("NSX")); + + when(offering.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + when(offering.getGuestType()).thenReturn(Network.GuestType.Isolated); + when(offering.getId()).thenReturn(1L); + + when(plan.getDataCenterId()).thenReturn(1L); + when(plan.getPhysicalNetworkId()).thenReturn(1L); + + when(vpcDao.findById(anyLong())).thenReturn(vpcVO); + + when(vpcVO.getName()).thenReturn("VPC01"); + + when(account.getAccountId()).thenReturn(1L); + when(accountDao.findById(anyLong())).thenReturn(mock(AccountVO.class)); + when(domainDao.findById(anyLong())).thenReturn(mock(DomainVO.class)); + + Mockito.when(networkOfferingServiceMapDao.isProviderForNetworkOffering(offering.getId(), Network.Provider.Nsx)).thenReturn( + true); + } + + @After + public void tearDown() throws Exception { + closeable.close(); + } + + @Test + public void testIsMyIsolationMethod() { + assertTrue(guru.isMyIsolationMethod(physicalNetwork)); + } + + @Test + public void testCanHandle() { + assertTrue(guru.canHandle(offering, dataCenterVO.getNetworkType(), physicalNetwork)); + } + + @Test + public void testNsxNetworkDesign() { + when(physicalNetworkDao.findById(ArgumentMatchers.anyLong())).thenReturn(physicalNetwork); + when(dcDao.findById(ArgumentMatchers.anyLong())).thenReturn(dataCenterVO); + + Network designedNetwork = guru.design(offering, plan, network, "", 1L, account); + assertNotNull(designedNetwork); + assertSame(Networks.BroadcastDomainType.NSX, designedNetwork.getBroadcastDomainType()); + assertSame(Network.State.Allocated, designedNetwork.getState()); + } + + @Test + public void testNsxNetworkSetup() { + when(dcDao.findById(ArgumentMatchers.anyLong())).thenReturn(dataCenterVO); + when(networkDao.findById(ArgumentMatchers.anyLong())).thenReturn(mock(NetworkVO.class)); + when(nsxControllerUtils.sendNsxCommand(any(CreateNsxSegmentCommand.class), anyLong())).thenReturn( + new NsxAnswer(new NsxCommand(), true, "")); + + guru.setup(network, 1L); + verify(nsxControllerUtils, times(1)).sendNsxCommand(any(CreateNsxSegmentCommand.class), anyLong()); + } + + @Test + public void testNsxNetworkImplementation() { + final DeployDestination deployDestination = mock(DeployDestination.class); + final ReservationContext reservationContext = mock(ReservationContext.class); + + when(network.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + when(network.getMode()).thenReturn(Networks.Mode.Dhcp); + when(network.getGateway()).thenReturn("192.168.1.1"); + when(network.getCidr()).thenReturn("192.168.1.0/24"); + when(network.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.NSX); + when(network.getNetworkOfferingId()).thenReturn(1L); + lenient().when(network.getState()).thenReturn(Network.State.Implementing); + when(network.getDataCenterId()).thenReturn(2L); + when(network.getPhysicalNetworkId()).thenReturn(3L); + when(network.getVpcId()).thenReturn(4L); + when(offering.isRedundantRouter()).thenReturn(false); + lenient().when(offering.getGuestType()).thenReturn(Network.GuestType.Isolated); + + + final Network implemented = guru.implement(network, offering, deployDestination, reservationContext); + assertEquals(Networks.BroadcastDomainType.NSX.toUri("nsx"), implemented.getBroadcastUri()); + assertEquals("192.168.1.1", implemented.getGateway()); + assertEquals("192.168.1.0/24", implemented.getCidr()); + assertEquals(Networks.Mode.Dhcp, implemented.getMode()); + assertEquals(Networks.BroadcastDomainType.NSX, implemented.getBroadcastDomainType()); + assertEquals(1L, implemented.getNetworkOfferingId()); + assertEquals(Network.State.Implemented, implemented.getState()); + assertEquals(2L, implemented.getDataCenterId()); + assertEquals(3L, implemented.getPhysicalNetworkId().longValue()); + assertEquals(4L, implemented.getVpcId().longValue()); + assertFalse(implemented.isRedundant()); + } +} diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxProviderServiceImplTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxProviderServiceImplTest.java new file mode 100644 index 00000000000..97717ac1524 --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxProviderServiceImplTest.java @@ -0,0 +1,158 @@ +// 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.service; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.host.Host; +import com.cloud.host.dao.HostDetailsDao; +import com.cloud.network.NsxProvider; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.element.NsxProviderVO; +import com.cloud.resource.ResourceManager; +import com.cloud.resource.ServerResource; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.command.AddNsxControllerCmd; +import org.apache.cloudstack.api.response.NsxControllerResponse; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class NsxProviderServiceImplTest { + @Mock + NsxProviderDao nsxProviderDao; + @Mock + DataCenterDao dataCenterDao; + @Mock + PhysicalNetworkDao physicalNetworkDao; + @Mock + NetworkDao networkDao; + @Mock + ResourceManager resourceManager; + @Mock + HostDetailsDao hostDetailsDao; + + NsxProviderServiceImpl nsxProviderService; + + @Before + public void setup() { + nsxProviderService = new NsxProviderServiceImpl(); + nsxProviderService.resourceManager = resourceManager; + nsxProviderService.nsxProviderDao = nsxProviderDao; + nsxProviderService.hostDetailsDao = hostDetailsDao; + nsxProviderService.dataCenterDao = dataCenterDao; + nsxProviderService.networkDao = networkDao; + nsxProviderService.physicalNetworkDao = physicalNetworkDao; + } + + @Test + public void testAddProvider() { + AddNsxControllerCmd cmd = mock(AddNsxControllerCmd.class); + when(cmd.getZoneId()).thenReturn(1L); + when(cmd.getName()).thenReturn("NsxController"); + when(cmd.getHostname()).thenReturn("192.168.0.100"); + when(cmd.getPort()).thenReturn("443"); + when(cmd.getUsername()).thenReturn("admin"); + when(cmd.getPassword()).thenReturn("password"); + when(cmd.getEdgeCluster()).thenReturn("EdgeCluster"); + when(cmd.getTier0Gateway()).thenReturn("Tier0-GW01"); + when(cmd.getTransportZone()).thenReturn("Overlay"); + when(resourceManager.addHost(anyLong(), any(ServerResource.class), any(Host.Type.class), anyMap())).thenReturn(mock(Host.class)); + try { + NsxProvider provider = nsxProviderService.addProvider(cmd); + Assert.assertNotNull(provider); + } catch (CloudRuntimeException e) { + e.printStackTrace(); + fail("Failed to add NSX controller due to internal error."); + } + } + + @Test + public void testCreateNsxControllerResponse() { + NsxProvider nsxProvider = mock(NsxProvider.class); + DataCenterVO zone = mock(DataCenterVO.class); + String uuid = UUID.randomUUID().toString(); + when(dataCenterDao.findById(anyLong())).thenReturn(zone); + when(zone.getUuid()).thenReturn(UUID.randomUUID().toString()); + when(zone.getName()).thenReturn("ZoneNSX"); + when(nsxProvider.getProviderName()).thenReturn("NSXController"); + when(nsxProvider.getUuid()).thenReturn(uuid); + when(nsxProvider.getHostname()).thenReturn("hostname"); + when(nsxProvider.getPort()).thenReturn("443"); + when(nsxProvider.getTier0Gateway()).thenReturn("Tier0Gw"); + when(nsxProvider.getEdgeCluster()).thenReturn("EdgeCluster"); + when(nsxProvider.getTransportZone()).thenReturn("Overlay"); + + NsxControllerResponse response = nsxProviderService.createNsxControllerResponse(nsxProvider); + + assertEquals(response.getEdgeCluster(), "EdgeCluster"); + assertEquals(response.getTier0Gateway(), "Tier0Gw"); + assertEquals(response.getTransportZone(), "Overlay"); + assertEquals(response.getZoneName(), "ZoneNSX"); + } + + @Test + public void testListNsxControllers() { + NsxProviderVO nsxProviderVO = Mockito.mock(NsxProviderVO.class); + + when(nsxProviderVO.getZoneId()).thenReturn(1L); + when(dataCenterDao.findById(1L)).thenReturn(mock(DataCenterVO.class)); + when(nsxProviderDao.findByZoneId(anyLong())).thenReturn(nsxProviderVO); + + List baseResponseList = nsxProviderService.listNsxProviders(1L); + assertEquals(1, baseResponseList.size()); + } + + @Test + public void testDeleteNsxController() { + NsxProviderVO nsxProviderVO = Mockito.mock(NsxProviderVO.class); + PhysicalNetworkVO physicalNetworkVO = mock(PhysicalNetworkVO.class); + List physicalNetworkVOList = List.of(physicalNetworkVO); + NetworkVO networkVO = mock(NetworkVO.class); + List networkVOList = List.of(networkVO); + + when(nsxProviderVO.getZoneId()).thenReturn(1L); + when(physicalNetworkVO.getId()).thenReturn(2L); + when(physicalNetworkDao.listByZone(1L)).thenReturn(physicalNetworkVOList); + when(nsxProviderDao.findById(anyLong())).thenReturn(nsxProviderVO); + when(networkDao.listByPhysicalNetwork(anyLong())).thenReturn(networkVOList); + + assertTrue(nsxProviderService.deleteNsxController(1L)); + } +} diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxServiceImplTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxServiceImplTest.java new file mode 100644 index 00000000000..effca9d4a30 --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxServiceImplTest.java @@ -0,0 +1,94 @@ +// 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.service; + +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; +import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand; +import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand; +import org.apache.cloudstack.utils.NsxControllerUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class NsxServiceImplTest { + @Mock + private NsxControllerUtils nsxControllerUtils; + @Mock + private VpcDao vpcDao; + NsxServiceImpl nsxService; + + AutoCloseable closeable; + + @Before + public void setup() { + closeable = MockitoAnnotations.openMocks(this); + nsxService = new NsxServiceImpl(); + nsxService.nsxControllerUtils = nsxControllerUtils; + nsxService.vpcDao = vpcDao; + } + + @After + public void teardown() throws Exception { + closeable.close(); + } + + @Test + public void testCreateVpcNetwork() { + NsxAnswer createNsxTier1GatewayAnswer = mock(NsxAnswer.class); + when(nsxControllerUtils.sendNsxCommand(any(CreateNsxTier1GatewayCommand.class), anyLong())).thenReturn(createNsxTier1GatewayAnswer); + when(createNsxTier1GatewayAnswer.getResult()).thenReturn(true); + + assertTrue(nsxService.createVpcNetwork(1L, 3L, 2L, 5L, "VPC01")); + } + + @Test + public void testDeleteVpcNetwork() { + NsxAnswer deleteNsxTier1GatewayAnswer = mock(NsxAnswer.class); + when(nsxControllerUtils.sendNsxCommand(any(DeleteNsxTier1GatewayCommand.class), anyLong())).thenReturn(deleteNsxTier1GatewayAnswer); + when(deleteNsxTier1GatewayAnswer.getResult()).thenReturn(true); + + assertTrue(nsxService.deleteVpcNetwork(1L, 2L, 3L, 10L, "VPC01")); + } + + @Test + public void testDelete() { + NetworkVO network = new NetworkVO(); + network.setVpcId(1L); + VpcVO vpc = mock(VpcVO.class); + when(vpcDao.findById(1L)).thenReturn(mock(VpcVO.class)); + NsxAnswer deleteNsxSegmentAnswer = mock(NsxAnswer.class); + when(nsxControllerUtils.sendNsxCommand(any(DeleteNsxSegmentCommand.class), anyLong())).thenReturn(deleteNsxSegmentAnswer); + when(deleteNsxSegmentAnswer.getResult()).thenReturn(true); + + assertTrue(nsxService.deleteNetwork(1L, 3L, 5L, network)); + } +} diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index ccb368e9caa..6df66446c52 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -2332,6 +2332,7 @@ public class ApiResponseHelper implements ResponseGenerator { response.setForVpc(_configMgr.isOfferingForVpc(offering)); response.setForTungsten(offering.isForTungsten()); response.setForNsx(offering.isForNsx()); + response.setNsxMode(offering.getNsxMode()); response.setServices(serviceResponses); //set network offering details Map details = _ntwkModel.getNtwkOffDetails(offering.getId()); diff --git a/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java index af0940609ba..bab22178e61 100644 --- a/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java @@ -72,6 +72,8 @@ public class VpcOfferingJoinDaoImpl extends GenericDaoBase detailsStr = cmd.getDetails(); final Boolean egressDefaultPolicy = cmd.getEgressDefaultPolicy(); Boolean forVpc = cmd.getForVpc(); + Boolean forNsx = cmd.isForNsx(); Boolean forTungsten = cmd.getForTungsten(); + String nsxMode = cmd.getNsxMode(); Integer maxconn = null; boolean enableKeepAlive = false; String servicePackageuuid = cmd.getServicePackageId(); @@ -5960,6 +5963,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } + if (Boolean.TRUE.equals(forNsx) && Boolean.TRUE.equals(forTungsten)) { + throw new InvalidParameterValueException("Network Offering cannot be for both Tungsten-Fabric and NSX"); + } + + if (Boolean.TRUE.equals(forNsx)) { + if (Objects.isNull(nsxMode)) { + throw new InvalidParameterValueException("Mode for an NSX offering needs to be specified. Valid values: " + Arrays.toString(NetworkOffering.NsxMode.values())); + } + if (!EnumUtils.isValidEnum(NetworkOffering.NsxMode.class, nsxMode)) { + throw new InvalidParameterValueException("Invalid mode passed. Valid values: " + Arrays.toString(NetworkOffering.NsxMode.values())); + } + } else { + if (Objects.nonNull(nsxMode)) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("nsxMode has is ignored for non-NSX enabled zones"); + } + nsxMode = null; + } + } + // Verify traffic type for (final TrafficType tType : TrafficType.values()) { if (tType.name().equalsIgnoreCase(trafficTypeString)) { @@ -6224,7 +6247,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } final NetworkOfferingVO offering = createNetworkOffering(name, displayText, trafficType, tags, specifyVlan, availability, networkRate, serviceProviderMap, false, guestType, false, - serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, forTungsten, false, domainIds, zoneIds, enable, internetProtocol); + serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, forTungsten, forNsx, nsxMode, domainIds, zoneIds, enable, internetProtocol); CallContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name); CallContext.current().putContextParameter(NetworkOffering.class, offering.getId()); return offering; @@ -6369,7 +6392,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Long serviceOfferingId, final boolean conserveMode, final Map> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent, final Map details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc, - Boolean forTungsten, Boolean forNsx, final List domainIds, final List zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol) { + Boolean forTungsten, Boolean forNsx, String mode, final List domainIds, final List zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol) { String servicePackageUuid; String spDescription = null; @@ -6595,7 +6618,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati s_logger.trace("Added service for the network offering: " + offService + " with provider " + provider.getName()); } - if (vpcOff) { + if (vpcOff && !forNsx) { final List supportedSvcs = new ArrayList(); supportedSvcs.addAll(serviceProviderMap.keySet()); _vpcMgr.validateNtwkOffForVpc(offering, supportedSvcs); diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java index fb3dea1129f..85c51b67191 100644 --- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java @@ -23,10 +23,15 @@ import java.util.UUID; import javax.inject.Inject; +import com.cloud.dc.DataCenter; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.domain.Domain; +import com.cloud.domain.dao.DomainDao; import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.backup.Backup; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -86,6 +91,10 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis @Inject protected AccountManager accountManager; @Inject + private DomainDao domainDao; + @Inject + private DataCenterDao dcDao; + @Inject private NetworkOfferingDetailsDao networkOfferingDetailsDao; @Inject protected @@ -160,11 +169,22 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis NetworkVO network = networkDao.findById(profile.getNetworkId()); to.setNetworkUuid(network.getUuid()); Account account = accountManager.getAccount(network.getAccountId()); + Domain domain = domainDao.findById(network.getDomainId()); + DataCenter zone = dcDao.findById(network.getDataCenterId()); + if (Objects.isNull(zone)) { + throw new CloudRuntimeException(String.format("Failed to find zone with ID: %s", network.getDataCenterId())); + } + if (Objects.isNull(account)) { + throw new CloudRuntimeException(String.format("Failed to find account with ID: %s", network.getAccountId())); + } + if (Objects.isNull(domain)) { + throw new CloudRuntimeException(String.format("Failed to find domain with ID: %s", network.getDomainId())); + } VpcVO vpc = null; if (Objects.nonNull(network) && Objects.nonNull(network.getVpcId())) { vpc = vpcDao.findById(network.getVpcId()); } - to.setNetworkSegmentName(getNetworkName(account.getAccountName(), vpc, network.getName())); + to.setNetworkSegmentName(getNetworkName(zone.getId(), domain.getId(), account.getId(), vpc, network.getId())); // Workaround to make sure the TO has the UUID we need for Nicira integration NicVO nicVO = nicDao.findById(profile.getId()); @@ -193,11 +213,12 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis return to; } - private String getNetworkName(String accountName, VpcVO vpc, String networkName) { + private String getNetworkName(long zoneId, long domainId, long accountId, VpcVO vpc, long networkId) { + String prefix = String.format("D%s-A%s-Z%s", domainId, accountId, zoneId); if (Objects.isNull(vpc)) { - return accountName + "-" + networkName; + return prefix + "-S" + networkId; } - return accountName + "-" + vpc.getName() + "-" + networkName; + return prefix + "-V" + vpc.getId() + "-S" + networkId; } diff --git a/server/src/main/java/com/cloud/network/guru/ControlNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/ControlNetworkGuru.java index 11f629a16d9..76d1ec46d61 100644 --- a/server/src/main/java/com/cloud/network/guru/ControlNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/ControlNetworkGuru.java @@ -104,6 +104,11 @@ public class ControlNetworkGuru extends PodBasedNetworkGuru implements NetworkGu return config; } + @Override + public void setup(Network network, long networkId) { + // do nothing + } + protected ControlNetworkGuru() { super(); } diff --git a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java index b5a88685ba0..0f7f31e6701 100644 --- a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java @@ -251,6 +251,11 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { return config; } + @Override + public void setup(Network network, long networkId) { + // do nothing + } + protected DirectNetworkGuru() { super(); _isolationMethods = new IsolationMethod[] { new IsolationMethod("VLAN"), new IsolationMethod("VXLAN") }; diff --git a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java index 420d458af6b..ce5af76bd3e 100644 --- a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java @@ -148,6 +148,11 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur _isolationMethods = null; } + @Override + public void setup(Network network, long networkId) { + // do nothing + } + private void updateNicIpv6(Network network, NicProfile nic, VirtualMachineProfile vm, DataCenter dc, boolean isGateway) throws InsufficientAddressCapacityException { boolean isIpv6Supported = networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()); if (!isIpv6Supported || nic.getIPv6Address() != null || network.getIp6Cidr() == null || network.getIp6Gateway() == null) { diff --git a/server/src/main/java/com/cloud/network/guru/PodBasedNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/PodBasedNetworkGuru.java index 168209b1e4b..42ae12aad85 100644 --- a/server/src/main/java/com/cloud/network/guru/PodBasedNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/PodBasedNetworkGuru.java @@ -89,6 +89,11 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru { return config; } + @Override + public void setup(Network network, long networkId) { + // do nothing + } + protected PodBasedNetworkGuru() { super(); } diff --git a/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java index 14f9ebe773c..d6da50ed5c6 100644 --- a/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java @@ -137,6 +137,11 @@ public class PrivateNetworkGuru extends AdapterBase implements NetworkGuru { return network; } + @Override + public void setup(Network network, long networkId) { + // do nothing + } + @Override public void deallocate(Network network, NicProfile nic, VirtualMachineProfile vm) { if (s_logger.isDebugEnabled()) { diff --git a/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java index 1c9654a2b45..5e157999357 100644 --- a/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java @@ -115,6 +115,11 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { } } + @Override + public void setup(Network network, long networkId) { + // do nothing + } + protected PublicNetworkGuru() { super(); } diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index 7088933f584..6e6cfedc2a0 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -62,6 +62,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.query.QueryService; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.log4j.Logger; import org.jetbrains.annotations.Nullable; @@ -325,7 +326,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis svcProviderMap.put(svc, defaultProviders); } } - createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap, true, State.Enabled, null, false, false, false); + createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap, + true, State.Enabled, null, false, + false, false, false, null); } // configure default vpc offering with Netscaler as LB Provider @@ -344,7 +347,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis svcProviderMap.put(svc, defaultProviders); } } - createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName, svcProviderMap, false, State.Enabled, null, false, false, false); + createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName, svcProviderMap, false, State.Enabled, null, false, false, false, false, null); } @@ -364,12 +367,13 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis svcProviderMap.put(svc, defaultProviders); } } - createVpcOffering(VpcOffering.redundantVPCOfferingName, VpcOffering.redundantVPCOfferingName, svcProviderMap, true, State.Enabled, null, false, false, true); + createVpcOffering(VpcOffering.redundantVPCOfferingName, VpcOffering.redundantVPCOfferingName, svcProviderMap, true, State.Enabled, + null, false, false, true, false, null); } - // configure default vpc offering with NSX as network service provider - if (_vpcOffDao.findByUniqueName(VpcOffering.DEFAULT_VPC_NSX_OFFERING_NAME) == null) { - s_logger.debug("Creating default VPC offering with NSX as network service provider" + VpcOffering.DEFAULT_VPC_NSX_OFFERING_NAME); + // configure default vpc offering with NSX as network service provider in NAT mode + if (_vpcOffDao.findByUniqueName(VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME) == null) { + s_logger.debug("Creating default VPC offering with NSX as network service provider" + VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME); final Map> svcProviderMap = new HashMap>(); final Set defaultProviders = Set.of(Provider.Nsx); for (final Service svc : getSupportedServices()) { @@ -380,7 +384,26 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis svcProviderMap.put(svc, defaultProviders); } } - createVpcOffering(VpcOffering.DEFAULT_VPC_NSX_OFFERING_NAME, VpcOffering.DEFAULT_VPC_NSX_OFFERING_NAME, svcProviderMap, false, State.Enabled, null, false, false, false); + createVpcOffering(VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME, VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME, svcProviderMap, false, + State.Enabled, null, false, false, false, true, NetworkOffering.NsxMode.NATTED.name()); + + } + + // configure default vpc offering with NSX as network service provider in Route mode + if (_vpcOffDao.findByUniqueName(VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME) == null) { + s_logger.debug("Creating default VPC offering with NSX as network service provider" + VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME); + final Map> svcProviderMap = new HashMap>(); + final Set defaultProviders = Set.of(Provider.Nsx); + for (final Service svc : getSupportedServices()) { + if (List.of(Service.UserData, Service.Dhcp, Service.Dns).contains(svc)) { + final Set userDataProvider = Set.of(Provider.VPCVirtualRouter); + svcProviderMap.put(svc, userDataProvider); + } else { + svcProviderMap.put(svc, defaultProviders); + } + } + createVpcOffering(VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME, VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME, svcProviderMap, false, + State.Enabled, null, false, false, false, true, NetworkOffering.NsxMode.ROUTED.name()); } } @@ -440,7 +463,25 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis final Long serviceOfferingId = cmd.getServiceOfferingId(); final List domainIds = cmd.getDomainIds(); final List zoneIds = cmd.getZoneIds(); + final Boolean forNsx = cmd.isForNsx(); + String nsxMode = cmd.getNsxMode(); final boolean enable = cmd.getEnable(); + + if (Boolean.TRUE.equals(forNsx)) { + if (Objects.isNull(nsxMode)) { + throw new InvalidParameterValueException("Mode for an NSX offering needs to be specified.Valid values: " + Arrays.toString(NetworkOffering.NsxMode.values())); + } + if (!EnumUtils.isValidEnum(NetworkOffering.NsxMode.class, nsxMode)) { + throw new InvalidParameterValueException("Invalid mode passed. Valid values: " + Arrays.toString(NetworkOffering.NsxMode.values())); + } + } else { + if (Objects.nonNull(nsxMode)) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("nsxMode has is ignored for non-NSX enabled zones"); + } + nsxMode = null; + } + } // check if valid domain if (CollectionUtils.isNotEmpty(cmd.getDomainIds())) { for (final Long domainId: cmd.getDomainIds()) { @@ -463,14 +504,15 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } return createVpcOffering(vpcOfferingName, displayText, supportedServices, - serviceProviderList, serviceCapabilityList, internetProtocol, serviceOfferingId, + serviceProviderList, serviceCapabilityList, internetProtocol, serviceOfferingId, forNsx, nsxMode, domainIds, zoneIds, (enable ? State.Enabled : State.Disabled)); } @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_CREATE, eventDescription = "creating vpc offering", create = true) public VpcOffering createVpcOffering(final String name, final String displayText, final List supportedServices, final Map> serviceProviders, - final Map serviceCapabilityList, final NetUtils.InternetProtocol internetProtocol, final Long serviceOfferingId, List domainIds, List zoneIds, State state) { + final Map serviceCapabilityList, final NetUtils.InternetProtocol internetProtocol, final Long serviceOfferingId, + final Boolean forNsx, final String mode, List domainIds, List zoneIds, State state) { if (!Ipv6Service.Ipv6OfferingCreationEnabled.value() && !(internetProtocol == null || NetUtils.InternetProtocol.IPv4.equals(internetProtocol))) { throw new InvalidParameterValueException(String.format("Configuration %s needs to be enabled for creating IPv6 supported VPC offering", Ipv6Service.Ipv6OfferingCreationEnabled.key())); @@ -555,7 +597,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis final boolean offersRegionLevelVPC = isVpcOfferingForRegionLevelVpc(serviceCapabilityList); final boolean redundantRouter = isVpcOfferingRedundantRouter(serviceCapabilityList); final VpcOfferingVO offering = createVpcOffering(name, displayText, svcProviderMap, false, state, serviceOfferingId, supportsDistributedRouter, offersRegionLevelVPC, - redundantRouter); + redundantRouter, forNsx, mode); if (offering != null) { List detailsVO = new ArrayList<>(); @@ -583,7 +625,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @DB protected VpcOfferingVO createVpcOffering(final String name, final String displayText, final Map> svcProviderMap, final boolean isDefault, final State state, final Long serviceOfferingId, final boolean supportsDistributedRouter, final boolean offersRegionLevelVPC, - final boolean redundantRouter) { + final boolean redundantRouter, Boolean forNsx, String mode) { return Transaction.execute(new TransactionCallback() { @Override @@ -594,6 +636,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (state != null) { offering.setState(state); } + offering.setForNsx(forNsx); + offering.setMode(mode); s_logger.debug("Adding vpc offering " + offering); offering = _vpcOffDao.persist(offering); // populate services and providers diff --git a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java index 75298b73e64..f7ada1fccf1 100644 --- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java @@ -1206,17 +1206,34 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio } _networkOfferingDao.persistDefaultL2NetworkOfferings(); - // Offering #9 - network offering for nsx provider - NetworkOfferingVO defaultNSXNetworkOffering = - new NetworkOfferingVO(NetworkOffering.DEFAULT_NSX_OFFERING, "Offering for NSX enabled networks", + // Offering #9 - network offering for nsx provider - NATTED mode + NetworkOfferingVO defaultNatNSXNetworkOffering = + new NetworkOfferingVO(NetworkOffering.DEFAULT_NAT_NSX_OFFERING, "Offering for NSX enabled networks - NAT mode", TrafficType.Guest, false, false, null, null, true, Availability.Optional, null, GuestType.Isolated, false, false, false, false, false, true); - defaultNSXNetworkOffering.setForNsx(true); - defaultNSXNetworkOffering.setState(NetworkOffering.State.Enabled); - defaultNSXNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNSXNetworkOffering); + defaultNatNSXNetworkOffering.setForNsx(true); + defaultNatNSXNetworkOffering.setNsxMode(NetworkOffering.NsxMode.NATTED.name()); + defaultNatNSXNetworkOffering.setState(NetworkOffering.State.Enabled); + defaultNatNSXNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNatNSXNetworkOffering); for (Map.Entry service : defaultNSXNetworkOfferingProviders.entrySet()) { NetworkOfferingServiceMapVO offService = - new NetworkOfferingServiceMapVO(defaultNSXNetworkOffering.getId(), service.getKey(), service.getValue()); + new NetworkOfferingServiceMapVO(defaultNatNSXNetworkOffering.getId(), service.getKey(), service.getValue()); + _ntwkOfferingServiceMapDao.persist(offService); + s_logger.trace("Added service for the network offering: " + offService); + } + + // Offering #10 - network offering for nsx provider - ROUTED mode + NetworkOfferingVO defaultRouteNSXNetworkOffering = + new NetworkOfferingVO(NetworkOffering.DEFAULT_NAT_NSX_OFFERING, "Offering for NSX enabled networks - NAT mode", + TrafficType.Guest, false, false, null, null, true, Availability.Optional, null, GuestType.Isolated, false, false, false, false, false, true); + defaultRouteNSXNetworkOffering.setForNsx(true); + defaultRouteNSXNetworkOffering.setNsxMode(NetworkOffering.NsxMode.ROUTED.name()); + defaultRouteNSXNetworkOffering.setState(NetworkOffering.State.Enabled); + defaultRouteNSXNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultRouteNSXNetworkOffering); + + for (Map.Entry service : defaultNSXNetworkOfferingProviders.entrySet()) { + NetworkOfferingServiceMapVO offService = + new NetworkOfferingServiceMapVO(defaultRouteNSXNetworkOffering.getId(), service.getKey(), service.getValue()); _ntwkOfferingServiceMapDao.persist(offService); s_logger.trace("Added service for the network offering: " + offService); } diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index 21bf3d57ff2..5b29061585c 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -546,7 +546,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu Integer networkRate, Map> serviceProviderMap, boolean isDefault, GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, - Boolean forTungsten, Boolean forNsx, List domainIds, List zoneIds, boolean enableOffering, NetUtils.InternetProtocol internetProtocol) { + Boolean forTungsten, Boolean forNsx, String mode, List domainIds, List zoneIds, boolean enableOffering, NetUtils.InternetProtocol internetProtocol) { // TODO Auto-generated method stub return null; } diff --git a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index 1038420f9a5..52885c43753 100644 --- a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -129,7 +129,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, false, false, null, null, false, null); + null, false, null, true, false, null, false, null, true, false, false, false, null,null, null, false, null); assertNotNull("Shared network offering with specifyVlan=true failed to create ", off); } @@ -137,7 +137,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithNoVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, false, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, true, false, null, false, null, true, false, false, false, null, null, false, null); + false, null, false, null, true, false, null, false, null, true, false, false, false, null, null,null, false, null); assertNotNull("Shared network offering with specifyVlan=false was created", off); } @@ -145,7 +145,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, false, false, null, null, false, null); + null, false, null, true, false, null, false, null, true, false, false, false, null,null, null, false, null); assertNotNull("Shared network offering with specifyIpRanges=true failed to create ", off); } @@ -154,7 +154,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithoutSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, false, false, null, false, null, true, false, false, false, null, null, false, null); + false, null, false, null, false, false, null, false, null, true, false, false, false, null,null, null, false, null); assertNull("Shared network offering with specifyIpRanges=false was created", off); } @@ -167,7 +167,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, null, null, false, null); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, null, null, null, false, null); assertNotNull("Isolated network offering with specifyIpRanges=false failed to create ", off); } @@ -180,7 +180,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, null, null, false, null); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, null,null, null, false, null); assertNotNull("Isolated network offering with specifyVlan=true wasn't created", off); } @@ -193,7 +193,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, null, null, false, null); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, null,null, null, false, null); assertNull("Isolated network offering with specifyIpRanges=true and source nat service enabled, was created", off); } @@ -204,7 +204,7 @@ public class CreateNetworkOfferingTest extends TestCase { Set vrProvider = new HashSet(); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, null, null, false, null); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, null,null, null, false, null); assertNotNull("Isolated network offering with specifyIpRanges=true and with no sourceNatService, failed to create", off); } @@ -222,7 +222,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.Lb, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, false, null); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null, false, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc provider ", off); } @@ -242,7 +242,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.Lb, lbProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, false, null); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null, false, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off); } diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 6a98532b530..59e32a62055 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -876,6 +876,7 @@ "label.forceencap": "Force UDP encapsulation of ESP packets", "label.forgedtransmits": "Forged transmits", "label.format": "Format", +"label.fornsx": "NSX", "label.free": "Free", "label.french.azerty.keyboard": "French AZERTY keyboard", "label.friday": "Friday", @@ -1289,6 +1290,7 @@ "label.minorsequence": "Minor Sequence", "label.minsize": "Minimum size", "label.minute.past.hour": "minute(s) past the hour", +"label.mode": "Mode", "label.monday": "Monday", "label.monitor": "Monitor", "label.monitor.expected.code": "Expected HTTP Status Code", @@ -1383,6 +1385,8 @@ "label.not.found": "Not found", "label.not.suitable": "Not suitable", "label.notifications": "Notifications", +"label.nsx": "NSX", +"label.nsx.mode": "NSX Mode", "label.nsx.provider": "NSX Provider", "label.nsx.provider.name": "NSX provider name", "label.nsx.provider.hostname": "NSX provider hostname", @@ -1561,6 +1565,7 @@ "label.public.ips": "Public IP addresses", "label.public.lb": "Public LB", "label.public.traffic": "Public traffic", +"label.public.traffic.nsx": "NSX Public traffic", "label.publicinterface": "Public interface", "label.publicip": "IP address", "label.publicipid": "IP address ID", diff --git a/ui/src/components/CheckBoxSelectPair.vue b/ui/src/components/CheckBoxSelectPair.vue index de6aed473cb..4fba1da2556 100644 --- a/ui/src/components/CheckBoxSelectPair.vue +++ b/ui/src/components/CheckBoxSelectPair.vue @@ -21,6 +21,7 @@ {{ checkBoxLabel }} @@ -30,7 +31,8 @@ v-if="reversed !== checked" :label="selectLabel">
- {{ service.name }} : {{ service.provider[0].name }} + {{ service.name }} : {{ service.provider?.[0]?.name }}
diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js index c44de61fb79..df4e264276b 100644 --- a/ui/src/config/section/offering.js +++ b/ui/src/config/section/offering.js @@ -262,7 +262,7 @@ export default { docHelp: 'adminguide/networking.html#network-offerings', permission: ['listNetworkOfferings'], columns: ['name', 'state', 'guestiptype', 'traffictype', 'networkrate', 'domain', 'zone', 'order'], - details: ['name', 'id', 'displaytext', 'guestiptype', 'traffictype', 'internetprotocol', 'networkrate', 'ispersistent', 'egressdefaultpolicy', 'availability', 'conservemode', 'specifyvlan', 'specifyipranges', 'supportspublicaccess', 'supportsstrechedl2subnet', 'service', 'tags', 'domain', 'zone'], + details: ['name', 'id', 'displaytext', 'guestiptype', 'traffictype', 'internetprotocol', 'networkrate', 'ispersistent', 'egressdefaultpolicy', 'availability', 'conservemode', 'specifyvlan', 'specifyipranges', 'supportspublicaccess', 'supportsstrechedl2subnet', 'forvpc', 'fornsx', 'nsxmode', 'service', 'tags', 'domain', 'zone'], resourceType: 'NetworkOffering', tabs: [ { @@ -355,7 +355,7 @@ export default { permission: ['listVPCOfferings'], resourceType: 'VpcOffering', columns: ['name', 'state', 'displaytext', 'domain', 'zone', 'order'], - details: ['name', 'id', 'displaytext', 'internetprotocol', 'distributedvpcrouter', 'tags', 'service', 'domain', 'zone', 'created'], + details: ['name', 'id', 'displaytext', 'internetprotocol', 'distributedvpcrouter', 'tags', 'service', 'fornsx', 'nsxmode', 'domain', 'zone', 'created'], related: [{ name: 'vpc', title: 'label.vpc', diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue index 17359e4e0c0..5af0c000165 100644 --- a/ui/src/views/offering/AddNetworkOffering.vue +++ b/ui/src/views/offering/AddNetworkOffering.vue @@ -41,7 +41,7 @@ v-model:value="form.displaytext" :placeholder="apiParams.displaytext.description"/> - + @@ -60,10 +60,10 @@ {{ $t('label.isolated') }} - + {{ $t('label.l2') }} - + {{ $t('label.shared') }} @@ -93,7 +93,7 @@ - +