diff --git a/api/src/main/java/com/cloud/agent/api/to/NicTO.java b/api/src/main/java/com/cloud/agent/api/to/NicTO.java index 3a616170d7e..573363c04fb 100644 --- a/api/src/main/java/com/cloud/agent/api/to/NicTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/NicTO.java @@ -32,6 +32,9 @@ public class NicTO extends NetworkTO { Map details; boolean dpdkEnabled; Integer mtu; + Long networkId; + + String networkSegmentName; public NicTO() { super(); @@ -127,4 +130,20 @@ public class NicTO extends NetworkTO { public void setMtu(Integer mtu) { this.mtu = mtu; } + + public Long getNetworkId() { + return networkId; + } + + public void setNetworkId(Long networkId) { + this.networkId = networkId; + } + + public String getNetworkSegmentName() { + return networkSegmentName; + } + + public void setNetworkSegmentName(String networkSegmentName) { + this.networkSegmentName = networkSegmentName; + } } diff --git a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java index db6cba77548..b4f4619be9a 100644 --- a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java @@ -82,6 +82,7 @@ public class VirtualMachineTO { Map guestOsDetails = new HashMap(); Map extraConfig = new HashMap<>(); + Map networkIdToNetworkNameMap = new HashMap<>(); DeployAsIsInfoTO deployAsIsInfo; public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader, @@ -392,6 +393,14 @@ public class VirtualMachineTO { return extraConfig; } + public Map getNetworkIdToNetworkNameMap() { + return networkIdToNetworkNameMap; + } + + public void setNetworkIdToNetworkNameMap(Map networkIdToNetworkNameMap) { + this.networkIdToNetworkNameMap = networkIdToNetworkNameMap; + } + public String getBootType() { return bootType; } diff --git a/api/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelper.java b/api/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelper.java index e445e50f82c..e160227749d 100644 --- a/api/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelper.java +++ b/api/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelper.java @@ -22,4 +22,5 @@ import org.apache.cloudstack.acl.ControlledEntity; public interface KubernetesClusterHelper extends Adapter { ControlledEntity findByUuid(String uuid); + ControlledEntity findByVmId(long vmId); } diff --git a/api/src/main/java/com/cloud/network/IpAddress.java b/api/src/main/java/com/cloud/network/IpAddress.java index cf2e2f82db9..ae1af450577 100644 --- a/api/src/main/java/com/cloud/network/IpAddress.java +++ b/api/src/main/java/com/cloud/network/IpAddress.java @@ -97,4 +97,6 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity, void setRuleState(State ruleState); + boolean isForSystemVms(); + } diff --git a/api/src/main/java/com/cloud/network/Network.java b/api/src/main/java/com/cloud/network/Network.java index 458169c80aa..3b13ef7bd9c 100644 --- a/api/src/main/java/com/cloud/network/Network.java +++ b/api/src/main/java/com/cloud/network/Network.java @@ -205,6 +205,8 @@ public interface Network extends ControlledEntity, StateObject, I //Add Tungsten Fabric provider public static final Provider Tungsten = new Provider("Tungsten", false); + public static final Provider Nsx = new Provider("Nsx", false); + private final String name; private final boolean isExternal; @@ -427,6 +429,8 @@ public interface Network extends ControlledEntity, StateObject, I long getDataCenterId(); + long getAccountId(); + long getNetworkOfferingId(); @Override diff --git a/api/src/main/java/com/cloud/network/NetworkService.java b/api/src/main/java/com/cloud/network/NetworkService.java index 82d229da459..51799e25cda 100644 --- a/api/src/main/java/com/cloud/network/NetworkService.java +++ b/api/src/main/java/com/cloud/network/NetworkService.java @@ -19,6 +19,7 @@ package com.cloud.network; import java.util.List; import java.util.Map; +import com.cloud.dc.DataCenter; import org.apache.cloudstack.api.command.admin.address.ReleasePodIpCmdByAdmin; import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; @@ -55,6 +56,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.Nic; import com.cloud.vm.NicSecondaryIp; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; /** * The NetworkService interface is the "public" api to entities that make requests to the orchestration engine @@ -87,6 +89,8 @@ public interface NetworkService { IpAddress reserveIpAddress(Account account, Boolean displayIp, Long ipAddressId) throws ResourceAllocationException; + IpAddress reserveIpAddressWithVlanDetail(Account account, DataCenter zone, Boolean displayIp, String vlanDetailKey) throws ResourceAllocationException; + boolean releaseReservedIpAddress(long ipAddressId) throws InsufficientAddressCapacityException; boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException; @@ -254,4 +258,9 @@ public interface NetworkService { PublicIpQuarantine updatePublicIpAddressInQuarantine(UpdateQuarantinedIpCmd cmd); void removePublicIpAddressFromQuarantine(RemoveQuarantinedIpCmd cmd); + + InternalLoadBalancerElementService getInternalLoadBalancerElementByType(VirtualRouterProvider.Type type); + InternalLoadBalancerElementService getInternalLoadBalancerElementByNetworkServiceProviderId(long networkProviderId); + InternalLoadBalancerElementService getInternalLoadBalancerElementById(long providerId); + List getInternalLoadBalancerElements(); } diff --git a/api/src/main/java/com/cloud/network/Networks.java b/api/src/main/java/com/cloud/network/Networks.java index aeed5d4aec6..dfa0ddb84ca 100644 --- a/api/src/main/java/com/cloud/network/Networks.java +++ b/api/src/main/java/com/cloud/network/Networks.java @@ -128,7 +128,8 @@ public class Networks { }, UnDecided(null, null), OpenDaylight("opendaylight", String.class), - TUNGSTEN("tf", String.class); + TUNGSTEN("tf", String.class), + NSX("nsx", String.class); private final String scheme; private final Class type; diff --git a/api/src/main/java/com/cloud/network/VirtualRouterProvider.java b/api/src/main/java/com/cloud/network/VirtualRouterProvider.java index aca526b1832..98410ca09f8 100644 --- a/api/src/main/java/com/cloud/network/VirtualRouterProvider.java +++ b/api/src/main/java/com/cloud/network/VirtualRouterProvider.java @@ -21,7 +21,7 @@ import org.apache.cloudstack.api.InternalIdentity; public interface VirtualRouterProvider extends InternalIdentity, Identity { public enum Type { - VirtualRouter, ElasticLoadBalancerVm, VPCVirtualRouter, InternalLbVm, NetScalerVm + VirtualRouter, ElasticLoadBalancerVm, VPCVirtualRouter, InternalLbVm, NetScalerVm, Nsx } public Type getType(); diff --git a/api/src/main/java/com/cloud/network/element/NetworkACLServiceProvider.java b/api/src/main/java/com/cloud/network/element/NetworkACLServiceProvider.java index 8c3243c99f4..852a650cfcd 100644 --- a/api/src/main/java/com/cloud/network/element/NetworkACLServiceProvider.java +++ b/api/src/main/java/com/cloud/network/element/NetworkACLServiceProvider.java @@ -21,6 +21,7 @@ import java.util.List; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.Vpc; public interface NetworkACLServiceProvider extends NetworkElement { @@ -32,4 +33,6 @@ public interface NetworkACLServiceProvider extends NetworkElement { */ boolean applyNetworkACLs(Network config, List rules) throws ResourceUnavailableException; + boolean reorderAclRules(Vpc vpc, List networks, List networkACLItems); + } 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 52f654007f2..cbadbb18a8f 100644 --- a/api/src/main/java/com/cloud/network/guru/NetworkGuru.java +++ b/api/src/main/java/com/cloud/network/guru/NetworkGuru.java @@ -79,20 +79,24 @@ public interface NetworkGuru extends Adapter { * be used to make determination can be isolation methods, services * provided on the guest network and the service provider that's on the * guest network. - * + *

* If a network is already fully substantiated with the necessary resources * during this design phase, then the state should be set to Setup. If * the resources are not allocated at this point, the state should be set * to Allocated. * - * @param offering network offering that contains the package of services - * the end user intends to use on that network. - * @param plan where is this network being deployed. + * @param offering network offering that contains the package of services + * the end user intends to use on that network. + * @param plan where is this network being deployed. * @param userSpecified user specified parameters for this network. - * @param owner owner of this network. + * @param name + * @param vpcId + * @param owner owner of this network. * @return Network */ - Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner); + 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, diff --git a/api/src/main/java/com/cloud/network/nsx/NsxProvider.java b/api/src/main/java/com/cloud/network/nsx/NsxProvider.java new file mode 100644 index 00000000000..19cb3b4b939 --- /dev/null +++ b/api/src/main/java/com/cloud/network/nsx/NsxProvider.java @@ -0,0 +1,34 @@ +// 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 com.cloud.network.nsx; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface NsxProvider extends InternalIdentity, Identity { + String getHostname(); + + String getPort(); + String getProviderName(); + String getUsername(); + long getZoneId(); + + String getTier0Gateway(); + String getEdgeCluster(); + + String getTransportZone(); +} diff --git a/api/src/main/java/com/cloud/network/nsx/NsxService.java b/api/src/main/java/com/cloud/network/nsx/NsxService.java new file mode 100644 index 00000000000..79ad9547c73 --- /dev/null +++ b/api/src/main/java/com/cloud/network/nsx/NsxService.java @@ -0,0 +1,26 @@ +// 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 com.cloud.network.nsx; + +import com.cloud.network.IpAddress; +import com.cloud.network.vpc.Vpc; + +public interface NsxService { + + boolean createVpcNetwork(Long zoneId, long accountId, long domainId, Long vpcId, String vpcName, boolean sourceNatEnabled); + boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address); +} 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 b4df8e38dba..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,6 +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_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"; /** * @@ -53,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 207880ea28c..cf01fbf30e2 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,6 +57,11 @@ 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_NAT_NSX_OFFERING_FOR_VPC = "DefaultNATNSXNetworkOfferingForVpc"; + public static final String DEFAULT_NAT_NSX_OFFERING_FOR_VPC_WITH_ILB = "DefaultNATNSXNetworkOfferingForVpcWithInternalLB"; + public static final String DEFAULT_ROUTED_NSX_OFFERING_FOR_VPC = "DefaultRoutedNSXNetworkOfferingForVpc"; + public static final String DEFAULT_NAT_NSX_OFFERING = "DefaultNATNSXNetworkOffering"; + public static final String DEFAULT_ROUTED_NSX_OFFERING = "DefaultRoutedNSXNetworkOffering"; public final static String QuickCloudNoServices = "QuickCloudNoServices"; public final static String DefaultIsolatedNetworkOfferingWithSourceNatService = "DefaultIsolatedNetworkOfferingWithSourceNatService"; public final static String OvsIsolatedNetworkOfferingWithSourceNatService = "OvsIsolatedNetworkOfferingWithSourceNatService"; @@ -90,6 +100,10 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, boolean isForTungsten(); + 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 416072f1210..f10769d7319 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -303,6 +303,8 @@ public class ApiConstants { public static final String MIGRATIONS = "migrations"; public static final String MEMORY = "memory"; public static final String MODE = "mode"; + public static final String NSX_MODE = "nsxmode"; + public static final String NSX_ENABLED = "isnsxenabled"; public static final String NAME = "name"; public static final String METHOD_NAME = "methodname"; public static final String NETWORK_DOMAIN = "networkdomain"; @@ -704,6 +706,12 @@ public class ApiConstants { public static final String VSWITCH_TYPE_PUBLIC_TRAFFIC = "publicvswitchtype"; public static final String VSWITCH_NAME_GUEST_TRAFFIC = "guestvswitchname"; public static final String VSWITCH_NAME_PUBLIC_TRAFFIC = "publicvswitchname"; + + // NSX + public static final String EDGE_CLUSTER = "edgecluster"; + public static final String TIER0_GATEWAY = "tier0gateway"; + + public static final String TRANSPORT_ZONE = "transportzone"; // Tungsten-Fabric public static final String TUNGSTEN_VIRTUAL_ROUTER_UUID = "tungstenvirtualrouteruuid"; public static final String TUNGSTEN_PROVIDER_HOSTNAME = "tungstenproviderhostname"; @@ -825,6 +833,9 @@ public class ApiConstants { public static final String FORCE_ENCAP = "forceencap"; public static final String SPLIT_CONNECTIONS = "splitconnections"; public static final String FOR_VPC = "forvpc"; + public static final String FOR_NSX = "fornsx"; + public static final String NSX_SUPPORT_LB = "nsxsupportlb"; + public static final String NSX_SUPPORTS_INTERNAL_LB = "nsxsupportsinternallb"; public static final String FOR_TUNGSTEN = "fortungsten"; public static final String SHRINK_OK = "shrinkok"; public static final String NICIRA_NVP_DEVICE_ID = "nvpdeviceid"; @@ -834,6 +845,11 @@ public class ApiConstants { public static final String NICIRA_NVP_L2_GATEWAYSERVICE_UUID = "l2gatewayserviceuuid"; public static final String NSX_LOGICAL_SWITCH = "nsxlogicalswitch"; public static final String NSX_LOGICAL_SWITCH_PORT = "nsxlogicalswitchport"; + public static final String NSX_PROVIDER_UUID = "nsxprovideruuid"; + public static final String NSX_PROVIDER_HOSTNAME = "nsxproviderhostname"; + + public static final String NSX_PROVIDER_PORT = "nsxproviderport"; + public static final String NSX_CONTROLLER_ID = "nsxcontrollerid"; public static final String S3_ACCESS_KEY = "accesskey"; public static final String S3_SECRET_KEY = "secretkey"; public static final String S3_END_POINT = "endpoint"; @@ -958,6 +974,7 @@ public class ApiConstants { public static final String SUPPORTS_REGION_LEVEL_VPC = "supportsregionLevelvpc"; public static final String SUPPORTS_STRECHED_L2_SUBNET = "supportsstrechedl2subnet"; public static final String SUPPORTS_PUBLIC_ACCESS = "supportspublicaccess"; + public static final String SUPPORTS_INTERNAL_LB = "supportsinternallb"; public static final String SUPPORTS_VM_AUTOSCALING = "supportsvmautoscaling"; public static final String REGION_LEVEL_VPC = "regionlevelvpc"; public static final String STRECHED_L2_SUBNET = "strechedl2subnet"; @@ -1076,14 +1093,13 @@ public class ApiConstants { public static final String SOURCE_NAT_IP = "sourcenatipaddress"; public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid"; public static final String HAS_RULES = "hasrules"; + public static final String NSX_DETAIL_KEY = "forNsx"; public static final String DISK_PATH = "diskpath"; public static final String IMPORT_SOURCE = "importsource"; public static final String TEMP_PATH = "temppath"; public static final String OBJECT_STORAGE = "objectstore"; - public static final String HEURISTIC_RULE = "heuristicrule"; public static final String HEURISTIC_TYPE_VALID_OPTIONS = "Valid options are: ISO, SNAPSHOT, TEMPLATE and VOLUME."; - public static final String MANAGEMENT = "management"; public static final String IS_VNF = "isvnf"; public static final String VNF_NICS = "vnfnics"; diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java index 323fd4e6f64..b206cd011c1 100644 --- a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java @@ -38,7 +38,6 @@ import org.apache.cloudstack.affinity.AffinityGroupService; import org.apache.cloudstack.alert.AlertService; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService; import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; import org.apache.cloudstack.query.QueryService; @@ -201,8 +200,6 @@ public abstract class BaseCmd { @Inject public AffinityGroupService _affinityGroupService; @Inject - public InternalLoadBalancerElementService _internalLbElementSvc; - @Inject public InternalLoadBalancerVMService _internalLbSvc; @Inject public NetworkModel _ntwkModel; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java index 18dfc87397a..c94d326ee62 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java @@ -17,11 +17,6 @@ package org.apache.cloudstack.api.command.admin.internallb; -import java.util.List; - -import javax.inject.Inject; - - import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -47,9 +42,6 @@ import com.cloud.user.Account; responseHasSensitiveInfo = false) public class ConfigureInternalLoadBalancerElementCmd extends BaseAsyncCmd { - @Inject - private List _service; - ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @@ -98,7 +90,8 @@ public class ConfigureInternalLoadBalancerElementCmd extends BaseAsyncCmd { @Override public void execute() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { CallContext.current().setEventDetails("Internal load balancer element: " + id); - VirtualRouterProvider result = _service.get(0).configureInternalLoadBalancerElement(getId(), getEnabled()); + InternalLoadBalancerElementService service = _networkService.getInternalLoadBalancerElementById(id); + VirtualRouterProvider result = service.configureInternalLoadBalancerElement(getId(), getEnabled()); if (result != null) { InternalLoadBalancerElementResponse routerResponse = _responseGenerator.createInternalLbElementResponse(result); routerResponse.setResponseName(getCommandName()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java index 971f097fca5..924287b673b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java @@ -16,11 +16,6 @@ // under the License. package org.apache.cloudstack.api.command.admin.internallb; -import java.util.List; - -import javax.inject.Inject; - - import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -45,9 +40,6 @@ import com.cloud.user.Account; responseHasSensitiveInfo = false) public class CreateInternalLoadBalancerElementCmd extends BaseAsyncCreateCmd { - @Inject - private List _service; - ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @@ -83,7 +75,8 @@ public class CreateInternalLoadBalancerElementCmd extends BaseAsyncCreateCmd { @Override public void execute() { CallContext.current().setEventDetails("Virtual router element Id: " + getEntityId()); - VirtualRouterProvider result = _service.get(0).getInternalLoadBalancerElement(getEntityId()); + InternalLoadBalancerElementService service = _networkService.getInternalLoadBalancerElementByNetworkServiceProviderId(getNspId()); + VirtualRouterProvider result = service.getInternalLoadBalancerElement(getEntityId()); if (result != null) { InternalLoadBalancerElementResponse response = _responseGenerator.createInternalLbElementResponse(result); response.setResponseName(getCommandName()); @@ -95,7 +88,8 @@ public class CreateInternalLoadBalancerElementCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException { - VirtualRouterProvider result = _service.get(0).addInternalLoadBalancerElement(getNspId()); + InternalLoadBalancerElementService service = _networkService.getInternalLoadBalancerElementByNetworkServiceProviderId(getNspId()); + VirtualRouterProvider result = service.addInternalLoadBalancerElement(getNspId()); if (result != null) { setEntityId(result.getId()); setEntityUuid(result.getUuid()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java index 6c2fadee737..b17cc22e746 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java @@ -17,11 +17,9 @@ package org.apache.cloudstack.api.command.admin.internallb; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import javax.inject.Inject; - - import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListCmd; @@ -46,9 +44,6 @@ import com.cloud.network.VirtualRouterProvider; responseHasSensitiveInfo = false) public class ListInternalLoadBalancerElementsCmd extends BaseListCmd { - @Inject - private InternalLoadBalancerElementService _service; - ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @@ -86,12 +81,21 @@ public class ListInternalLoadBalancerElementsCmd extends BaseListCmd { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { - List providers = _service.searchForInternalLoadBalancerElements(getId(), getNspId(), getEnabled()); + List services; + if (id == null && nspId == null) { + services = _networkService.getInternalLoadBalancerElements(); + } else { + InternalLoadBalancerElementService elementService = id != null ? _networkService.getInternalLoadBalancerElementById(id) : _networkService.getInternalLoadBalancerElementByNetworkServiceProviderId(nspId); + services = Collections.singletonList(elementService); + } ListResponse response = new ListResponse(); List providerResponses = new ArrayList(); - for (VirtualRouterProvider provider : providers) { - InternalLoadBalancerElementResponse providerResponse = _responseGenerator.createInternalLbElementResponse(provider); - providerResponses.add(providerResponse); + for (InternalLoadBalancerElementService service : services) { + List providers = service.searchForInternalLoadBalancerElements(getId(), getNspId(), getEnabled()); + for (VirtualRouterProvider provider : providers) { + InternalLoadBalancerElementResponse providerResponse = _responseGenerator.createInternalLbElementResponse(provider); + providerResponses.add(providerResponse); + } } response.setResponses(providerResponses); response.setResponseName(getCommandName()); 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 f2b1a18831a..9117bcfc193 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,10 +24,14 @@ 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; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.cloudstack.api.APICommand; @@ -46,6 +50,16 @@ 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; +import static com.cloud.network.Network.Service.Firewall; + @APICommand(name = "createNetworkOffering", description = "Creates a network offering.", responseObject = NetworkOfferingResponse.class, since = "3.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class CreateNetworkOfferingCmd extends BaseCmd { @@ -126,6 +140,30 @@ 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.NSX_SUPPORT_LB, + type = CommandType.BOOLEAN, + description = "true if network offering for NSX network offering supports Load balancer service.", + since = "4.20.0") + private Boolean nsxSupportsLbService; + + @Parameter(name = ApiConstants.NSX_SUPPORTS_INTERNAL_LB, + type = CommandType.BOOLEAN, + description = "true if network offering for NSX network offering supports Internal Load balancer service.", + since = "4.20.0") + private Boolean nsxSupportsInternalLbService; + @Parameter(name = ApiConstants.FOR_TUNGSTEN, type = CommandType.BOOLEAN, description = "true if network offering is meant to be used for Tungsten-Fabric, false otherwise.") @@ -210,7 +248,27 @@ public class CreateNetworkOfferingCmd extends BaseCmd { } public List getSupportedServices() { - return supportedServices == null ? new ArrayList() : supportedServices; + if (!isForNsx()) { + 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() + )); + if (getNsxSupportsLbService()) { + services.add(Lb.getName()); + } + if (Boolean.TRUE.equals(forVpc)) { + services.add(NetworkACL.getName()); + } else { + services.add(Firewall.getName()); + } + return services; + } } public String getGuestIpType() { @@ -240,6 +298,22 @@ public class CreateNetworkOfferingCmd extends BaseCmd { return forVpc; } + public boolean isForNsx() { + return BooleanUtils.isTrue(forNsx); + } + + public String getNsxMode() { + return nsxMode; + } + + public boolean getNsxSupportsLbService() { + return BooleanUtils.isTrue(nsxSupportsLbService); + } + + public boolean getNsxSupportsInternalLbService() { + return BooleanUtils.isTrue(nsxSupportsInternalLbService); + } + public Boolean getForTungsten() { return forTungsten; } @@ -260,9 +334,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()) { @@ -278,11 +351,37 @@ 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 = new ArrayList<>(List.of("Vpn", "SecurityGroup", "Connectivity", + "Gateway", "BaremetalPxeService")); + List routerSupported = List.of("Dhcp", "Dns", "UserData"); + List allServices = Service.listAllServices().stream().map(Service::getName).collect(Collectors.toList()); + if (routerProvider.equals(VirtualRouterProvider.Type.VPCVirtualRouter.name())) { + unsupportedServices.add("Firewall"); + } else { + unsupportedServices.add("NetworkACL"); + } + 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())); + if (!getNsxSupportsLbService()) { + serviceProviderMap.remove(Lb.getName()); + } + } + } + public Map getServiceCapabilities(Service service) { Map capabilityMap = null; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java index cceadea8532..c0ba99a8233 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java @@ -39,6 +39,8 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.Account; +import java.util.Objects; + @APICommand(name = "createVlanIpRange", description = "Creates a VLAN IP range.", responseObject = VlanIpRangeResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class CreateVlanIpRangeCmd extends BaseCmd { @@ -112,6 +114,9 @@ public class CreateVlanIpRangeCmd extends BaseCmd { @Parameter(name = ApiConstants.FOR_SYSTEM_VMS, type = CommandType.BOOLEAN, description = "true if IP range is set to system vms, false if not") private Boolean forSystemVms; + @Parameter(name = ApiConstants.FOR_NSX, type = CommandType.BOOLEAN, description = "true if the IP range is used for NSX resource", since = "4.20.0") + private boolean forNsx; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -152,8 +157,12 @@ public class CreateVlanIpRangeCmd extends BaseCmd { return startIp; } + public boolean isForNsx() { + return !Objects.isNull(forNsx) && forNsx; + } + public String getVlan() { - if (vlan == null || vlan.isEmpty()) { + if ((vlan == null || vlan.isEmpty()) && !isForNsx()) { vlan = "untagged"; } return vlan; 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 382c081e01e..dd5c815238e 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 @@ -24,10 +24,15 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; 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; +import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.cloudstack.api.APICommand; @@ -44,6 +49,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 { @@ -60,7 +74,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; @@ -99,6 +112,24 @@ 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.NSX_SUPPORT_LB, + type = CommandType.BOOLEAN, + description = "true if network offering for NSX VPC offering supports Load balancer service.", + since = "4.20.0") + private Boolean nsxSupportsLbService; + @Parameter(name = ApiConstants.ENABLE, type = CommandType.BOOLEAN, description = "set to true if the offering is to be enabled during creation. Default is false", @@ -118,13 +149,41 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { } public List getSupportedServices() { + if (!isForNsx() && CollectionUtils.isEmpty(supportedServices)) { + throw new InvalidParameterValueException("Supported services needs to be provided"); + } + if (isForNsx()) { + supportedServices = new ArrayList<>(List.of( + Dhcp.getName(), + Dns.getName(), + StaticNat.getName(), + SourceNat.getName(), + NetworkACL.getName(), + PortForwarding.getName(), + UserData.getName() + )); + if (getNsxSupportsLbService()) { + supportedServices.add(Lb.getName()); + } + } return supportedServices; } + public boolean isForNsx() { + return BooleanUtils.isTrue(forNsx); + } + + public String getNsxMode() { + return nsxMode; + } + + public boolean getNsxSupportsLbService() { + return org.apache.commons.lang3.BooleanUtils.isTrue(nsxSupportsLbService); + } + 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()) { @@ -132,7 +191,7 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { if (logger.isTraceEnabled()) { 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; @@ -144,11 +203,31 @@ 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())); + } + if (!getNsxSupportsLbService()) { + serviceProviderMap.remove(Lb.getName()); + } + } + public Map> getServiceCapabilityList() { return serviceCapabilityList; } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java index 5c1c61130ba..5760ca3ba1c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.api.command.user.address; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang.BooleanUtils; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; @@ -104,6 +105,9 @@ public class ListPublicIpAddressesCmd extends BaseListRetrieveOnlyResourceCountC @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "list resources by display flag; only ROOT admin is eligible to pass this parameter", since = "4.4", authorized = {RoleType.Admin}) private Boolean display; + @Parameter(name = ApiConstants.FOR_SYSTEM_VMS, type = CommandType.BOOLEAN, description = "true if range is dedicated for system VMs", since = "4.20.0") + private Boolean forSystemVMs; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -175,6 +179,10 @@ public class ListPublicIpAddressesCmd extends BaseListRetrieveOnlyResourceCountC return state; } + public boolean getForSystemVMs() { + return BooleanUtils.isTrue(forSystemVMs); + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java index e2bf6ef5c60..8a9bf7789dd 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java @@ -167,6 +167,10 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co @Param(description="whether the ip address has Firewall/PortForwarding/LoadBalancing rules defined") private boolean hasRules; + @SerializedName(ApiConstants.FOR_SYSTEM_VMS) + @Param(description="true if range is dedicated for System VMs") + private boolean forSystemVms; + public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } @@ -316,4 +320,8 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co public void setHasRules(final boolean hasRules) { this.hasRules = hasRules; } + + public void setForSystemVms(boolean forSystemVms) { + this.forSystemVms = forSystemVms; + } } 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 b92725d883e..b73163a5d05 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 @@ -99,10 +99,18 @@ public class NetworkOfferingResponse extends BaseResponseWithAnnotations { @Param(description = "true if network offering can be used by VPC networks only") private Boolean forVpc; + @SerializedName(ApiConstants.FOR_NSX) + @Param(description = "true if network offering can be used by NSX networks only") + private Boolean forNsx; + @SerializedName(ApiConstants.FOR_TUNGSTEN) @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; @@ -127,6 +135,10 @@ public class NetworkOfferingResponse extends BaseResponseWithAnnotations { @Param(description = "true if network offering supports public access for guest networks", since = "4.10.0") private Boolean supportsPublicAccess; + @SerializedName(ApiConstants.SUPPORTS_INTERNAL_LB) + @Param(description = "true if network offering supports public access for guest networks", since = "4.20.0") + private Boolean supportsInternalLb; + @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; @@ -215,10 +227,18 @@ public class NetworkOfferingResponse extends BaseResponseWithAnnotations { this.forVpc = forVpc; } + public void setForNsx(Boolean forNsx) { + this.forNsx = forNsx; + } + public void setForTungsten(Boolean forTungsten) { this.forTungsten = forTungsten; } + public void setNsxMode(String nsxMode) { + this.nsxMode = nsxMode; + } + public void setIsPersistent(Boolean isPersistent) { this.isPersistent = isPersistent; } @@ -243,6 +263,10 @@ public class NetworkOfferingResponse extends BaseResponseWithAnnotations { this.supportsPublicAccess = supportsPublicAccess; } + public void setSupportsInternalLb(Boolean supportsInternalLb) { + this.supportsInternalLb = supportsInternalLb; + } + public String getDomainId() { return domainId; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java index a22e2eb7024..aac6dd3c577 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java @@ -123,6 +123,10 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit @Param(description = "indicates whether VLAN IP range is dedicated to system vms or not") private Boolean forSystemVms; + @SerializedName(ApiConstants.FOR_NSX) + @Param(description = "indicates whether IP range is dedicated to NSX resources or not") + private Boolean forNsx; + public void setId(String id) { this.id = id; } @@ -235,4 +239,8 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit public void setIp6Cidr(String ip6Cidr) { this.ip6Cidr = ip6Cidr; } + + public void setForNsx(Boolean forNsx) { + this.forNsx = forNsx; + } } 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/main/java/org/apache/cloudstack/api/response/ZoneResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java index 4e8e665836c..a898cd9d577 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java @@ -145,6 +145,10 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso @Param(description = "the type of the zone - core or edge", since = "4.18.0") String type; + @SerializedName(ApiConstants.NSX_ENABLED) + @Param(description = "true, if zone is NSX enabled", since = "4.20.0") + private boolean nsxEnabled = false; + public ZoneResponse() { tags = new LinkedHashSet(); } @@ -368,4 +372,8 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso public String getType() { return type; } + + public void setNsxEnabled(boolean nsxEnabled) { + this.nsxEnabled = nsxEnabled; + } } diff --git a/api/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java b/api/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java index 76706a4cfc9..1fff54f5f8f 100644 --- a/api/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java +++ b/api/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java @@ -52,4 +52,6 @@ public interface InternalLoadBalancerElementService extends PluggableService { * @return */ List searchForInternalLoadBalancerElements(Long id, Long ntwkSvsProviderId, Boolean enabled); + + VirtualRouterProvider.Type getProviderType(); } diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateNetworkOfferingCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateNetworkOfferingCmdTest.java index 8b95456a84c..ef10ebff467 100644 --- a/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateNetworkOfferingCmdTest.java +++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateNetworkOfferingCmdTest.java @@ -23,14 +23,16 @@ import org.junit.Test; import org.mockito.InjectMocks; import org.springframework.test.util.ReflectionTestUtils; + public class CreateNetworkOfferingCmdTest { @InjectMocks private CreateNetworkOfferingCmd createNetworkOfferingCmd = new CreateNetworkOfferingCmd(); + String netName = "network"; + @Test public void createVpcNtwkOffWithEmptyDisplayText() { - String netName = "network"; ReflectionTestUtils.setField(createNetworkOfferingCmd, "networkOfferingName", netName); Assert.assertEquals(createNetworkOfferingCmd.getDisplayText(), netName); } 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/client/pom.xml b/client/pom.xml index 91399097d64..9ff3f2ada39 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -296,6 +296,11 @@ cloud-plugin-network-tungsten ${project.version} + + org.apache.cloudstack + cloud-plugin-network-nsx + ${project.version} + org.apache.cloudstack cloud-plugin-network-elb diff --git a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java index e9781993239..06583f2d0d3 100644 --- a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java +++ b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java @@ -35,6 +35,7 @@ public class SetupGuestNetworkCommand extends NetworkElementCommand { String routerIpv6 = null; String routerIpv6Gateway = null; String routerIpv6Cidr = null; + boolean isVrGuestGateway = false; public NicTO getNic() { return nic; @@ -114,4 +115,12 @@ public class SetupGuestNetworkCommand extends NetworkElementCommand { public void setDefaultIp6Dns2(String defaultIp6Dns2) { this.defaultIp6Dns2 = defaultIp6Dns2; } + + public boolean isVrGuestGateway() { + return isVrGuestGateway; + } + + public void setVrGuestGateway(boolean vrGuestGateway) { + isVrGuestGateway = vrGuestGateway; + } } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java index aee1e779571..1a6824ceb7f 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java @@ -75,6 +75,7 @@ public class SetGuestNetworkConfigItem extends AbstractConfigItemFacade { guestNetwork.setRouterIp6(command.getRouterIpv6()); guestNetwork.setRouterIp6Gateway(command.getRouterIpv6Gateway()); guestNetwork.setRouterIp6Cidr(command.getRouterIpv6Cidr()); + guestNetwork.setVrGuestGateway(command.isVrGuestGateway()); return generateConfigItems(guestNetwork); } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java index bb5e443c2e8..a416b4bc5e4 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java @@ -37,6 +37,7 @@ public class GuestNetwork extends ConfigBase { private String routerIp6; private String routerIp6Gateway; private String routerIp6Cidr; + private boolean isVrGuestGateway; private Integer mtu; @@ -202,4 +203,12 @@ public class GuestNetwork extends ConfigBase { public Integer getMtu() { return mtu; } + + public boolean isVrGuestGateway() { + return isVrGuestGateway; + } + + public void setVrGuestGateway(boolean vrGuestGateway) { + isVrGuestGateway = vrGuestGateway; + } } diff --git a/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml b/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml index a36d1243155..49775fe41e1 100644 --- a/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml +++ b/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml @@ -350,4 +350,12 @@ + + + + + + + + diff --git a/core/src/main/resources/META-INF/cloudstack/network/spring-core-lifecycle-network-context-inheritable.xml b/core/src/main/resources/META-INF/cloudstack/network/spring-core-lifecycle-network-context-inheritable.xml index 8dbaf610581..2240d1f2606 100644 --- a/core/src/main/resources/META-INF/cloudstack/network/spring-core-lifecycle-network-context-inheritable.xml +++ b/core/src/main/resources/META-INF/cloudstack/network/spring-core-lifecycle-network-context-inheritable.xml @@ -103,4 +103,9 @@ + + + + + diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index 2005b70b439..110592161f9 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -105,6 +105,9 @@ public interface NetworkOrchestrationService { static final ConfigKey TUNGSTEN_ENABLED = new ConfigKey<>(Boolean.class, "tungsten.plugin.enable", "Advanced", "false", "Indicates whether to enable the Tungsten plugin", false, ConfigKey.Scope.Zone, null); + static final ConfigKey NSX_ENABLED = new ConfigKey<>(Boolean.class, "nsx.plugin.enable", "Advanced", "false", + "Indicates whether to enable the NSX plugin", false, ConfigKey.Scope.Zone, null); + List setupNetwork(Account owner, NetworkOffering offering, DeploymentPlan plan, String name, String displayText, boolean isDefault) throws ConcurrentOperationException; 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 5343fb632b5..bbddd8fd471 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 @@ -63,6 +63,9 @@ public interface ConfigurationManager { static final String VM_USERDATA_MAX_LENGTH_STRING = "vm.userdata.max.length"; static final ConfigKey VM_USERDATA_MAX_LENGTH = new ConfigKey<>("Advanced", Integer.class, VM_USERDATA_MAX_LENGTH_STRING, "32768", "Max length of vm userdata after base64 decoding. Default is 32768 and maximum is 1048576", true); + public static final ConfigKey AllowNonRFC1918CompliantIPs = new ConfigKey<>(Boolean.class, + "allow.non.rfc1918.compliant.ips", "Advanced", "false", + "Allows non-compliant RFC 1918 IPs for Shared, Isolated networks and VPCs", true, null); /** * @param offering @@ -97,7 +100,6 @@ public interface ConfigurationManager { // * @param volatileVm // * @param hostTag // * @param networkRate -// * TODO // * @param id // * @param useVirtualNetwork // * @param deploymentPlanner @@ -167,11 +169,9 @@ public interface ConfigurationManager { * @param zoneType * @param allocationState * @param networkDomain - * TODO * @param isSecurityGroupEnabled - * TODO - * @param ip6Dns1 TODO - * @param ip6Dns2 TODO + * @param ip6Dns1 + * @param ip6Dns2 * @return * @throws * @throws @@ -186,7 +186,7 @@ public interface ConfigurationManager { * * @param userId * @param vlanDbId - * @param caller TODO + * @param caller * @return success/failure */ boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId, Account caller); @@ -197,30 +197,25 @@ public interface ConfigurationManager { /** * Creates a new network offering + * * @param name * @param displayText * @param trafficType * @param tags * @param specifyVlan * @param networkRate - * TODO * @param serviceProviderMap - * TODO * @param isDefault - * TODO * @param type - * TODO * @param systemOnly - * TODO * @param serviceOfferingId - * @param conserveMode - * ; + * @param conserveMode ; * @param specifyIpRanges - * TODO - * @param isPersistent - * ; - * @param details TODO + * @param isPersistent ; + * @param details * @param forVpc + * @param forTungsten + * @param forNsx * @param domainIds * @param zoneIds * @return network offering object @@ -230,10 +225,10 @@ 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, 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) + String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr, boolean forNsx) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException; diff --git a/engine/components-api/src/main/java/com/cloud/network/addr/PublicIp.java b/engine/components-api/src/main/java/com/cloud/network/addr/PublicIp.java index d1153a291f8..d69a72a02c5 100644 --- a/engine/components-api/src/main/java/com/cloud/network/addr/PublicIp.java +++ b/engine/components-api/src/main/java/com/cloud/network/addr/PublicIp.java @@ -269,4 +269,11 @@ public class PublicIp implements PublicIpAddress { public void setRuleState(State ruleState) { _addr.setRuleState(ruleState); } + + @Override + public boolean isForSystemVms() { + return false; + } + + } diff --git a/engine/components-api/src/main/java/com/cloud/network/vpc/NetworkACLManager.java b/engine/components-api/src/main/java/com/cloud/network/vpc/NetworkACLManager.java index 4200ea8c601..de69b894183 100644 --- a/engine/components-api/src/main/java/com/cloud/network/vpc/NetworkACLManager.java +++ b/engine/components-api/src/main/java/com/cloud/network/vpc/NetworkACLManager.java @@ -19,6 +19,7 @@ package com.cloud.network.vpc; import java.util.List; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; import com.cloud.network.dao.NetworkVO; public interface NetworkACLManager { @@ -91,4 +92,6 @@ public interface NetworkACLManager { boolean revokeACLItemsForPrivateGw(PrivateGateway gateway) throws ResourceUnavailableException; boolean applyACLToPrivateGw(PrivateGateway gateway) throws ResourceUnavailableException; + + boolean reorderAclRules(VpcVO vpc, List networks, List networkACLItems); } 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 87399389271..e951444c4f1 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -36,6 +36,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; import java.util.TimeZone; import java.util.UUID; @@ -48,6 +49,11 @@ 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; import com.cloud.event.ActionEventUtils; import com.google.gson.Gson; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; @@ -385,6 +391,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac private DomainRouterJoinDao domainRouterJoinDao; @Inject private AnnotationDao annotationDao; + @Inject + private AccountDao accountDao; + @Inject + private VpcDao vpcDao; + @Inject + private DomainDao domainDao; VmWorkJobHandlerProxy _jobHandlerProxy = new VmWorkJobHandlerProxy(this); @@ -599,11 +611,18 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VirtualMachine.Type.ConsoleProxy.equals(vm.getType()); } - protected void advanceExpunge(VMInstanceVO vm) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException { + private boolean isVmDestroyed(VMInstanceVO vm) { if (vm == null || vm.getRemoved() != null) { if (logger.isDebugEnabled()) { logger.debug("Unable to find vm or vm is expunged: " + vm); } + return true; + } + return false; + } + + protected void advanceExpunge(VMInstanceVO vm) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException { + if (isVmDestroyed(vm)) { return; } @@ -674,28 +693,31 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac // send hypervisor-dependent commands before removing final List finalizeExpungeCommands = hvGuru.finalizeExpunge(vm); - if (CollectionUtils.isNotEmpty(finalizeExpungeCommands) || CollectionUtils.isNotEmpty(nicExpungeCommands)) { - if (hostId != null) { - final Commands cmds = new Commands(Command.OnError.Stop); - addAllExpungeCommandsFromList(finalizeExpungeCommands, cmds, vm); - addAllExpungeCommandsFromList(nicExpungeCommands, cmds, vm); - _agentMgr.send(hostId, cmds); - if (!cmds.isSuccessful()) { - for (final Answer answer : cmds.getAnswers()) { - if (!answer.getResult()) { - logger.warn("Failed to expunge vm due to: " + answer.getDetails()); - throw new CloudRuntimeException("Unable to expunge " + vm + " due to " + answer.getDetails()); - } - } - } - } - } + handleUnsuccessfulExpungeOperation(finalizeExpungeCommands, nicExpungeCommands, vm, hostId); if (logger.isDebugEnabled()) { logger.debug("Expunged " + vm); } } + private void handleUnsuccessfulExpungeOperation(List finalizeExpungeCommands, List nicExpungeCommands, + VMInstanceVO vm, Long hostId) throws OperationTimedoutException, AgentUnavailableException { + if (CollectionUtils.isNotEmpty(finalizeExpungeCommands) || CollectionUtils.isNotEmpty(nicExpungeCommands) && (hostId != null)) { + final Commands cmds = new Commands(Command.OnError.Stop); + addAllExpungeCommandsFromList(finalizeExpungeCommands, cmds, vm); + addAllExpungeCommandsFromList(nicExpungeCommands, cmds, vm); + _agentMgr.send(hostId, cmds); + if (!cmds.isSuccessful()) { + for (final Answer answer : cmds.getAnswers()) { + if (!answer.getResult()) { + logger.warn("Failed to expunge vm due to: " + answer.getDetails()); + throw new CloudRuntimeException(String.format("Unable to expunge %s due to %s", vm, answer.getDetails())); + } + } + } + } + } + protected void handleUnsuccessfulCommands(Commands cmds, VMInstanceVO vm) throws CloudRuntimeException { String cmdsStr = cmds.toString(); String vmToString = vm.toString(); @@ -1277,6 +1299,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac checkAndSetEnterSetupMode(vmTO, params); handlePath(vmTO.getDisks(), vm.getHypervisorType()); + setVmNetworkDetails(vm, vmTO); + Commands cmds = new Commands(Command.OnError.Stop); final Map sshAccessDetails = _networkMgr.getSystemVMAccessDetails(vm); @@ -1460,6 +1484,55 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } + public void setVmNetworkDetails(VMInstanceVO vm, VirtualMachineTO vmTO) { + Map networkToNetworkNameMap = new HashMap<>(); + if (VirtualMachine.Type.User.equals(vm.getType())) { + List userVmJoinVOs = userVmJoinDao.searchByIds(vm.getId()); + if (userVmJoinVOs != null && !userVmJoinVOs.isEmpty()) { + for (UserVmJoinVO userVmJoinVO : userVmJoinVOs) { + addToNetworkNameMap(userVmJoinVO.getNetworkId(), vm.getDataCenterId(), networkToNetworkNameMap); + } + vmTO.setNetworkIdToNetworkNameMap(networkToNetworkNameMap); + } + } else if (VirtualMachine.Type.DomainRouter.equals(vm.getType())) { + List routerJoinVO = domainRouterJoinDao.getRouterByIdAndTrafficType(vm.getId(), Networks.TrafficType.Guest); + for (DomainRouterJoinVO router : routerJoinVO) { + NetworkVO guestNetwork = _networkDao.findById(router.getNetworkId()); + if (guestNetwork.getVpcId() == null && guestNetwork.getBroadcastDomainType() == Networks.BroadcastDomainType.NSX) { + addToNetworkNameMap(router.getNetworkId(), vm.getDataCenterId(), networkToNetworkNameMap); + } + } + vmTO.setNetworkIdToNetworkNameMap(networkToNetworkNameMap); + } + } + + private void addToNetworkNameMap(long networkId, long dataCenterId, Map networkToNetworkNameMap) { + NetworkVO networkVO = _networkDao.findById(networkId); + Account acc = accountDao.findById(networkVO.getAccountId()); + Domain domain = domainDao.findById(networkVO.getDomainId()); + DataCenter zone = _dcDao.findById(dataCenterId); + if (Objects.isNull(zone)) { + throw new CloudRuntimeException(String.format("Failed to find zone with ID: %s", dataCenterId)); + } + 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 += "-S" + networkVO.getId(); + } else { + VpcVO vpc = vpcDao.findById(networkVO.getVpcId()); + 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); + } + /** * Setting pod id to null can result in migration of Volumes across pods. This is not desirable for VMs which * have a volume in Ready state (happens when a VM is shutdown and started again). @@ -2734,6 +2807,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac final VirtualMachineTO to = toVmTO(profile); final PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to); + setVmNetworkDetails(vm, to); ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Migrating, vm.getType(), vm.getId()); work.setStep(Step.Prepare); 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 e7cd1a3ef3a..5e3c8cfaa57 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 @@ -38,6 +38,9 @@ import java.util.stream.Collectors; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.VlanDetailsVO; +import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.network.dao.NsxProviderDao; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.dao.AnnotationDao; @@ -56,6 +59,7 @@ import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.network.dao.NetworkPermissionDao; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import com.cloud.agent.AgentManager; @@ -253,6 +257,7 @@ import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; import com.googlecode.ipv6.IPv6Address; +import org.jetbrains.annotations.NotNull; /** * NetworkManagerImpl implements NetworkManager. @@ -337,8 +342,12 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra Ipv6Service ipv6Service; @Inject RouterNetworkDao routerNetworkDao; + @Inject + private VlanDetailsDao vlanDetailsDao; List networkGurus; + @Inject + private NsxProviderDao nsxProviderDao; @Override public List getNetworkGurus() { @@ -500,6 +509,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra defaultTungstenSharedSGEnabledNetworkOfferingProviders.put(Service.UserData, tungstenProvider); defaultTungstenSharedSGEnabledNetworkOfferingProviders.put(Service.SecurityGroup, tungstenProvider); + final Map> defaultIsolatedSourceNatEnabledNetworkOfferingProviders = new HashMap>(); defaultProviders.clear(); defaultProviders.add(Network.Provider.VirtualRouter); @@ -536,27 +546,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, 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, 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, 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,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); } @@ -566,14 +576,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, 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, 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 @@ -582,14 +592,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, 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, 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 @@ -611,7 +621,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, 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); @@ -642,7 +652,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, 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); } @@ -738,20 +748,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra .getBroadcastDomainType() == BroadcastDomainType.Vlan || predefined.getBroadcastDomainType() == BroadcastDomainType.Lswitch || predefined .getBroadcastDomainType() == BroadcastDomainType.Vxlan)) { final List configs = _networksDao.listBy(owner.getId(), offering.getId(), plan.getDataCenterId()); - if (configs.size() > 0) { - if (logger.isDebugEnabled()) { - logger.debug("Found existing network configuration for offering " + offering + ": " + configs.get(0)); - } - - if (errorIfAlreadySetup) { - final InvalidParameterValueException ex = new InvalidParameterValueException( - "Found existing network configuration (with specified id) for offering (with specified id)"); - ex.addProxyObject(offering.getUuid(), "offeringId"); - ex.addProxyObject(configs.get(0).getUuid(), "networkConfigId"); - throw ex; - } else { - return configs; - } + if (!configs.isEmpty()) { + return existingConfiguration(offering, configs, errorIfAlreadySetup); } } @@ -760,7 +758,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra long related = -1; for (final NetworkGuru guru : networkGurus) { - final Network network = guru.design(offering, plan, predefined, owner); + final Network network = guru.design(offering, plan, predefined, name, vpcId, owner); if (network == null) { continue; } @@ -783,11 +781,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(final TransactionStatus status) { - final NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(), relatedFile, name, displayText, predefined - .getNetworkDomain(), offering.getGuestType(), plan.getDataCenterId(), plan.getPhysicalNetworkId(), aclType, offering.isSpecifyIpRanges(), - vpcId, offering.isRedundantRouter(), predefined.getExternalId()); - vo.setDisplayNetwork(isDisplayNetworkEnabled == null ? true : isDisplayNetworkEnabled); - vo.setStrechedL2Network(offering.isSupportingStrechedL2()); + final NetworkVO vo = getNetworkVO(id, offering, plan, predefined, + network, guru, owner, name, displayText,relatedFile, aclType,vpcId, isDisplayNetworkEnabled); final NetworkVO networkPersisted = _networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated, finalizeServicesAndProvidersForNetwork(offering, plan.getPhysicalNetworkId())); networks.add(networkPersisted); @@ -804,13 +799,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } if (domainId != null && aclType == ACLType.Domain) { - _networksDao.addDomainToNetwork(id, domainId, subdomainAccess == null ? true : subdomainAccess); + _networksDao.addDomainToNetwork(id, domainId, subdomainAccess == null || subdomainAccess); } } }); + guru.setup(network, relatedFile); } - if (networks.size() < 1) { + if (networks.isEmpty()) { // see networkOfferingVO.java final CloudRuntimeException ex = new CloudRuntimeException("Unable to convert network offering with specified id to network profile"); ex.addProxyObject(offering.getUuid(), "offeringId"); @@ -824,6 +820,37 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } } + @NotNull + private static NetworkVO getNetworkVO(long id, final NetworkOffering offering, final DeploymentPlan plan, final Network predefined, + Network network, final NetworkGuru guru, final Account owner, + final String name, final String displayText, long relatedFile, final ACLType aclType, + final Long vpcId, final Boolean isDisplayNetworkEnabled) { + final NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(), + relatedFile, name, displayText, predefined.getNetworkDomain(), offering.getGuestType(), + plan.getDataCenterId(), plan.getPhysicalNetworkId(), aclType, offering.isSpecifyIpRanges(), + vpcId, offering.isRedundantRouter(), predefined.getExternalId()); + vo.setDisplayNetwork(isDisplayNetworkEnabled == null || isDisplayNetworkEnabled); + vo.setStrechedL2Network(offering.isSupportingStrechedL2()); + return vo; + } + + private List existingConfiguration(final NetworkOffering offering, List configs, + final boolean errorIfAlreadySetup) { + if (logger.isDebugEnabled()) { + logger.debug("Found existing network configuration for offering " + offering + ": " + configs.get(0)); + } + + if (errorIfAlreadySetup) { + final InvalidParameterValueException ex = new InvalidParameterValueException( + "Found existing network configuration (with specified id) for offering (with specified id)"); + ex.addProxyObject(offering.getUuid(), "offeringId"); + ex.addProxyObject(configs.get(0).getUuid(), "networkConfigId"); + throw ex; + } else { + return configs; + } + } + @Override @DB public void allocate(final VirtualMachineProfile vm, final LinkedHashMap> networks, final Map> extraDhcpOptions) throws InsufficientCapacityException, @@ -1025,6 +1052,12 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return null; } + if (isNicAllocatedForNsxPublicNetworkOnVR(network, profile, vm)) { + String guruName = "NsxPublicNetworkGuru"; + NetworkGuru nsxGuru = AdapterBase.getAdapterByName(networkGurus, guruName); + nsxGuru.allocate(network, profile, vm); + } + if (isDefaultNic != null) { profile.setDefaultNic(isDefaultNic); } @@ -1057,6 +1090,36 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return new Pair(vmNic, Integer.valueOf(deviceId)); } + private boolean isNicAllocatedForNsxPublicNetworkOnVR(Network network, NicProfile requested, VirtualMachineProfile vm) { + if (ObjectUtils.anyNull(network, requested, vm)) { + return false; + } + boolean isVirtualRouter = vm.getType() == Type.DomainRouter; + boolean isPublicTraffic = network.getTrafficType() == TrafficType.Public; + if (!isVirtualRouter || !isPublicTraffic || requested.getIPv4Address() == null) { + return false; + } + long dataCenterId = vm.getVirtualMachine().getDataCenterId(); + if (nsxProviderDao.findByZoneId(dataCenterId) == null) { + return false; + } + + Long vpcId = _ipAddressDao.findByIp(requested.getIPv4Address()).getVpcId(); + List ips = _ipAddressDao.listByAssociatedVpc(vpcId, true); + + if (CollectionUtils.isEmpty(ips)) { + return false; + } + ips = ips.stream().filter(x -> !x.getAddress().addr().equals(requested.getIPv4Address())).collect(Collectors.toList()); + IPAddressVO ip = ips.get(0); + VlanDetailsVO vlanDetail = vlanDetailsDao.findDetail(ip.getVlanId(), ApiConstants.NSX_DETAIL_KEY); + if (vlanDetail == null) { + return false; + } + boolean isForNsx = vlanDetail.getValue().equalsIgnoreCase("true"); + return isForNsx && !ip.isForSystemVms(); + } + private void setMtuDetailsInVRNic(final Pair networks, Network network, NicVO vo) { if (TrafficType.Public == network.getTrafficType()) { if (networks == null) { @@ -2814,10 +2877,9 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } // Check if cidr is RFC1918 compliant if the network is Guest Isolated for IPv4 - if (cidr != null && ntwkOff.getGuestType() == Network.GuestType.Isolated && ntwkOff.getTrafficType() == TrafficType.Guest) { - if (!NetUtils.validateGuestCidr(cidr)) { + if (cidr != null && (ntwkOff.getGuestType() == Network.GuestType.Isolated && ntwkOff.getTrafficType() == TrafficType.Guest) && + !NetUtils.validateGuestCidr(cidr, !ConfigurationManager.AllowNonRFC1918CompliantIPs.value())) { throw new InvalidParameterValueException("Virtual Guest Cidr " + cidr + " is not RFC 1918 or 6598 compliant"); - } } final String networkDomainFinal = networkDomain; @@ -3844,7 +3906,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra private boolean cleanupNetworkResources(final long networkId, final Account caller, final long callerUserId) { boolean success = true; - final Network network = _networksDao.findById(networkId); + final NetworkVO network = _networksDao.findById(networkId); + final NetworkOfferingVO networkOffering= _networkOfferingDao.findById(network.getNetworkOfferingId()); //remove all PF/Static Nat rules for the network try { @@ -4724,6 +4787,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return new ConfigKey[]{NetworkGcWait, NetworkGcInterval, NetworkLockTimeout, GuestDomainSuffix, NetworkThrottlingRate, MinVRVersion, PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RollingRestartEnabled, - TUNGSTEN_ENABLED }; + TUNGSTEN_ENABLED, NSX_ENABLED }; } } 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 e357c062c17..3d79f413f3b 100644 --- a/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java +++ b/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java @@ -39,6 +39,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.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.framework.config.ConfigKey; @@ -182,6 +194,16 @@ public class VirtualMachineManagerImplTest { @Mock private UserVmVO userVmMock; @Mock + private NetworkDao networkDao; + @Mock + private AccountDao accountDao; + @Mock + private DomainDao domainDao; + @Mock + private DataCenterDao dcDao; + @Mock + private VpcDao vpcDao; + @Mock private EntityManager _entityMgr; @Mock private DeploymentPlanningManager _dpMgr; @@ -938,6 +960,48 @@ public class VirtualMachineManagerImplTest { 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(1, vmTO.getNetworkIdToNetworkNameMap().size()); + assertEquals("D3-A2-Z1-V4-S5", vmTO.getNetworkIdToNetworkNameMap().get(5L)); + } + @Test public void testOrchestrateStartNonNullPodId() throws Exception { VMInstanceVO vmInstance = new VMInstanceVO(); diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java index fde93238451..581f7899069 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java @@ -367,6 +367,10 @@ public class NetworkVO implements Network { return mode; } + public void setAccountId(long accountId) { + this.accountId = accountId; + } + @Override public long getAccountId() { return accountId; diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NsxProviderDao.java b/engine/schema/src/main/java/com/cloud/network/dao/NsxProviderDao.java new file mode 100644 index 00000000000..0fc77537711 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/NsxProviderDao.java @@ -0,0 +1,30 @@ +// 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 com.cloud.network.dao; + +import com.cloud.network.element.NsxProviderVO; +import com.cloud.utils.db.GenericDao; + +import java.util.List; + +public interface NsxProviderDao extends GenericDao { + NsxProviderVO findByZoneId(long zoneId); + + NsxProviderVO findByUuid(String uuid); + + List findAll(); +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NsxProviderDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/NsxProviderDaoImpl.java new file mode 100644 index 00000000000..cf7b5d405c0 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/NsxProviderDaoImpl.java @@ -0,0 +1,65 @@ +// 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 com.cloud.network.dao; + +import com.cloud.network.element.NsxProviderVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@DB() +public class NsxProviderDaoImpl extends GenericDaoBase + implements NsxProviderDao { + + final SearchBuilder allFieldsSearch; + + public NsxProviderDaoImpl() { + super(); + allFieldsSearch = createSearchBuilder(); + allFieldsSearch.and("id", allFieldsSearch.entity().getId(), + SearchCriteria.Op.EQ); + allFieldsSearch.and("uuid", allFieldsSearch.entity().getUuid(), + SearchCriteria.Op.EQ); + allFieldsSearch.and("hostname", allFieldsSearch.entity().getHostname(), + SearchCriteria.Op.EQ); + allFieldsSearch.and("provider_name", allFieldsSearch.entity().getProviderName(), + SearchCriteria.Op.EQ); + allFieldsSearch.and("tier0_gateway", allFieldsSearch.entity().getTier0Gateway(), + SearchCriteria.Op.EQ); + allFieldsSearch.and("zone_id", allFieldsSearch.entity().getZoneId(), + SearchCriteria.Op.EQ); + allFieldsSearch.and("edge_cluster", allFieldsSearch.entity().getEdgeCluster(), + SearchCriteria.Op.EQ); + allFieldsSearch.done(); + } + @Override + public NsxProviderVO findByZoneId(long zoneId) { + SearchCriteria sc = allFieldsSearch.create(); + sc.setParameters("zone_id", zoneId); + return findOneBy(sc); + } + + @Override + public List findAll() { + return listAll(); + } +} diff --git a/engine/schema/src/main/java/com/cloud/network/element/NsxProviderVO.java b/engine/schema/src/main/java/com/cloud/network/element/NsxProviderVO.java new file mode 100644 index 00000000000..f08e08b1ca0 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/element/NsxProviderVO.java @@ -0,0 +1,285 @@ +// 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 com.cloud.network.element; + +import com.cloud.network.nsx.NsxProvider; +import com.cloud.utils.db.Encrypt; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; +import java.util.UUID; + +@Entity +@Table(name = "nsx_providers") +public class NsxProviderVO implements NsxProvider { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + long id; + + @Column(name = "zone_id") + private long zoneId; + + @Column(name = "host_id") + private long hostId; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "provider_name") + private String providerName; + + @Column(name = "hostname") + private String hostname; + + @Column(name = "port") + private String port = "443"; + + @Column(name = "username") + private String username; + + @Encrypt + @Column(name = "password") + private String password; + + @Column(name = "tier0_gateway") + private String tier0Gateway; + + @Column(name = "edge_cluster") + private String edgeCluster; + + @Column(name = "transport_zone") + private String transportZone; + + @Column(name = "created") + private Date created; + + @Column(name = "removed") + private Date removed; + public NsxProviderVO() { + this.uuid = UUID.randomUUID().toString(); + } + + @Override + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @Override + public long getZoneId() { + return zoneId; + } + + public void setZoneId(long zoneId) { + this.zoneId = zoneId; + } + + public long getHostId() { + return hostId; + } + + public void setHostId(long hostId) { + this.hostId = hostId; + } + + @Override + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public String getProviderName() { + return providerName; + } + + public void setProviderName(String providerName) { + this.providerName = providerName; + } + + @Override + public String getHostname() { + return hostname; + } + + public void setPort(String port) { + this.port = port; + } + + @Override + public String getPort() { + return port; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + @Override + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getTier0Gateway() { + return tier0Gateway; + } + + public void setTier0Gateway(String tier0Gateway) { + this.tier0Gateway = tier0Gateway; + } + + public String getEdgeCluster() { + return edgeCluster; + } + + public void setEdgeCluster(String edgeCluster) { + this.edgeCluster = edgeCluster; + } + + public String getTransportZone() { + return transportZone; + } + + public void setTransportZone(String transportZone) { + this.transportZone = transportZone; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getRemoved() { + return removed; + } + + public void setRemoved(Date removed) { + this.removed = removed; + } + + public static final class Builder { + private long zoneId; + private long hostId; + private String providerName; + private String hostname; + private String port; + private String username; + private String password; + private String tier0Gateway; + private String edgeCluster; + private String transportZone; + + + public Builder() { + // Default constructor + } + + public Builder setZoneId(long zoneId) { + this.zoneId = zoneId; + return this; + } + + public Builder setHostId(long hostId) { + this.hostId = hostId; + return this; + } + + public Builder setProviderName(String providerName) { + this.providerName = providerName; + return this; + } + + public Builder setHostname(String hostname) { + this.hostname = hostname; + return this; + } + + public Builder setPort(String port) { + this.port = port; + return this; + } + + public Builder setUsername(String username) { + this.username = username; + return this; + } + + public Builder setPassword(String password) { + this.password = password; + return this; + } + + public Builder setTier0Gateway(String tier0Gateway) { + this.tier0Gateway = tier0Gateway; + return this; + } + + public Builder setEdgeCluster(String edgeCluster) { + this.edgeCluster = edgeCluster; + return this; + } + + public Builder setTransportZone(String transportZone) { + this.transportZone = transportZone; + return this; + } + public NsxProviderVO build() { + NsxProviderVO provider = new NsxProviderVO(); + provider.setZoneId(this.zoneId); + provider.setHostId(this.hostId); + provider.setUuid(UUID.randomUUID().toString()); + provider.setProviderName(this.providerName); + provider.setHostname(this.hostname); + provider.setPort(this.port); + provider.setUsername(this.username); + provider.setPassword(this.password); + provider.setTier0Gateway(this.tier0Gateway); + provider.setEdgeCluster(this.edgeCluster); + provider.setTransportZone(this.transportZone); + provider.setCreated(new Date()); + return provider; + } + } +} 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 ae5e6fb95ea..b2fabf2e3cd 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java @@ -136,6 +136,12 @@ public class NetworkOfferingVO implements NetworkOffering { @Column(name = "for_tungsten") boolean forTungsten = false; + @Column(name = "for_nsx") + boolean forNsx = false; + + @Column(name = "nsx_mode") + String nsxMode; + @Column(name = "egress_default_policy") boolean egressdefaultpolicy; @@ -195,6 +201,24 @@ public class NetworkOfferingVO implements NetworkOffering { this.forTungsten = forTungsten; } + @Override + public boolean isForNsx() { + return forNsx; + } + + public void setForNsx(boolean forNsx) { + 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/java/com/cloud/vm/dao/NicDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java index 68f57329d77..23c26ea0718 100644 --- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java @@ -44,6 +44,8 @@ public interface NicDao extends GenericDao { NicVO findByNetworkIdAndType(long networkId, VirtualMachine.Type vmType); + NicVO findByNetworkIdAndTypeIncludingRemoved(long networkId, VirtualMachine.Type vmType); + NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId); NicVO findByNetworkIdAndMacAddress(long networkId, String mac); diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java index 59d2417b073..3eee1d4e749 100644 --- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java @@ -176,12 +176,21 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { return findOneIncludingRemovedBy(sc); } - @Override - public NicVO findByNetworkIdAndType(long networkId, VirtualMachine.Type vmType) { + private NicVO findByNetworkIdAndTypeInternal(long networkId, VirtualMachine.Type vmType, boolean includingRemoved) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("network", networkId); sc.setParameters("vmType", vmType); - return findOneBy(sc); + return includingRemoved ? findOneIncludingRemovedBy(sc) : findOneBy(sc); + } + + @Override + public NicVO findByNetworkIdAndType(long networkId, VirtualMachine.Type vmType) { + return findByNetworkIdAndTypeInternal(networkId, vmType, false); + } + + @Override + public NicVO findByNetworkIdAndTypeIncludingRemoved(long networkId, VirtualMachine.Type vmType) { + return findByNetworkIdAndTypeInternal(networkId, vmType, true); } @Override diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 5d958383161..9fa01c28f5f 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -136,6 +136,7 @@ + diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41900to42000.sql b/engine/schema/src/main/resources/META-INF/db/schema-41900to42000.sql index cc54e637d88..e270583c9b1 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41900to42000.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41900to42000.sql @@ -33,4 +33,32 @@ ADD UNIQUE INDEX `i_resource_count__type_tag_domaintId` (`type`,`tag`,`domain_id UPDATE `cloud`.`service_offering` SET ram_size = 512 WHERE unique_name IN ("Cloud.Com-SoftwareRouter", "Cloud.Com-SoftwareRouter-Local", "Cloud.Com-InternalLBVm", "Cloud.Com-InternalLBVm-Local", "Cloud.Com-ElasticLBVm", "Cloud.Com-ElasticLBVm-Local") - AND system_use = 1 AND ram_size < 512; + AND system_use = 1 AND ram_size < 512; + +-- NSX Plugin -- +CREATE TABLE `cloud`.`nsx_providers` ( + `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', + `uuid` varchar(40), + `zone_id` bigint unsigned NOT NULL COMMENT 'Zone ID', + `host_id` bigint unsigned NOT NULL COMMENT 'Host ID', + `provider_name` varchar(40), + `hostname` varchar(255) NOT NULL, + `port` varchar(255), + `username` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `tier0_gateway` varchar(255), + `edge_cluster` varchar(255), + `transport_zone` varchar(255), + `created` datetime NOT NULL COMMENT 'date created', + `removed` datetime COMMENT 'date removed if not null', + PRIMARY KEY (`id`), + CONSTRAINT `fk_nsx_providers__zone_id` FOREIGN KEY `fk_nsx_providers__zone_id` (`zone_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, + INDEX `i_nsx_providers__zone_id`(`zone_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- 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"'); + diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql index 8ba291e154c..bae73deda32 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql @@ -60,6 +60,8 @@ SELECT `network_offerings`.`supports_vm_autoscaling` AS `supports_vm_autoscaling`, `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, diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql index cb762a57883..9aca869b510 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql @@ -17,7 +17,6 @@ -- cloud.vpc_offering_view source - DROP VIEW IF EXISTS `cloud`.`vpc_offering_view`; CREATE VIEW `cloud`.`vpc_offering_view` AS @@ -29,6 +28,8 @@ select `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`, diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 2c570f64a44..826c613798a 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -462,7 +462,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw } } HypervisorHostHelper.prepareNetwork(vSwitchName, "cloud.private", hostMo, vlanId, null, null, null, 180000, - vsType, portsPerDvPortGroup, null, false, BroadcastDomainType.Vlan, null, null); + vsType, portsPerDvPortGroup, null, false, BroadcastDomainType.Vlan, null, null, null); } } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 10ad8f2176a..3a551fce7eb 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -730,7 +730,7 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes HostMO hostMO = new HostMO(context, host.getMor()); try { - prepareNetworkFromNicInfo(hostMO, cmd.getNic(), false, null); + prepareNetworkFromNicInfo(hostMO, cmd.getNic(), false, null, null); hostname = host.getHyperHostName(); } catch (Exception e) { return new SetupPersistentNetworkAnswer(cmd, false, "failed to setup port-group due to: "+ e.getLocalizedMessage()); @@ -1472,7 +1472,7 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes deviceNumber++; VirtualDevice nic; - Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false, vmType); + Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false, nicTo.getNetworkSegmentName(), vmType); String dvSwitchUuid = null; if (VmwareHelper.isDvPortGroup(networkInfo.first())) { ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); @@ -1534,7 +1534,7 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes return new ReplugNicAnswer(cmd, false, "Nic to replug not found"); } - Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false, cmd.getVMType()); + Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false, null, cmd.getVMType()); String dvSwitchUuid = null; if (VmwareHelper.isDvPortGroup(networkInfo.first())) { ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); @@ -1616,7 +1616,7 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes } else { networkInfo = HypervisorHostHelper.prepareNetwork(_publicTrafficInfo.getVirtualSwitchName(), "cloud.public", vmMo.getRunningHost(), vlanId, null, ipAddressTO.getNetworkRate(), null, - _opsTimeout, vSwitchType, _portsPerDvPortGroup, null, false, BroadcastDomainType.Vlan, _vsmCredentials, null); + _opsTimeout, vSwitchType, _portsPerDvPortGroup, null, false, BroadcastDomainType.Vlan, _vsmCredentials, null, null); } int nicIndex = allocPublicNicIndex(vmMo); @@ -2525,7 +2525,8 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes } boolean configureVServiceInNexus = (nicTo.getType() == TrafficType.Guest) && (vmSpec.getDetails().containsKey("ConfigureVServiceInNexus")); VirtualMachine.Type vmType = cmd.getVirtualMachine().getType(); - Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus, vmType); + Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus, + vmSpec.getNetworkIdToNetworkNameMap().getOrDefault(nicTo.getNetworkId(), null), vmType); if ((nicTo.getBroadcastType() != BroadcastDomainType.Lswitch) || (nicTo.getBroadcastType() == BroadcastDomainType.Lswitch && NiciraNvpApiVersion.isApiVersionLowerThan("4.2"))) { if (VmwareHelper.isDvPortGroup(networkInfo.first())) { @@ -3981,7 +3982,7 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes return defaultVlan; } - private Pair prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus, VirtualMachine.Type vmType) + private Pair prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus, String networkName, VirtualMachine.Type vmType) throws Exception { Ternary switchDetails = getTargetSwitch(nicTo); @@ -4011,7 +4012,7 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes } networkInfo = HypervisorHostHelper.prepareNetwork(switchName, namePrefix, hostMo, vlanId, svlanId, nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _opsTimeout, switchType, - _portsPerDvPortGroup, nicTo.getGateway(), configureVServiceInNexus, nicTo.getBroadcastType(), _vsmCredentials, nicTo.getDetails()); + _portsPerDvPortGroup, nicTo.getGateway(), configureVServiceInNexus, nicTo.getBroadcastType(), _vsmCredentials, nicTo.getDetails(), networkName); } return networkInfo; @@ -4602,7 +4603,8 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes NicTO[] nics = vm.getNics(); for (NicTO nic : nics) { // prepare network on the host - prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false, cmd.getVirtualMachine().getType()); + prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false, + vm.getNetworkIdToNetworkNameMap().getOrDefault(nic.getNetworkId(), null), cmd.getVirtualMachine().getType()); } List> secStoreUrlAndIdList = mgr.getSecondaryStorageStoresUrlAndIdList(Long.parseLong(_dcId)); @@ -5680,7 +5682,7 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes } protected Answer execute(MaintainCommand cmd) { - return new MaintainAnswer(cmd, "Put host in maintaince"); + return new MaintainAnswer(cmd, "Put host in maintenance"); } protected Answer execute(PingTestCommand cmd) { @@ -7326,7 +7328,8 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes NicTO[] nics = vmTo.getNics(); for (NicTO nic : nics) { // prepare network on the host - prepareNetworkFromNicInfo((HostMO)targetHyperHost, nic, false, vmTo.getType()); + prepareNetworkFromNicInfo((HostMO)targetHyperHost, nic, false, + vmTo.getNetworkIdToNetworkNameMap().get(nic.getNetworkId()), vmTo.getType()); } if (targetHyperHost == null) { diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImpl.java index 0ef916ab959..60bd81c7c5a 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImpl.java @@ -17,6 +17,7 @@ package com.cloud.kubernetes.cluster; import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao; +import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao; import com.cloud.utils.component.AdapterBase; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.framework.config.ConfigKey; @@ -24,18 +25,30 @@ import org.apache.cloudstack.framework.config.Configurable; import org.springframework.stereotype.Component; import javax.inject.Inject; +import java.util.Objects; @Component public class KubernetesClusterHelperImpl extends AdapterBase implements KubernetesClusterHelper, Configurable { @Inject private KubernetesClusterDao kubernetesClusterDao; + @Inject + private KubernetesClusterVmMapDao kubernetesClusterVmMapDao; @Override public ControlledEntity findByUuid(String uuid) { return kubernetesClusterDao.findByUuid(uuid); } + @Override + public ControlledEntity findByVmId(long vmId) { + KubernetesClusterVmMapVO clusterVmMapVO = kubernetesClusterVmMapDao.getClusterMapFromVmId(vmId); + if (Objects.isNull(clusterVmMapVO)) { + return null; + } + return kubernetesClusterDao.findById(clusterVmMapVO.getClusterId()); + } + @Override public String getConfigComponentName() { return KubernetesClusterHelper.class.getSimpleName(); diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java index fb95a35a6fe..834d6d33330 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java @@ -182,6 +182,11 @@ import org.apache.logging.log4j.Level; public class KubernetesClusterManagerImpl extends ManagerBase implements KubernetesClusterService { private static final String DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME = "DefaultNetworkOfferingforKubernetesService"; + private static final String DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT = "Network Offering used for CloudStack Kubernetes service"; + private static final String DEFAULT_NSX_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME = "DefaultNSXNetworkOfferingforKubernetesService"; + private static final String DEFAULT_NSX_VPC_TIER_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME = "DefaultNSXVPCNetworkOfferingforKubernetesService"; + private static final String DEFAULT_NSX_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT = "Network Offering for NSX CloudStack Kubernetes Service"; + private static final String DEFAULT_NSX_VPC_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT = "Network Offering for NSX CloudStack Kubernetes service on VPC"; protected StateMachine2 _stateMachine = KubernetesCluster.State.getStateMachine(); @@ -1893,26 +1898,54 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne @Override public boolean start() { + createNetworkOfferingForKubernetes(DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME, + DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT, false, false); + + createNetworkOfferingForKubernetes(DEFAULT_NSX_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME, + DEFAULT_NSX_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT, true, false); + + createNetworkOfferingForKubernetes(DEFAULT_NSX_VPC_TIER_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME, + DEFAULT_NSX_VPC_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT , true, true); + + _gcExecutor.scheduleWithFixedDelay(new KubernetesClusterGarbageCollector(), 300, 300, TimeUnit.SECONDS); + _stateScanner.scheduleWithFixedDelay(new KubernetesClusterStatusScanner(), 300, 30, TimeUnit.SECONDS); + + return true; + } + + private void createNetworkOfferingForKubernetes(String offeringName, String offeringDesc, boolean forNsx, boolean forVpc) { final Map defaultKubernetesServiceNetworkOfferingProviders = new HashMap(); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Dhcp, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Dns, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.UserData, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Firewall, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Gateway, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Lb, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.SourceNat, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.StaticNat, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.PortForwarding, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Vpn, Network.Provider.VirtualRouter); + Network.Provider provider = forVpc ? Network.Provider.VPCVirtualRouter : Network.Provider.VirtualRouter; + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Dhcp, provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Dns, provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.UserData, provider); + if (forVpc) { + defaultKubernetesServiceNetworkOfferingProviders.put(Service.NetworkACL, forNsx ? Network.Provider.Nsx : provider); + } else { + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Firewall, forNsx ? Network.Provider.Nsx : provider); + } + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Lb, forNsx ? Network.Provider.Nsx : provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.SourceNat, forNsx ? Network.Provider.Nsx : provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.StaticNat, forNsx ? Network.Provider.Nsx : provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.PortForwarding, forNsx ? Network.Provider.Nsx : provider); + + if (!forNsx) { + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Gateway, Network.Provider.VirtualRouter); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Vpn, Network.Provider.VirtualRouter); + } NetworkOfferingVO defaultKubernetesServiceNetworkOffering = - new NetworkOfferingVO(DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME, - "Network Offering used for CloudStack Kubernetes service", Networks.TrafficType.Guest, + new NetworkOfferingVO(offeringName, + offeringDesc, Networks.TrafficType.Guest, false, false, null, null, true, NetworkOffering.Availability.Required, null, Network.GuestType.Isolated, true, true, false, false, false, false, false, false, false, true, true, false, - false, true, false, false); + forVpc, true, false, false); + if (forNsx) { + defaultKubernetesServiceNetworkOffering.setNsxMode(NetworkOffering.NsxMode.NATTED.name()); + defaultKubernetesServiceNetworkOffering.setForNsx(true); + } defaultKubernetesServiceNetworkOffering.setSupportsVmAutoScaling(true); defaultKubernetesServiceNetworkOffering.setState(NetworkOffering.State.Enabled); defaultKubernetesServiceNetworkOffering = networkOfferingDao.persistDefaultNetworkOffering(defaultKubernetesServiceNetworkOffering); @@ -1924,11 +1957,6 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne networkOfferingServiceMapDao.persist(offService); logger.trace("Added service for the network offering: " + offService); } - - _gcExecutor.scheduleWithFixedDelay(new KubernetesClusterGarbageCollector(), 300, 300, TimeUnit.SECONDS); - _stateScanner.scheduleWithFixedDelay(new KubernetesClusterStatusScanner(), 300, 30, TimeUnit.SECONDS); - - return true; } @Override diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java index c7451adf502..e8bc8e2851e 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java @@ -31,6 +31,8 @@ import java.util.stream.Collectors; import javax.inject.Inject; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingDao; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd; @@ -149,6 +151,8 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu protected VolumeApiService volumeService; @Inject protected VolumeDao volumeDao; + @Inject + protected NetworkOfferingDao networkOfferingDao; protected String kubernetesClusterNodeNamePrefix; @@ -738,12 +742,24 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu protected void setupKubernetesClusterVpcTierRules(IpAddress publicIp, Network network, List clusterVMIds) throws ManagementServerException { // Create ACL rules createVpcTierAclRules(network); - // Add port forwarding for API access - try { - provisionPublicIpPortForwardingRule(publicIp, network, owner, clusterVMIds.get(0), CLUSTER_API_PORT, CLUSTER_API_PORT); - } catch (ResourceUnavailableException | NetworkRuleConflictException e) { - throw new ManagementServerException(String.format("Failed to activate API port forwarding rules for the Kubernetes cluster : %s", kubernetesCluster.getName()), e); + + NetworkOffering offering = networkOfferingDao.findById(network.getNetworkOfferingId()); + if (offering.isConserveMode()) { + // Add load balancing for API access + try { + provisionLoadBalancerRule(publicIp, network, owner, clusterVMIds, CLUSTER_API_PORT); + } catch (InsufficientAddressCapacityException e) { + throw new ManagementServerException(String.format("Failed to activate API load balancing rules for the Kubernetes cluster : %s", kubernetesCluster.getName()), e); + } + } else { + // Add port forwarding for API access + try { + provisionPublicIpPortForwardingRule(publicIp, network, owner, clusterVMIds.get(0), CLUSTER_API_PORT, CLUSTER_API_PORT); + } catch (ResourceUnavailableException | NetworkRuleConflictException e) { + throw new ManagementServerException(String.format("Failed to activate API port forwarding rules for the Kubernetes cluster : %s", kubernetesCluster.getName()), e); + } } + // Add port forwarding rule for SSH access on each node VM try { provisionSshPortForwardingRules(publicIp, network, owner, clusterVMIds); diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java index 688a611ac99..45c0b79485c 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java @@ -23,6 +23,8 @@ import java.util.List; public interface KubernetesClusterVmMapDao extends GenericDao { public List listByClusterId(long clusterId); + + public KubernetesClusterVmMapVO getClusterMapFromVmId(long vmId); public List listByClusterIdAndVmIdsIn(long clusterId, List vmIds); int removeByClusterIdAndVmIdsIn(long clusterId, List vmIds); diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java index b9f2ec917b2..0d90a4cdaca 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java @@ -31,12 +31,17 @@ import com.cloud.utils.db.SearchCriteria; public class KubernetesClusterVmMapDaoImpl extends GenericDaoBase implements KubernetesClusterVmMapDao { private final SearchBuilder clusterIdSearch; + private final SearchBuilder vmIdSearch; public KubernetesClusterVmMapDaoImpl() { clusterIdSearch = createSearchBuilder(); clusterIdSearch.and("clusterId", clusterIdSearch.entity().getClusterId(), SearchCriteria.Op.EQ); clusterIdSearch.and("vmIdsIN", clusterIdSearch.entity().getVmId(), SearchCriteria.Op.IN); clusterIdSearch.done(); + + vmIdSearch = createSearchBuilder(); + vmIdSearch.and("vmId", vmIdSearch.entity().getVmId(), SearchCriteria.Op.EQ); + vmIdSearch.done(); } @Override @@ -47,6 +52,13 @@ public class KubernetesClusterVmMapDaoImpl extends GenericDaoBase sc = vmIdSearch.create(); + sc.setParameters("vmId", vmId); + return findOneBy(sc); + } + @Override public List listByClusterIdAndVmIdsIn(long clusterId, List vmIds) { SearchCriteria sc = clusterIdSearch.create(); diff --git a/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java b/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java index 95513df9c86..5fc9480c610 100644 --- a/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java +++ b/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java @@ -698,6 +698,11 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter { return true; } + @Override + public boolean reorderAclRules(Vpc vpc, List networks, List networkACLItems) { + return true; + } + @Override public boolean applyFWRules(Network network, List rules) diff --git a/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/guru/BigSwitchBcfGuestNetworkGuru.java b/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/guru/BigSwitchBcfGuestNetworkGuru.java index e23395bcf65..f9c11e50748 100644 --- a/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/guru/BigSwitchBcfGuestNetworkGuru.java +++ b/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/guru/BigSwitchBcfGuestNetworkGuru.java @@ -143,7 +143,7 @@ public class BigSwitchBcfGuestNetworkGuru extends GuestNetworkGuru implements Ne } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { // Check if the isolation type of the physical network is BCF_SEGMENT, then delegate GuestNetworkGuru to design PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); if (physnet == null || physnet.getIsolationMethods() == null || !physnet.getIsolationMethods().contains("BCF_SEGMENT")) { @@ -162,7 +162,7 @@ public class BigSwitchBcfGuestNetworkGuru extends GuestNetworkGuru implements Ne } logger.debug("Physical isolation type is BCF_SEGMENT, asking GuestNetworkGuru to design this network"); - NetworkVO networkObject = (NetworkVO)super.design(offering, plan, userSpecified, owner); + NetworkVO networkObject = (NetworkVO)super.design(offering, plan, userSpecified, name, vpcId, owner); if (networkObject == null) { return null; } diff --git a/plugins/network-elements/brocade-vcs/src/main/java/com/cloud/network/guru/BrocadeVcsGuestNetworkGuru.java b/plugins/network-elements/brocade-vcs/src/main/java/com/cloud/network/guru/BrocadeVcsGuestNetworkGuru.java index 1e13aaaa326..8d2125d70eb 100644 --- a/plugins/network-elements/brocade-vcs/src/main/java/com/cloud/network/guru/BrocadeVcsGuestNetworkGuru.java +++ b/plugins/network-elements/brocade-vcs/src/main/java/com/cloud/network/guru/BrocadeVcsGuestNetworkGuru.java @@ -95,7 +95,7 @@ public class BrocadeVcsGuestNetworkGuru extends GuestNetworkGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { // Check of the isolation type of the related physical network is VLAN PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); DataCenter dc = _dcDao.findById(plan.getDataCenterId()); @@ -103,8 +103,9 @@ public class BrocadeVcsGuestNetworkGuru extends GuestNetworkGuru { logger.debug("Refusing to design this network"); return null; } + logger.debug("Physical isolation type is VCS, asking GuestNetworkGuru to design this network"); - NetworkVO networkObject = (NetworkVO)super.design(offering, plan, userSpecified, owner); + NetworkVO networkObject = (NetworkVO)super.design(offering, plan, userSpecified, name, vpcId, owner); if (networkObject == null) { return null; } diff --git a/plugins/network-elements/brocade-vcs/src/test/java/com/cloud/network/guru/BrocadeVcsGuestNetworkGuruTest.java b/plugins/network-elements/brocade-vcs/src/test/java/com/cloud/network/guru/BrocadeVcsGuestNetworkGuruTest.java index 9fbb96f046d..3f5a047b911 100644 --- a/plugins/network-elements/brocade-vcs/src/test/java/com/cloud/network/guru/BrocadeVcsGuestNetworkGuruTest.java +++ b/plugins/network-elements/brocade-vcs/src/test/java/com/cloud/network/guru/BrocadeVcsGuestNetworkGuruTest.java @@ -170,7 +170,7 @@ public class BrocadeVcsGuestNetworkGuruTest { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = guru.design(offering, plan, network, "", 1L, account); assertTrue(designednetwork != null); assertTrue(designednetwork.getBroadcastDomainType() == BroadcastDomainType.Vcs); } @@ -191,7 +191,7 @@ public class BrocadeVcsGuestNetworkGuruTest { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = guru.design(offering, plan, network, "", 1L, account); assertTrue(designednetwork == null); } @@ -213,7 +213,7 @@ public class BrocadeVcsGuestNetworkGuruTest { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = guru.design(offering, plan, network, "", 1L, account); assertTrue(designednetwork == null); } diff --git a/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java b/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java index 0bbc3e678d3..0a9b4a7131a 100644 --- a/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java +++ b/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java @@ -83,7 +83,9 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.network.router.NetworkHelper; +import org.springframework.stereotype.Component; +@Component public class InternalLoadBalancerElement extends AdapterBase implements LoadBalancingServiceProvider, InternalLoadBalancerElementService, IpDeployer { protected static final Map> capabilities = setCapabilities(); private static InternalLoadBalancerElement internalLbElement = null; @@ -112,14 +114,7 @@ public class InternalLoadBalancerElement extends AdapterBase implements LoadBala @Qualifier("networkHelper") protected NetworkHelper _networkHelper; - protected InternalLoadBalancerElement() { - } - - public static InternalLoadBalancerElement getInstance() { - if (internalLbElement == null) { - internalLbElement = new InternalLoadBalancerElement(); - } - return internalLbElement; + public InternalLoadBalancerElement() { } private boolean canHandle(Network config, Scheme lbScheme) { @@ -517,6 +512,11 @@ public class InternalLoadBalancerElement extends AdapterBase implements LoadBala return sc.list(); } + @Override + public Type getProviderType() { + return Type.InternalLbVm; + } + @Override public boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException { //do nothing here; this element just has to extend the ip deployer 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 6fb4c3eff97..345cdc1e6c6 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 @@ -117,7 +117,7 @@ public class ContrailGuru extends AdapterBase implements NetworkGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { // Check of the isolation type of the related physical network is L3VPN PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); DataCenter dc = _dcDao.findById(plan.getDataCenterId()); @@ -136,6 +136,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 1261a23b569..791e245b17c 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 @@ -217,7 +217,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, 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); @@ -252,7 +252,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, 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); } @@ -293,7 +293,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/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailVpcElementImpl.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailVpcElementImpl.java index b73ed7feb60..85125bf3af6 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailVpcElementImpl.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailVpcElementImpl.java @@ -182,6 +182,11 @@ public class ContrailVpcElementImpl extends ContrailElementImpl implements Netwo return true; } + @Override + public boolean reorderAclRules(Vpc vpc, List networks, List networkACLItems) { + return true; + } + @Override public boolean applyACLItemsToPrivateGw(PrivateGateway privateGateway, List rules) diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ManagementNetworkGuru.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ManagementNetworkGuru.java index 0959eabd832..dc453f75c15 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ManagementNetworkGuru.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ManagementNetworkGuru.java @@ -109,7 +109,7 @@ public class ManagementNetworkGuru extends ContrailGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { if (!canHandle(offering)) { return null; diff --git a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java index 61dcf914e49..daf2420b528 100644 --- a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java +++ b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java @@ -136,7 +136,7 @@ public class NiciraNvpGuestNetworkGuru extends GuestNetworkGuru implements Netwo } @Override - public Network design(final NetworkOffering offering, final DeploymentPlan plan, final Network userSpecified, final Account owner) { + public Network design(final NetworkOffering offering, final DeploymentPlan plan, final Network userSpecified, String name, Long vpcId, final Account owner) { // Check of the isolation type of the related physical network is supported final PhysicalNetworkVO physnet = physicalNetworkDao.findById(plan.getPhysicalNetworkId()); final DataCenter dc = _dcDao.findById(plan.getDataCenterId()); @@ -153,7 +153,7 @@ public class NiciraNvpGuestNetworkGuru extends GuestNetworkGuru implements Netwo logger.debug("Nicira Nvp " + devices.get(0).getUuid() + " found on physical network " + physnet.getId()); logger.debug("Physical isolation type is supported, asking GuestNetworkGuru to design this network"); - final NetworkVO networkObject = (NetworkVO) super.design(offering, plan, userSpecified, owner); + final NetworkVO networkObject = (NetworkVO) super.design(offering, plan, userSpecified, name, vpcId, owner); if (networkObject == null) { return null; } diff --git a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java index 5925fd98149..c6ad8a6d907 100644 --- a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java +++ b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java @@ -168,7 +168,7 @@ public class NiciraNvpGuestNetworkGuruTest { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = guru.design(offering, plan, network, "", 1L, account); assertTrue(designednetwork != null); assertTrue(designednetwork.getBroadcastDomainType() == BroadcastDomainType.Lswitch); } @@ -192,7 +192,7 @@ public class NiciraNvpGuestNetworkGuruTest { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = guru.design(offering, plan, network, "", 1L, account); assertTrue(designednetwork == null); } @@ -215,7 +215,7 @@ public class NiciraNvpGuestNetworkGuruTest { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = guru.design(offering, plan, network, "", 1L, account); assertTrue(designednetwork == null); } @@ -241,7 +241,7 @@ public class NiciraNvpGuestNetworkGuruTest { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = guru.design(offering, plan, network, "", 1L, account); assertTrue(designednetwork == null); } diff --git a/plugins/network-elements/nsx/pom.xml b/plugins/network-elements/nsx/pom.xml new file mode 100644 index 00000000000..bed5731feee --- /dev/null +++ b/plugins/network-elements/nsx/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + cloud-plugin-network-nsx + Apache CloudStack Plugin - NSX Network + + + org.apache.cloudstack + cloudstack-plugins + 4.20.0.0-SNAPSHOT + ../../pom.xml + + + + com.vmware + nsx-java-sdk + 4.1.0.2.0 + + + com.vmware + nsx-gpm-java-sdk + 4.1.0.2.0 + + + com.vmware + nsx-policy-java-sdk + 4.1.0.2.0 + + + com.vmware.vapi + vapi-authentication + 2.40.0 + + + com.vmware.vapi + vapi-runtime + 2.40.0 + + + diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java new file mode 100644 index 00000000000..0820465a6b6 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java @@ -0,0 +1,31 @@ +// 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; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public class NsxAnswer extends Answer { + public NsxAnswer(final Command command, final boolean success, final String details) { + super(command, success, details); + } + + public NsxAnswer(final Command command, final Exception e) { + super(command, e); + } + +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/StartupNsxCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/StartupNsxCommand.java new file mode 100644 index 00000000000..8a5ac35e57e --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/StartupNsxCommand.java @@ -0,0 +1,26 @@ +// 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; + +import com.cloud.agent.api.StartupCommand; +import com.cloud.host.Host; + +public class StartupNsxCommand extends StartupCommand { + public StartupNsxCommand() { + super(Host.Type.L2Networking); + } +} 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 new file mode 100644 index 00000000000..6ef75b21e30 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDhcpRelayConfigCommand.java @@ -0,0 +1,77 @@ +// 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.agent.api; + +import java.util.List; +import java.util.Objects; + +public class CreateNsxDhcpRelayConfigCommand extends NsxCommand { + + private Long vpcId; + private String vpcName; + private long networkId; + private String networkName; + private List addresses; + + 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; + } + + public List getAddresses() { + return addresses; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + CreateNsxDhcpRelayConfigCommand that = (CreateNsxDhcpRelayConfigCommand) o; + return networkId == that.networkId && Objects.equals(vpcId, that.vpcId) && Objects.equals(vpcName, that.vpcName) && Objects.equals(networkName, that.networkName) && Objects.equals(addresses, that.addresses); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), vpcId, vpcName, networkId, networkName, addresses); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDistributedFirewallRulesCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDistributedFirewallRulesCommand.java new file mode 100644 index 00000000000..f598a201429 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDistributedFirewallRulesCommand.java @@ -0,0 +1,67 @@ +// 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.agent.api; + +import org.apache.cloudstack.resource.NsxNetworkRule; + +import java.util.List; +import java.util.Objects; + +public class CreateNsxDistributedFirewallRulesCommand extends NsxCommand { + + private Long vpcId; + private long networkId; + private List rules; + + public CreateNsxDistributedFirewallRulesCommand(long domainId, long accountId, long zoneId, + Long vpcId, long networkId, + List rules) { + super(domainId, accountId, zoneId); + this.vpcId = vpcId; + this.networkId = networkId; + this.rules = rules; + } + + public Long getVpcId() { + return vpcId; + } + + public long getNetworkId() { + return networkId; + } + + public List getRules() { + return rules; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + CreateNsxDistributedFirewallRulesCommand that = (CreateNsxDistributedFirewallRulesCommand) o; + return networkId == that.networkId && Objects.equals(vpcId, that.vpcId) && Objects.equals(rules, that.rules); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), vpcId, networkId, rules); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxLoadBalancerRuleCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxLoadBalancerRuleCommand.java new file mode 100644 index 00000000000..92acc83064d --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxLoadBalancerRuleCommand.java @@ -0,0 +1,87 @@ +// 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.agent.api; + +import org.apache.cloudstack.resource.NsxLoadBalancerMember; + +import java.util.List; +import java.util.Objects; + +public class CreateNsxLoadBalancerRuleCommand extends NsxNetworkCommand { + + private final String publicPort; + private final String privatePort; + private final String algorithm; + private final String protocol; + List memberList; + + private final long lbId; + public CreateNsxLoadBalancerRuleCommand(long domainId, long accountId, long zoneId, Long networkResourceId, + String networkResourceName, boolean isResourceVpc, + List memberList, long lbId, String publicPort, + String privatePort, String algorithm, String protocol) { + super(domainId, accountId, zoneId, networkResourceId, networkResourceName, isResourceVpc); + this.lbId = lbId; + this.memberList = memberList; + this.publicPort = publicPort; + this.privatePort = privatePort; + this.algorithm = algorithm; + this.protocol = protocol; + } + + + public long getLbId() { + return lbId; + } + + public String getPublicPort() { + return publicPort; + } + + public String getPrivatePort() { + return privatePort; + } + + public List getMemberList() { + return memberList; + } + + public String getAlgorithm() { + return algorithm; + } + + public String getProtocol() { + return protocol; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + CreateNsxLoadBalancerRuleCommand command = (CreateNsxLoadBalancerRuleCommand) o; + return lbId == command.lbId && Objects.equals(publicPort, command.publicPort) && Objects.equals(privatePort, command.privatePort) && Objects.equals(algorithm, command.algorithm) && Objects.equals(protocol, command.protocol) && Objects.equals(memberList, command.memberList); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), publicPort, privatePort, algorithm, protocol, memberList, lbId); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxPortForwardRuleCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxPortForwardRuleCommand.java new file mode 100644 index 00000000000..d72295563c7 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxPortForwardRuleCommand.java @@ -0,0 +1,71 @@ +// 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.agent.api; + +import java.util.Objects; + +public class CreateNsxPortForwardRuleCommand extends NsxNetworkCommand { + private final String publicPort; + private final String privatePort; + private final String protocol; + private final long ruleId; + + + public CreateNsxPortForwardRuleCommand(long domainId, long accountId, long zoneId, Long networkResourceId, + String networkResourceName, boolean isResourceVpc, Long vmId, + long ruleId, String publicIp, String vmIp, String publicPort, String privatePort, String protocol) { + super(domainId, accountId, zoneId, networkResourceId, networkResourceName, isResourceVpc, vmId, publicIp, vmIp); + this.publicPort = publicPort; + this.privatePort = privatePort; + this.ruleId = ruleId; + this.protocol = protocol; + + } + + public String getPublicPort() { + return publicPort; + } + + public String getPrivatePort() { + return privatePort; + } + + public long getRuleId() { + return ruleId; + } + + public String getProtocol() { + return protocol; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + CreateNsxPortForwardRuleCommand that = (CreateNsxPortForwardRuleCommand) o; + return ruleId == that.ruleId && Objects.equals(publicPort, that.publicPort) && Objects.equals(privatePort, that.privatePort) && Objects.equals(protocol, that.protocol); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), publicPort, privatePort, protocol, ruleId); + } +} 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 new file mode 100644 index 00000000000..b4b86bd640a --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxSegmentCommand.java @@ -0,0 +1,79 @@ +// 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.agent.api; + +import java.util.Objects; + +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 Long getVpcId() { + return vpcId; + } + + 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 + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + CreateNsxSegmentCommand command = (CreateNsxSegmentCommand) o; + return Objects.equals(networkName, command.networkName); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), networkName); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxStaticNatCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxStaticNatCommand.java new file mode 100644 index 00000000000..08c13420d1d --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxStaticNatCommand.java @@ -0,0 +1,25 @@ +// 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.agent.api; + +public class CreateNsxStaticNatCommand extends NsxNetworkCommand { + + public CreateNsxStaticNatCommand(long domainId, long accountId, long zoneId, Long networkResourceId, String networkResourceName, + boolean isResourceVpc, Long vmId, String publicIp, String vmIp) { + super(domainId, accountId, zoneId, networkResourceId, networkResourceName, isResourceVpc, vmId, publicIp, vmIp); + } +} 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 new file mode 100644 index 00000000000..90e4b3a25bd --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxTier1GatewayCommand.java @@ -0,0 +1,67 @@ +// 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.agent.api; + +import java.util.Objects; + +public class CreateNsxTier1GatewayCommand extends NsxCommand { + + private Long networkResourceId; + private String networkResourceName; + private boolean isResourceVpc; + private boolean sourceNatEnabled; + + public CreateNsxTier1GatewayCommand(long domainId, long accountId, long zoneId, + Long networkResourceId, String networkResourceName, boolean isResourceVpc, + boolean sourceNatEnabled) { + super(domainId, accountId, zoneId); + this.networkResourceId = networkResourceId; + this.networkResourceName = networkResourceName; + this.isResourceVpc = isResourceVpc; + this.sourceNatEnabled = sourceNatEnabled; + } + + public Long getNetworkResourceId() { + return networkResourceId; + } + + public boolean isResourceVpc() { + return isResourceVpc; + } + + public String getNetworkResourceName() { + return networkResourceName; + } + + public boolean isSourceNatEnabled() { + return sourceNatEnabled; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + CreateNsxTier1GatewayCommand that = (CreateNsxTier1GatewayCommand) o; + return Objects.equals(networkResourceName, that.networkResourceName); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), networkResourceName); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNsxTier1NatRuleCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNsxTier1NatRuleCommand.java new file mode 100644 index 00000000000..c14be743ea0 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNsxTier1NatRuleCommand.java @@ -0,0 +1,69 @@ +// 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.agent.api; + +import java.util.Objects; + +public class CreateOrUpdateNsxTier1NatRuleCommand extends NsxCommand { + + private String tier1GatewayName; + private String action; + private String translatedIpAddress; + private String natRuleId; + + public CreateOrUpdateNsxTier1NatRuleCommand(long domainId, long accountId, long zoneId, + String tier1GatewayName, String action, String translatedIpAddress, String natRuleId) { + super(domainId, accountId, zoneId); + this.tier1GatewayName = tier1GatewayName; + this.action = action; + this.translatedIpAddress = translatedIpAddress; + this.natRuleId = natRuleId; + } + + public String getTier1GatewayName() { + return tier1GatewayName; + } + + public String getAction() { + return action; + } + + public String getTranslatedIpAddress() { + return translatedIpAddress; + } + + public String getNatRuleId() { + return natRuleId; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + CreateOrUpdateNsxTier1NatRuleCommand that = (CreateOrUpdateNsxTier1NatRuleCommand) o; + return Objects.equals(tier1GatewayName, that.tier1GatewayName) && Objects.equals(action, that.action) && Objects.equals(translatedIpAddress, that.translatedIpAddress) && Objects.equals(natRuleId, that.natRuleId); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), tier1GatewayName, action, translatedIpAddress, natRuleId); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxDistributedFirewallRulesCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxDistributedFirewallRulesCommand.java new file mode 100644 index 00000000000..ad88f23b3b1 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxDistributedFirewallRulesCommand.java @@ -0,0 +1,27 @@ +// 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.agent.api; + +import org.apache.cloudstack.resource.NsxNetworkRule; + +import java.util.List; + +public class DeleteNsxDistributedFirewallRulesCommand extends CreateNsxDistributedFirewallRulesCommand { + public DeleteNsxDistributedFirewallRulesCommand(long domainId, long accountId, long zoneId, Long vpcId, long networkId, List rules) { + super(domainId, accountId, zoneId, vpcId, networkId, rules); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxLoadBalancerRuleCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxLoadBalancerRuleCommand.java new file mode 100644 index 00000000000..72aa61fdca3 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxLoadBalancerRuleCommand.java @@ -0,0 +1,58 @@ +// 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.agent.api; + +import org.apache.cloudstack.resource.NsxLoadBalancerMember; + +import java.util.List; +import java.util.Objects; + +public class DeleteNsxLoadBalancerRuleCommand extends NsxNetworkCommand { + private long lbId; + List memberList; + + public DeleteNsxLoadBalancerRuleCommand(long domainId, long accountId, long zoneId, Long networkResourceId, + String networkResourceName, boolean isResourceVpc, + List memberList, long lbId, long vmId) { + super(domainId, accountId, zoneId, networkResourceId, networkResourceName, isResourceVpc, vmId); + this.lbId = lbId; + this.memberList = memberList; + } + + public long getLbId() { + return lbId; + } + + public List getMemberList() { return memberList; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + DeleteNsxLoadBalancerRuleCommand that = (DeleteNsxLoadBalancerRuleCommand) o; + return lbId == that.lbId && Objects.equals(memberList, that.memberList); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), lbId, memberList); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxNatRuleCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxNatRuleCommand.java new file mode 100644 index 00000000000..c5231b19ac4 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxNatRuleCommand.java @@ -0,0 +1,73 @@ +// 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.agent.api; + +import com.cloud.network.Network; + +import java.util.Objects; + +public class DeleteNsxNatRuleCommand extends NsxNetworkCommand { + private Long ruleId; + private Network.Service service; + + private String privatePort; + private String protocol; + public DeleteNsxNatRuleCommand(long domainId, long accountId, long zoneId, Long networkResourceId, String networkResourceName, + boolean isResourceVpc, Long vmId, Long ruleId, String privatePort, String protocol) { + super(domainId, accountId, zoneId, networkResourceId, networkResourceName, isResourceVpc, vmId); + this.ruleId = ruleId; + this.privatePort = privatePort; + this.protocol = protocol; + } + + public Long getRuleId() { + return ruleId; + } + + public Network.Service getService() { + return service; + } + + public void setService(Network.Service service) { + this.service = service; + } + + public String getPrivatePort() { + return privatePort; + } + + public String getProtocol() { + return protocol; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + DeleteNsxNatRuleCommand that = (DeleteNsxNatRuleCommand) o; + return Objects.equals(ruleId, that.ruleId) && Objects.equals(service, that.service) && Objects.equals(privatePort, that.privatePort) && Objects.equals(protocol, that.protocol); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), ruleId, service, privatePort, protocol); + } +} 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 new file mode 100644 index 00000000000..882b55388ff --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxSegmentCommand.java @@ -0,0 +1,70 @@ +// 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.agent.api; + +import java.util.Objects; + +public class DeleteNsxSegmentCommand extends NsxCommand { + + 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; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + DeleteNsxSegmentCommand command = (DeleteNsxSegmentCommand) o; + return networkId == command.networkId && Objects.equals(vpcId, command.vpcId) && Objects.equals(vpcName, command.vpcName) && Objects.equals(networkName, command.networkName); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), vpcId, vpcName, networkId, 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 new file mode 100644 index 00000000000..d05acc18002 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxTier1GatewayCommand.java @@ -0,0 +1,63 @@ +// 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.agent.api; + +import java.util.Objects; + +public class DeleteNsxTier1GatewayCommand extends NsxCommand { + + private Long networkResourceId; + private String networkResourceName; + private boolean isResourceVpc; + + public DeleteNsxTier1GatewayCommand(long domainId, long accountId, long zoneId, + Long networkResourceId, String networkResourceName, boolean isResourceVpc) { + super(domainId, accountId, zoneId); + this.networkResourceId = networkResourceId; + this.networkResourceName = networkResourceName; + this.isResourceVpc = isResourceVpc; + } + + public Long getNetworkResourceId() { + return networkResourceId; + } + + public String getNetworkResourceName() { + return networkResourceName; + } + + public boolean isResourceVpc() { + return isResourceVpc; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass() || !super.equals(o)) { + return false; + } + DeleteNsxTier1GatewayCommand that = (DeleteNsxTier1GatewayCommand) o; + return isResourceVpc == that.isResourceVpc && Objects.equals(networkResourceId, that.networkResourceId) && Objects.equals(networkResourceName, that.networkResourceName); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), networkResourceId, networkResourceName, isResourceVpc); + } +} 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 new file mode 100644 index 00000000000..7c5e3a1d9fa --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxCommand.java @@ -0,0 +1,67 @@ +// 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.agent.api; + +import com.cloud.agent.api.Command; + +import java.util.Objects; + +public class NsxCommand extends Command { + private long zoneId; + private long accountId; + private long domainId; + + public NsxCommand() { + } + + public NsxCommand(long domainId, long accountId, long zoneId) { + this.zoneId = zoneId; + this.accountId = accountId; + this.domainId = domainId; + } + + public long getZoneId() { + return zoneId; + } + + public long getAccountId() { + return accountId; + } + + public long getDomainId() { + return domainId; + } + + @Override + public boolean executeInSequence() { + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + NsxCommand that = (NsxCommand) o; + 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(), zoneId, accountId, domainId); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxNetworkCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxNetworkCommand.java new file mode 100644 index 00000000000..4cad50db356 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxNetworkCommand.java @@ -0,0 +1,117 @@ +// 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.agent.api; + +import java.util.Objects; + +public class NsxNetworkCommand extends NsxCommand { + private Long networkResourceId; + private String networkResourceName; + private boolean isResourceVpc; + private Long vmId; + private String publicIp; + private String vmIp; + + public NsxNetworkCommand(long domainId, long accountId, long zoneId, Long networkResourceId, String networkResourceName, + boolean isResourceVpc, Long vmId, String publicIp, String vmIp) { + super(domainId, accountId, zoneId); + this.networkResourceId = networkResourceId; + this.networkResourceName = networkResourceName; + this.isResourceVpc = isResourceVpc; + this.vmId = vmId; + this.publicIp = publicIp; + this.vmIp = vmIp; + } + + public NsxNetworkCommand(long domainId, long accountId, long zoneId, Long networkResourceId, String networkResourceName, + boolean isResourceVpc) { + super(domainId, accountId, zoneId); + this.networkResourceId = networkResourceId; + this.networkResourceName = networkResourceName; + this.isResourceVpc = isResourceVpc; + } + + public NsxNetworkCommand(long domainId, long accountId, long zoneId, Long networkResourceId, String networkResourceName, + boolean isResourceVpc, Long vmId) { + this(domainId, accountId, zoneId, networkResourceId, networkResourceName, isResourceVpc); + this.vmId = vmId; + } + + public Long getNetworkResourceId() { + return networkResourceId; + } + + public void setNetworkResourceId(long networkResourceId) { + this.networkResourceId = networkResourceId; + } + + public String getNetworkResourceName() { + return networkResourceName; + } + + public void setNetworkResourceName(String networkResourceName) { + this.networkResourceName = networkResourceName; + } + + public boolean isResourceVpc() { + return isResourceVpc; + } + + public void setResourceVpc(boolean resourceVpc) { + isResourceVpc = resourceVpc; + } + + public Long getVmId() { + return vmId; + } + + public void setVmId(Long vmId) { + this.vmId = vmId; + } + + public String getPublicIp() { + return publicIp; + } + + public void setPublicIp(String publicIp) { + this.publicIp = publicIp; + } + + public String getVmIp() { + return vmIp; + } + + public void setVmIp(String vmIp) { + this.vmIp = vmIp; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + NsxNetworkCommand that = (NsxNetworkCommand) o; + return networkResourceId == that.networkResourceId && vmId == that.vmId && + Objects.equals(networkResourceName, that.networkResourceName) && Objects.equals(publicIp, that.publicIp) + && Objects.equals(vmIp, that.vmIp); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), networkResourceId, networkResourceName, vmId, publicIp, vmIp); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/StartupNsxCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/StartupNsxCommand.java new file mode 100644 index 00000000000..22deacca354 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/StartupNsxCommand.java @@ -0,0 +1,27 @@ +// 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.agent.api; + +import com.cloud.agent.api.StartupCommand; +import com.cloud.host.Host; + +public class StartupNsxCommand extends StartupCommand { + + public StartupNsxCommand() { + super(Host.Type.L2Networking); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/AddNsxControllerCmd.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/AddNsxControllerCmd.java new file mode 100644 index 00000000000..8e36599bf32 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/AddNsxControllerCmd.java @@ -0,0 +1,130 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command; + +import com.cloud.network.nsx.NsxProvider; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.response.NsxControllerResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.service.NsxProviderService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; + + +@APICommand(name = AddNsxControllerCmd.APINAME, description = "Add NSX Controller to CloudStack", + responseObject = NsxControllerResponse.class, requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, since = "4.19.0") +public class AddNsxControllerCmd extends BaseCmd { + public static final String APINAME = "addNsxController"; + public static final Logger LOGGER = LoggerFactory.getLogger(AddNsxControllerCmd.class.getName()); + + @Inject + NsxProviderService nsxProviderService; + + @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, + description = "the ID of zone") + private Long zoneId; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "NSX controller / provider name") + private String name; + + @Parameter(name = ApiConstants.NSX_PROVIDER_HOSTNAME, type = CommandType.STRING, required = true, description = "NSX controller hostname / IP address") + private String hostname; + + @Parameter(name = ApiConstants.NSX_PROVIDER_PORT, type = CommandType.STRING, description = "NSX controller port") + private String port; + @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = true, description = "Username to log into NSX controller") + private String username; + @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, required = true, description = "Password to login into NSX controller") + private String password; + + @Parameter(name = ApiConstants.TIER0_GATEWAY, type = CommandType.STRING, required = true, description = "Tier-0 Gateway address") + private String tier0Gateway; + + @Parameter(name = ApiConstants.EDGE_CLUSTER, type = CommandType.STRING, required = true, description = "Edge Cluster name") + private String edgeCluster; + + @Parameter(name = ApiConstants.TRANSPORT_ZONE, type = CommandType.STRING, required = true, description = "Transport Zone controls to which hosts a logical switch can reach") + private String transportZone; + + public NsxProviderService getNsxProviderService() { + return nsxProviderService; + } + + public Long getZoneId() { + return zoneId; + } + + public String getName() { + return name; + } + + public String getHostname() { + return hostname; + } + + public String getPort() { + return port; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getTier0Gateway() { + return tier0Gateway; + } + + public String getEdgeCluster() { + return edgeCluster; + } + + public String getTransportZone() { + return transportZone; + } + + @Override + public void execute() throws ServerApiException { + NsxProvider nsxProvider = nsxProviderService.addProvider(this); + NsxControllerResponse nsxControllerResponse = + nsxProviderService.createNsxControllerResponse( + nsxProvider); + if (nsxControllerResponse == null) + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add NSX controller"); + else { + nsxControllerResponse.setResponseName(getCommandName()); + setResponseObject(nsxControllerResponse); + } + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/DeleteNsxControllerCmd.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/DeleteNsxControllerCmd.java new file mode 100644 index 00000000000..5a3e5586400 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/DeleteNsxControllerCmd.java @@ -0,0 +1,87 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.response.NsxControllerResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.service.NsxProviderService; + +import javax.inject.Inject; + +import static org.apache.cloudstack.api.command.DeleteNsxControllerCmd.APINAME; + +@APICommand(name = APINAME, description = "delete NSX Controller to CloudStack", + responseObject = NsxControllerResponse.class, requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, since = "4.19.0") +public class DeleteNsxControllerCmd extends BaseCmd { + public static final String APINAME = "deleteNsxController"; + + @Inject + protected NsxProviderService nsxProviderService; +///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.NSX_CONTROLLER_ID, type = CommandType.UUID, entityType = NsxControllerResponse.class, + required = true, description = "NSX Controller ID") + private Long nsxControllerId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getNsxControllerId() { + return nsxControllerId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + + @Override + public void execute() throws ServerApiException, ConcurrentOperationException { + try { + boolean deleted = nsxProviderService.deleteNsxController(getNsxControllerId()); + if (deleted) { + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove NSX Controller from Zone"); + } + } catch (InvalidParameterValueException e) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage()); + } catch (CloudRuntimeException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public long getEntityOwnerId() { + return 0; + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/ListNsxControllersCmd.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/ListNsxControllersCmd.java new file mode 100644 index 00000000000..94b5855e783 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/ListNsxControllersCmd.java @@ -0,0 +1,68 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.utils.StringUtils; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NsxControllerResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.service.NsxProviderService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.util.List; + +import static org.apache.cloudstack.api.command.ListNsxControllersCmd.APINAME; + +@APICommand(name = APINAME, description = "list all NSX controllers added to CloudStack", + responseObject = NsxControllerResponse.class, requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, since = "4.19.0") +public class ListNsxControllersCmd extends BaseListCmd { + public static final String APINAME = "listNsxControllers"; + public static final Logger LOGGER = LoggerFactory.getLogger(ListNsxControllersCmd.class.getName()); + + @Inject + private NsxProviderService nsxProviderService; + + @Parameter(name = ApiConstants.ZONE_ID, description = "NSX controller added to the specific zone", + type = CommandType.UUID, entityType = ZoneResponse.class) + Long zoneId; + + @Override + public void execute() throws ServerApiException, ConcurrentOperationException { + List baseResponseList = nsxProviderService.listNsxProviders(zoneId); + List pagingList = StringUtils.applyPagination(baseResponseList, this.getStartIndex(), this.getPageSizeVal()); + ListResponse listResponse = new ListResponse<>(); + listResponse.setResponses(pagingList); + listResponse.setResponseName(getCommandName()); + setResponseObject(listResponse); + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/response/NsxControllerResponse.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/response/NsxControllerResponse.java new file mode 100644 index 00000000000..910c5e115bf --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/response/NsxControllerResponse.java @@ -0,0 +1,136 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import com.cloud.network.nsx.NsxProvider; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +@EntityReference(value = {NsxProvider.class}) +public class NsxControllerResponse extends BaseResponse { + @SerializedName(ApiConstants.NSX_PROVIDER_UUID) + @Param(description = "NSX controller ID") + private String uuid; + @SerializedName(ApiConstants.NAME) + @Param(description = "NSX controller name") + private String name; + + @SerializedName(ApiConstants.ZONE_ID) + @Param(description = "Zone ID to which the NSX controller is associated with") + private String zoneId; + + @SerializedName(ApiConstants.ZONE_NAME) + @Param(description = "Zone name to which the NSX controller is associated with") + private String zoneName; + + @SerializedName(ApiConstants.HOST_NAME) + @Param(description = "NSX controller hostname or IP address") + private String hostname; + + @SerializedName(ApiConstants.PORT) + @Param(description = "NSX controller port") + private String port; + + @SerializedName(ApiConstants.TIER0_GATEWAY) + @Param(description = "The tier-0 gateway network. Tier-0 gateway is responsible for handling" + + " traffic between logical and physical networks" + ) + private String tier0Gateway; + + @SerializedName(ApiConstants.EDGE_CLUSTER) + @Param(description = "The name of the edge cluster. An edge cluster is a logical grouping of edge nodes in NSX") + private String edgeCluster; + + @SerializedName(ApiConstants.TRANSPORT_ZONE) + @Param(description = "The name of the transport zone. A transport zone controls to which hosts a logical switch can reach") + private String transportZone; + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getZoneName() { + return zoneName; + } + + public void setZoneName(String zoneName) { + this.zoneName = zoneName; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getTier0Gateway() { + return tier0Gateway; + } + + public void setTier0Gateway(String tier0Gateway) { + this.tier0Gateway = tier0Gateway; + } + + public String getEdgeCluster() { + return edgeCluster; + } + + public void setEdgeCluster(String edgeCluster) { + this.edgeCluster = edgeCluster; + } + + public String getTransportZone() { + return transportZone; + } + + public void setTransportZone(String transportZone) { + this.transportZone = transportZone; + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxLoadBalancerMember.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxLoadBalancerMember.java new file mode 100644 index 00000000000..00960ddb78a --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxLoadBalancerMember.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.resource; + +public class NsxLoadBalancerMember { + private long vmId; + private String vmIp; + private int port; + + public NsxLoadBalancerMember(long vmId, String vmIp, int port) { + this.vmId = vmId; + this.vmIp = vmIp; + this.port = port; + } + + public long getVmId() { + return vmId; + } + + public String getVmIp() { + return vmIp; + } + + public int getPort() { + return port; + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java new file mode 100644 index 00000000000..c11141db9d4 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java @@ -0,0 +1,397 @@ +// 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.Network; + +import java.util.List; + +public class NsxNetworkRule { + + public enum NsxRuleAction { + ALLOW, DROP + } + + private long domainId; + private long accountId; + private long zoneId; + private Long networkResourceId; + private String networkResourceName; + private boolean isVpcResource; + private long vmId; + private long ruleId; + private String publicIp; + private String vmIp; + private String publicPort; + private String privatePort; + private String protocol; + private String algorithm; + private List memberList; + private NsxRuleAction aclAction; + private List sourceCidrList; + private List destinationCidrList; + private Integer icmpCode; + + private Integer icmpType; + private String trafficType; + private Network.Service service; + + public long getDomainId() { + return domainId; + } + + public void setDomainId(long domainId) { + this.domainId = domainId; + } + + public long getAccountId() { + return accountId; + } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + + public long getZoneId() { + return zoneId; + } + + public void setZoneId(long zoneId) { + this.zoneId = zoneId; + } + + public Long getNetworkResourceId() { + return networkResourceId; + } + + public void setNetworkResourceId(Long networkResourceId) { + this.networkResourceId = networkResourceId; + } + + public String getNetworkResourceName() { + return networkResourceName; + } + + public void setNetworkResourceName(String networkResourceName) { + this.networkResourceName = networkResourceName; + } + + public boolean isVpcResource() { + return isVpcResource; + } + + public void setVpcResource(boolean vpcResource) { + isVpcResource = vpcResource; + } + + public long getVmId() { + return vmId; + } + + public void setVmId(long vmId) { + this.vmId = vmId; + } + + public long getRuleId() { + return ruleId; + } + + public void setRuleId(long ruleId) { + this.ruleId = ruleId; + } + + public String getPublicIp() { + return publicIp; + } + + public void setPublicIp(String publicIp) { + this.publicIp = publicIp; + } + + public String getVmIp() { + return vmIp; + } + + public void setVmIp(String vmIp) { + this.vmIp = vmIp; + } + + public String getPublicPort() { + return publicPort; + } + + public void setPublicPort(String publicPort) { + this.publicPort = publicPort; + } + + public String getPrivatePort() { + return privatePort; + } + + public void setPrivatePort(String privatePort) { + this.privatePort = privatePort; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public String getAlgorithm() { + return algorithm; + } + + public List getMemberList() { + return memberList; + } + + public void setMemberList(List memberList) { + this.memberList = memberList; + } + + public NsxRuleAction getAclAction() { + return aclAction; + } + + public void setAclAction(NsxRuleAction aclAction) { + this.aclAction = aclAction; + } + + public Network.Service getService() { + return service; + } + + public void setService(Network.Service service) { + this.service = service; + } + + public Integer getIcmpCode() { + return icmpCode; + } + + public void setIcmpCode(Integer icmpCode) { + this.icmpCode = icmpCode; + } + + public Integer getIcmpType() { + return icmpType; + } + + public void setIcmpType(Integer icmpType) { + this.icmpType = icmpType; + } + + public List getSourceCidrList() { + return sourceCidrList; + } + + public void setSourceCidrList(List sourceCidrList) { + this.sourceCidrList = sourceCidrList; + } + + public List getDestinationCidrList() { + return destinationCidrList; + } + + public void setDestinationCidrList(List destinationCidrList) { + this.destinationCidrList = destinationCidrList; + } + + public String getTrafficType() { + return trafficType; + } + + public void setTrafficType(String trafficType) { + this.trafficType = trafficType; + } + + public static final class Builder { + private long domainId; + private long accountId; + private long zoneId; + private Long networkResourceId; + private String networkResourceName; + private boolean isVpcResource; + private long vmId; + + private long ruleId; + private String publicIp; + private String vmIp; + private String publicPort; + private String privatePort; + private String protocol; + private String algorithm; + private List memberList; + private NsxRuleAction aclAction; + private List sourceCidrList; + private List destinationidrList; + private String trafficType; + private Integer icmpType; + private Integer icmpCode; + private Network.Service service; + + public Builder() { + // Default constructor + } + + public Builder setDomainId(long domainId) { + this.domainId = domainId; + return this; + } + + public Builder setAccountId(long accountId) { + this.accountId = accountId; + return this; + } + + public Builder setZoneId(long zoneId) { + this.zoneId = zoneId; + return this; + } + + public Builder setNetworkResourceId(Long networkResourceId) { + this.networkResourceId = networkResourceId; + return this; + } + + public Builder setNetworkResourceName(String networkResourceName) { + this.networkResourceName = networkResourceName; + return this; + } + + public Builder setVpcResource(boolean isVpcResource) { + this.isVpcResource = isVpcResource; + return this; + } + + + public Builder setVmId(long vmId) { + this.vmId = vmId; + return this; + } + + public Builder setRuleId(long ruleId) { + this.ruleId = ruleId; + return this; + } + + public Builder setPublicIp(String publicIp) { + this.publicIp = publicIp; + return this; + } + + public Builder setVmIp(String vmIp) { + this.vmIp = vmIp; + return this; + } + + public Builder setPublicPort(String publicPort) { + this.publicPort = publicPort; + return this; + } + + public Builder setPrivatePort(String privatePort) { + this.privatePort = privatePort; + return this; + } + + public Builder setProtocol(String protocol) { + this.protocol = protocol; + return this; + } + + public Builder setAlgorithm(String algorithm) { + this.algorithm = algorithm; + return this; + } + + public Builder setMemberList(List memberList) { + this.memberList = memberList; + return this; + } + + + public Builder setAclAction(NsxRuleAction aclAction) { + this.aclAction = aclAction; + return this; + } + + public Builder setTrafficType(String trafficType) { + this.trafficType = trafficType; + return this; + } + + public Builder setIcmpType(Integer icmpType) { + this.icmpType = icmpType; + return this; + } + + public Builder setIcmpCode(Integer icmpCode) { + this.icmpCode = icmpCode; + return this; + } + + public Builder setSourceCidrList(List sourceCidrList) { + this.sourceCidrList = sourceCidrList; + return this; + } + + public Builder setDestinationCidrList(List destinationCidrList) { + this.destinationidrList = destinationCidrList; + return this; + } + + public Builder setService(Network.Service service) { + this.service = service; + return this; + } + + public NsxNetworkRule build() { + NsxNetworkRule rule = new NsxNetworkRule(); + rule.setDomainId(this.domainId); + rule.setAccountId(this.accountId); + rule.setZoneId(this.zoneId); + rule.setNetworkResourceId(this.networkResourceId); + rule.setNetworkResourceName(this.networkResourceName); + rule.setVpcResource(this.isVpcResource); + rule.setVmId(this.vmId); + rule.setVmIp(this.vmIp); + rule.setPublicIp(this.publicIp); + rule.setPublicPort(this.publicPort); + rule.setPrivatePort(this.privatePort); + rule.setProtocol(this.protocol); + rule.setRuleId(this.ruleId); + rule.setAlgorithm(this.algorithm); + rule.setMemberList(this.memberList); + rule.setAclAction(this.aclAction); + rule.setIcmpType(this.icmpType); + rule.setIcmpCode(this.icmpCode); + rule.setSourceCidrList(this.sourceCidrList); + rule.setDestinationCidrList(this.destinationidrList); + rule.setTrafficType(this.trafficType); + rule.setService(service); + return rule; + } + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java new file mode 100644 index 00000000000..bb411249b88 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java @@ -0,0 +1,129 @@ +// 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.cloud.network.vpc.VpcVO; + +import java.util.Objects; + +public class NsxOpObject { + VpcVO vpcVO; + NetworkVO networkVO; + long accountId; + long domainId; + long zoneId; + + public VpcVO getVpcVO() { + return vpcVO; + } + + public void setVpcVO(VpcVO vpcVO) { + this.vpcVO = vpcVO; + } + + public NetworkVO getNetworkVO() { + return networkVO; + } + + public void setNetworkVO(NetworkVO networkVO) { + this.networkVO = networkVO; + } + + public long getAccountId() { + return accountId; + } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + + public long getDomainId() { + return domainId; + } + + public void setDomainId(long domainId) { + this.domainId = domainId; + } + + public long getZoneId() { + return zoneId; + } + + public void setZoneId(long zoneId) { + this.zoneId = zoneId; + } + + public String getNetworkResourceName() { + return Objects.nonNull(vpcVO) ? vpcVO.getName() : networkVO.getName(); + } + + public boolean isVpcResource() { + return Objects.nonNull(vpcVO); + } + + public long getNetworkResourceId() { + return Objects.nonNull(vpcVO) ? vpcVO.getId() : networkVO.getId(); + } + + public static final class Builder { + VpcVO vpcVO; + NetworkVO networkVO; + long accountId; + long domainId; + long zoneId; + + public Builder() { + // Default constructor + } + + public Builder vpcVO(VpcVO vpcVO) { + this.vpcVO = vpcVO; + return this; + } + + public Builder networkVO(NetworkVO networkVO) { + this.networkVO = networkVO; + return this; + } + + public Builder domainId(long domainId) { + this.domainId = domainId; + return this; + } + + public Builder accountId(long accountId) { + this.accountId = accountId; + return this; + } + + public Builder zoneId(long zoneId) { + this.zoneId = zoneId; + return this; + } + + public NsxOpObject build() { + NsxOpObject object = new NsxOpObject(); + object.setVpcVO(this.vpcVO); + object.setNetworkVO(this.networkVO); + object.setDomainId(this.domainId); + object.setAccountId(this.accountId); + object.setZoneId(this.zoneId); + return object; + } + } +} 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 new file mode 100644 index 00000000000..cd1d481b9f8 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java @@ -0,0 +1,486 @@ +// 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.agent.IAgentControl; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +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.host.Host; +import com.cloud.network.Network; +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.model.Segment; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.StartupNsxCommand; +import org.apache.cloudstack.agent.api.CreateNsxDhcpRelayConfigCommand; +import org.apache.cloudstack.agent.api.CreateNsxDistributedFirewallRulesCommand; +import org.apache.cloudstack.agent.api.CreateNsxLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.CreateNsxPortForwardRuleCommand; +import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand; +import org.apache.cloudstack.agent.api.CreateNsxStaticNatCommand; +import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxDistributedFirewallRulesCommand; +import org.apache.cloudstack.agent.api.DeleteNsxLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand; +import org.apache.cloudstack.agent.api.DeleteNsxNatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand; +import org.apache.cloudstack.service.NsxApiClient; +import org.apache.cloudstack.utils.NsxControllerUtils; +import org.apache.commons.collections.CollectionUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +public class NsxResource implements ServerResource { + protected Logger logger = LogManager.getLogger(getClass()); + private static final String DHCP_RELAY_CONFIGS_PATH_PREFIX = "/infra/dhcp-relay-configs"; + + private String name; + protected String hostname; + protected String username; + protected String password; + protected String guid; + protected String port; + protected String tier0Gateway; + protected String edgeCluster; + protected String transportZone; + protected String zoneId; + + protected NsxApiClient nsxApiClient; + + @Override + public Host.Type getType() { + return Host.Type.Routing; + } + @Override + public StartupCommand[] initialize() { + StartupNsxCommand sc = new StartupNsxCommand(); + sc.setGuid(guid); + sc.setName(name); + sc.setDataCenter(zoneId); + sc.setPod(""); + sc.setPrivateIpAddress(""); + sc.setStorageIpAddress(""); + sc.setVersion(""); + return new StartupCommand[] {sc}; + } + + @Override + public PingCommand getCurrentStatus(long id) { + return null; + } + + @Override + public Answer executeRequest(Command cmd) { + if (cmd instanceof ReadyCommand) { + return executeRequest((ReadyCommand) cmd); + } else if (cmd instanceof DeleteNsxTier1GatewayCommand) { + return executeRequest((DeleteNsxTier1GatewayCommand) cmd); + } else if (cmd instanceof DeleteNsxSegmentCommand) { + return executeRequest((DeleteNsxSegmentCommand) cmd); + } else if (cmd instanceof CreateNsxSegmentCommand) { + return executeRequest((CreateNsxSegmentCommand) cmd); + } else if (cmd instanceof CreateNsxTier1GatewayCommand) { + return executeRequest((CreateNsxTier1GatewayCommand) cmd); + } else if (cmd instanceof CreateNsxDhcpRelayConfigCommand) { + return executeRequest((CreateNsxDhcpRelayConfigCommand) cmd); + } else if (cmd instanceof CreateOrUpdateNsxTier1NatRuleCommand) { + return executeRequest((CreateOrUpdateNsxTier1NatRuleCommand) cmd); + } else if (cmd instanceof CreateNsxStaticNatCommand) { + return executeRequest((CreateNsxStaticNatCommand) cmd); + } else if (cmd instanceof DeleteNsxNatRuleCommand) { + return executeRequest((DeleteNsxNatRuleCommand) cmd); + } else if (cmd instanceof CreateNsxPortForwardRuleCommand) { + return executeRequest((CreateNsxPortForwardRuleCommand) cmd); + } else if (cmd instanceof CreateNsxLoadBalancerRuleCommand) { + return executeRequest((CreateNsxLoadBalancerRuleCommand) cmd); + } else if (cmd instanceof DeleteNsxLoadBalancerRuleCommand) { + return executeRequest((DeleteNsxLoadBalancerRuleCommand) cmd); + } else if (cmd instanceof DeleteNsxDistributedFirewallRulesCommand) { + return executeRequest((DeleteNsxDistributedFirewallRulesCommand) cmd); + } else if (cmd instanceof CreateNsxDistributedFirewallRulesCommand) { + return executeRequest((CreateNsxDistributedFirewallRulesCommand) cmd); + } else { + return Answer.createUnsupportedCommandAnswer(cmd); + } + } + + @Override + public void disconnected() { + // Do nothing + } + + @Override + public IAgentControl getAgentControl() { + return null; + } + + @Override + public void setAgentControl(IAgentControl agentControl) { + // Do nothing + } + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public void setConfigParams(Map params) { + // Do nothing + } + + @Override + public Map getConfigParams() { + return new HashMap<>(); + } + + @Override + public int getRunLevel() { + return 0; + } + + @Override + public void setRunLevel(int level) { + // Do nothing + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + hostname = (String) params.get("hostname"); + if (hostname == null) { + throw new ConfigurationException("Missing NSX hostname from params: " + params); + } + + port = (String) params.get("port"); + if (port == null) { + throw new ConfigurationException("Missing NSX port from params: " + params); + } + + username = (String) params.get("username"); + if (username == null) { + throw new ConfigurationException("Missing NSX username from params: " + params); + } + + password = (String) params.get("password"); + if (password == null) { + throw new ConfigurationException("Missing NSX password from params: " + params); + } + + this.name = (String) params.get("name"); + if (this.name == null) { + throw new ConfigurationException("Unable to find name"); + } + + guid = (String) params.get("guid"); + if (guid == null) { + throw new ConfigurationException("Unable to find the guid"); + } + + zoneId = (String) params.get("zoneId"); + if (zoneId == null) { + throw new ConfigurationException("Unable to find zone"); + } + + tier0Gateway = (String) params.get("tier0Gateway"); + if (tier0Gateway == null) { + throw new ConfigurationException("Missing NSX tier0 gateway"); + } + + edgeCluster = (String) params.get("edgeCluster"); + if (edgeCluster == null) { + throw new ConfigurationException("Missing NSX edgeCluster"); + } + + transportZone = (String) params.get("transportZone"); + if (transportZone == null) { + throw new ConfigurationException("Missing NSX transportZone"); + } + + nsxApiClient = new NsxApiClient(hostname, port, username, password.toCharArray()); + return true; + } + + private Answer executeRequest(CreateOrUpdateNsxTier1NatRuleCommand cmd) { + String tier1GatewayName = cmd.getTier1GatewayName(); + String action = cmd.getAction(); + String translatedIpAddress = cmd.getTranslatedIpAddress(); + String natRuleId = cmd.getNatRuleId(); + String natId = "USER"; + try { + nsxApiClient.createTier1NatRule(tier1GatewayName, natId, natRuleId, action, translatedIpAddress); + } catch (CloudRuntimeException e) { + String msg = String.format("Error creating the NAT rule with ID %s on Tier1 Gateway %s: %s", natRuleId, tier1GatewayName, e.getMessage()); + logger.error(msg, e); + return new NsxAnswer(cmd, e); + } + return new NsxAnswer(cmd, true, ""); + } + + private Answer executeRequest(CreateNsxDhcpRelayConfigCommand cmd) { + long datacenterId = 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 = NsxControllerUtils.getNsxDhcpRelayConfigId(datacenterId, 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 { + 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 = NsxControllerUtils.getNsxSegmentId(domainId, accountId, datacenterId, vpcId, networkId); + String dhcpConfigPath = String.format("%s/%s", DHCP_RELAY_CONFIGS_PATH_PREFIX, dhcpRelayConfigName); + try { + Segment segment = nsxApiClient.getSegmentById(segmentName); + segment.setDhcpConfigPath(dhcpConfigPath); + 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, e); + } + + return new NsxAnswer(cmd, true, ""); + } + + private Answer executeRequest(ReadyCommand cmd) { + return new ReadyAnswer(cmd); + } + + private Answer executeRequest(CreateNsxTier1GatewayCommand cmd) { + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), cmd.getNetworkResourceId(), cmd.isResourceVpc()); + boolean sourceNatEnabled = cmd.isSourceNatEnabled(); + try { + nsxApiClient.createTier1Gateway(tier1GatewayName, tier0Gateway, edgeCluster, sourceNatEnabled); + return new NsxAnswer(cmd, true, ""); + } catch (CloudRuntimeException e) { + String msg = String.format("Cannot create tier 1 gateway %s (%s: %s): %s", tier1GatewayName, + (cmd.isResourceVpc() ? "VPC" : "NETWORK"), cmd.getNetworkResourceName(), e.getMessage()); + logger.error(msg); + return new NsxAnswer(cmd, e); + } + } + + private Answer executeRequest(DeleteNsxTier1GatewayCommand cmd) { + String tier1Id = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), cmd.getNetworkResourceId(), cmd.isResourceVpc()); + String lbName = NsxControllerUtils.getLoadBalancerName(tier1Id); + try { + nsxApiClient.deleteLoadBalancer(lbName); + nsxApiClient.deleteTier1Gateway(tier1Id); + } catch (Exception e) { + return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); + } + return new NsxAnswer(cmd, true, null); + } + + private Answer executeRequest(CreateNsxSegmentCommand cmd) { + try { + String siteId = nsxApiClient.getDefaultSiteId(); + String enforcementPointPath = nsxApiClient.getDefaultEnforcementPointPath(siteId); + TransportZoneListResult transportZoneListResult = nsxApiClient.getTransportZones(); + if (CollectionUtils.isEmpty(transportZoneListResult.getResults())) { + String errorMsg = String.format("Failed to create network: %s as no transport zones were found in the linked NSX infrastructure", cmd.getNetworkName()); + 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.isEmpty(transportZones)) { + String errorMsg = String.format("Failed to create network: %s as no transport zone of name %s was found in the linked NSX infrastructure", cmd.getNetworkName(), transportZone); + logger.error(errorMsg); + return new NsxAnswer(cmd, new CloudRuntimeException(errorMsg)); + } + + String segmentName = NsxControllerUtils.getNsxSegmentId(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), cmd.getVpcId(), cmd.getNetworkId()); + String gatewayAddress = cmd.getNetworkGateway() + "/" + cmd.getNetworkCidr().split("/")[1]; + + Long networkResourceId = Objects.isNull(cmd.getVpcId()) ? cmd.getNetworkId() : cmd.getVpcId(); + boolean isResourceVpc = !Objects.isNull(cmd.getVpcId()); + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), + cmd.getZoneId(), networkResourceId, isResourceVpc); + nsxApiClient.createSegment(segmentName, tier1GatewayName, gatewayAddress, enforcementPointPath, transportZones); + nsxApiClient.createGroupForSegment(segmentName); + } catch (Exception e) { + 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 { + 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: %s", segmentName, e.getMessage())); + return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); + } + return new NsxAnswer(cmd, true, null); + } + + private NsxAnswer executeRequest(CreateNsxStaticNatCommand cmd) { + String staticNatRuleName = NsxControllerUtils.getStaticNatRuleName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), + cmd.getNetworkResourceId(), cmd.isResourceVpc()); + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), + cmd.getNetworkResourceId(), cmd.isResourceVpc()); + try { + nsxApiClient.createStaticNatRule(cmd.getNetworkResourceName(), tier1GatewayName, staticNatRuleName, cmd.getPublicIp(), cmd.getVmIp()); + } catch (Exception e) { + logger.error(String.format("Failed to add NSX static NAT rule %s for network: %s", staticNatRuleName, cmd.getNetworkResourceName())); + return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); + } + return new NsxAnswer(cmd, true, null); + } + + private NsxAnswer executeRequest(CreateNsxPortForwardRuleCommand cmd) { + String ruleName = NsxControllerUtils.getPortForwardRuleName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), + cmd.getNetworkResourceId(), cmd.getRuleId(), cmd.isResourceVpc()); + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), + cmd.getNetworkResourceId(), cmd.isResourceVpc()); + try { + String privatePort = cmd.getPrivatePort(); + String service = privatePort.contains("-") ? nsxApiClient.getServicePath(ruleName, privatePort, cmd.getProtocol(), null, null) : + nsxApiClient.getNsxInfraServices(ruleName, privatePort, cmd.getProtocol(), null, null); + if (nsxApiClient.doesPfRuleExist(ruleName, tier1GatewayName)) { + logger.debug(String.format("Port forward rule for port: %s exits on NSX, not adding it again", privatePort)); + return new NsxAnswer(cmd, true, null); + } + nsxApiClient.createPortForwardingRule(ruleName, tier1GatewayName, cmd.getNetworkResourceName(), cmd.getPublicIp(), + cmd.getVmIp(), cmd.getPublicPort(), service); + } catch (Exception e) { + logger.error(String.format("Failed to add NSX port forward rule %s for network: %s", ruleName, cmd.getNetworkResourceName())); + return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); + } + return new NsxAnswer(cmd, true, null); + } + + private NsxAnswer executeRequest(DeleteNsxNatRuleCommand cmd) { + String ruleName = null; + if (cmd.getService() == Network.Service.StaticNat) { + ruleName = NsxControllerUtils.getStaticNatRuleName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), + cmd.getNetworkResourceId(), cmd.isResourceVpc()); + } else if (cmd.getService() == Network.Service.PortForwarding) { + ruleName = NsxControllerUtils.getPortForwardRuleName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), + cmd.getNetworkResourceId(), cmd.getRuleId(), cmd.isResourceVpc()); + } + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), + cmd.getNetworkResourceId(), cmd.isResourceVpc()); + try { + nsxApiClient.deleteNatRule(cmd.getService(), cmd.getPrivatePort(), cmd.getProtocol(), + cmd.getNetworkResourceName(), tier1GatewayName, ruleName); + } catch (Exception e) { + logger.error(String.format("Failed to add NSX static NAT rule %s for network: %s", ruleName, cmd.getNetworkResourceName())); + return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); + } + return new NsxAnswer(cmd, true, null); + } + + private NsxAnswer executeRequest(CreateNsxLoadBalancerRuleCommand cmd) { + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), + cmd.getNetworkResourceId(), cmd.isResourceVpc()); + String ruleName = NsxControllerUtils.getLoadBalancerRuleName(tier1GatewayName, cmd.getLbId()); + try { + nsxApiClient.createAndAddNsxLbVirtualServer(tier1GatewayName, cmd.getLbId(), cmd.getPublicIp(), cmd.getPublicPort(), + cmd.getMemberList(), cmd.getAlgorithm(), cmd.getProtocol(), cmd.getPrivatePort()); + } catch (Exception e) { + logger.error(String.format("Failed to add NSX load balancer rule %s for network: %s", ruleName, cmd.getNetworkResourceName())); + return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); + } + return new NsxAnswer(cmd, true, null); + } + + private NsxAnswer executeRequest(DeleteNsxLoadBalancerRuleCommand cmd) { + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), + cmd.getZoneId(), cmd.getNetworkResourceId(), cmd.isResourceVpc()); + String ruleName = NsxControllerUtils.getLoadBalancerRuleName(tier1GatewayName, cmd.getLbId()); + try { + nsxApiClient.deleteNsxLbResources(tier1GatewayName, cmd.getLbId()); + } catch (Exception e) { + logger.error(String.format("Failed to add NSX load balancer rule %s for network: %s", ruleName, cmd.getNetworkResourceName())); + return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); + } + return new NsxAnswer(cmd, true, null); + } + + private NsxAnswer executeRequest(CreateNsxDistributedFirewallRulesCommand cmd) { + String segmentName = NsxControllerUtils.getNsxSegmentId(cmd.getDomainId(), cmd.getAccountId(), + cmd.getZoneId(), cmd.getVpcId(), cmd.getNetworkId()); + List rules = cmd.getRules(); + try { + nsxApiClient.createSegmentDistributedFirewall(segmentName, rules); + } catch (Exception e) { + logger.error(String.format("Failed to create NSX distributed firewall %s: %s", segmentName, e.getMessage()), e); + return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); + } + return new NsxAnswer(cmd, true, null); + } + + private NsxAnswer executeRequest(DeleteNsxDistributedFirewallRulesCommand cmd) { + String segmentName = NsxControllerUtils.getNsxSegmentId(cmd.getDomainId(), cmd.getAccountId(), + cmd.getZoneId(), cmd.getVpcId(), cmd.getNetworkId()); + List rules = cmd.getRules(); + try { + nsxApiClient.deleteDistributedFirewallRules(segmentName, rules); + } catch (Exception e) { + logger.error(String.format("Failed to delete NSX distributed firewall %s: %s", segmentName, e.getMessage()), e); + return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage())); + } + return new NsxAnswer(cmd, true, null); + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } +} 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..d443b0e14e7 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java @@ -0,0 +1,1067 @@ +// 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.Network; +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.LbAppProfiles; +import com.vmware.nsx_policy.infra.LbMonitorProfiles; +import com.vmware.nsx_policy.infra.LbPools; +import com.vmware.nsx_policy.infra.LbServices; +import com.vmware.nsx_policy.infra.LbVirtualServers; +import com.vmware.nsx_policy.infra.Segments; +import com.vmware.nsx_policy.infra.Services; +import com.vmware.nsx_policy.infra.Sites; +import com.vmware.nsx_policy.infra.Tier1s; +import com.vmware.nsx_policy.infra.domains.Groups; +import com.vmware.nsx_policy.infra.domains.SecurityPolicies; +import com.vmware.nsx_policy.infra.domains.groups.members.SegmentPorts; +import com.vmware.nsx_policy.infra.domains.security_policies.Rules; +import com.vmware.nsx_policy.infra.sites.EnforcementPoints; +import com.vmware.nsx_policy.infra.tier_0s.LocaleServices; +import com.vmware.nsx_policy.infra.tier_1s.nat.NatRules; +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.Group; +import com.vmware.nsx_policy.model.GroupListResult; +import com.vmware.nsx_policy.model.ICMPTypeServiceEntry; +import com.vmware.nsx_policy.model.L4PortSetServiceEntry; +import com.vmware.nsx_policy.model.LBAppProfileListResult; +import com.vmware.nsx_policy.model.LBMonitorProfileListResult; +import com.vmware.nsx_policy.model.LBPool; +import com.vmware.nsx_policy.model.LBPoolListResult; +import com.vmware.nsx_policy.model.LBPoolMember; +import com.vmware.nsx_policy.model.LBService; +import com.vmware.nsx_policy.model.LBTcpMonitorProfile; +import com.vmware.nsx_policy.model.LBUdpMonitorProfile; +import com.vmware.nsx_policy.model.LBVirtualServer; +import com.vmware.nsx_policy.model.LBVirtualServerListResult; +import com.vmware.nsx_policy.model.LocaleServicesListResult; +import com.vmware.nsx_policy.model.PathExpression; +import com.vmware.nsx_policy.model.PolicyGroupMembersListResult; +import com.vmware.nsx_policy.model.PolicyNatRule; +import com.vmware.nsx_policy.model.PolicyNatRuleListResult; +import com.vmware.nsx_policy.model.Rule; +import com.vmware.nsx_policy.model.SecurityPolicy; +import com.vmware.nsx_policy.model.Segment; +import com.vmware.nsx_policy.model.SegmentSubnet; +import com.vmware.nsx_policy.model.ServiceListResult; +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.Structure; +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.resource.NsxLoadBalancerMember; +import org.apache.cloudstack.resource.NsxNetworkRule; +import org.apache.cloudstack.utils.NsxControllerUtils; +import org.apache.commons.collections.CollectionUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.apache.cloudstack.utils.NsxControllerUtils.getServerPoolMemberName; +import static org.apache.cloudstack.utils.NsxControllerUtils.getServerPoolName; +import static org.apache.cloudstack.utils.NsxControllerUtils.getServiceName; +import static org.apache.cloudstack.utils.NsxControllerUtils.getVirtualServerName; +import static org.apache.cloudstack.utils.NsxControllerUtils.getServiceEntryName; +import static org.apache.cloudstack.utils.NsxControllerUtils.getLoadBalancerName; +import static org.apache.cloudstack.utils.NsxControllerUtils.getLoadBalancerAlgorithm; +import static org.apache.cloudstack.utils.NsxControllerUtils.getActiveMonitorProfileName; +import static org.apache.cloudstack.utils.NsxControllerUtils.getTier1GatewayName; + +public class NsxApiClient { + + protected ApiClient apiClient; + protected Function, Service> nsxService; + + public static final int RESPONSE_TIMEOUT_SECONDS = 60; + protected Logger logger = LogManager.getLogger(getClass()); + + // 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/"; + protected static final String SEGMENTS_PATH = "/infra/segments"; + protected static final String DEFAULT_DOMAIN = "default"; + protected static final String GROUPS_PATH_PREFIX = "/infra/domains/default/groups"; + // TODO: Pass as global / zone-level setting? + protected static final String NSX_LB_PASSIVE_MONITOR = "/infra/lb-monitor-profiles/default-passive-lb-monitor"; + protected static final String TCP_MONITOR_PROFILE = "LBTcpMonitorProfile"; + protected static final String UDP_MONITOR_PROFILE = "LBUdpMonitorProfile"; + protected static final String NAT_ID = "USER"; + + private enum PoolAllocation { ROUTING, LB_SMALL, LB_MEDIUM, LB_LARGE, LB_XLARGE } + + private enum HAMode { ACTIVE_STANDBY, ACTIVE_ACTIVE } + + private enum FailoverMode { PREEMPTIVE, NON_PREEMPTIVE } + + private enum AdminState { UP, DOWN } + + private enum TransportType { OVERLAY, VLAN } + + private enum NatId { USER, INTERNAL, DEFAULT } + + private enum NatAction {SNAT, DNAT, REFLEXIVE} + + private enum FirewallMatch { + MATCH_INTERNAL_ADDRESS, + MATCH_EXTERNAL_ADDRESS, + BYPASS + } + + public enum LBAlgorithm { + ROUND_ROBIN, + LEAST_CONNECTION, + IP_HASH + } + + private enum LBSize { + SMALL, + MEDIUM, + LARGE, + XLARGE + } + + private enum FirewallActions { + ALLOW, + DROP, + REJECT, + JUMP_TO_APPLICATION + } + + public enum RouteAdvertisementType { TIER1_STATIC_ROUTES, TIER1_CONNECTED, TIER1_NAT, + TIER1_LB_VIP, TIER1_LB_SNAT, TIER1_DNS_FORWARDER_IP, TIER1_IPSEC_LOCAL_ENDPOINT + } + + protected NsxApiClient() { + } + + 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 = ApiClients.newRestClient(controllerUrl, config); + nsxService = apiClient::createStub; + } + + public void createTier1NatRule(String tier1GatewayName, String natId, String natRuleId, + String action, String translatedIp) { + NatRules natRulesService = (NatRules) nsxService.apply(NatRules.class); + PolicyNatRule natPolicy = new PolicyNatRule.Builder() + .setAction(action) + .setTranslatedNetwork(translatedIp) + .build(); + natRulesService.patch(tier1GatewayName, natId, natRuleId, natPolicy); + } + + 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)); + } + } + + private List getRouterAdvertisementTypeList(boolean sourceNatEnabled) { + List types = new ArrayList<>(); + types.add(RouteAdvertisementType.TIER1_IPSEC_LOCAL_ENDPOINT.name()); + types.add(RouteAdvertisementType.TIER1_LB_VIP.name()); + types.add(RouteAdvertisementType.TIER1_NAT.name()); + if (!sourceNatEnabled) { + types.add(RouteAdvertisementType.TIER1_CONNECTED.name()); + } + return types; + } + + public void createTier1Gateway(String name, String tier0Gateway, String edgeCluster, boolean sourceNatEnabled) throws CloudRuntimeException { + String tier0GatewayPath = TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway; + Tier1 tier1 = getTier1Gateway(name); + if (tier1 != null) { + logger.info(String.format("VPC network with name %s exists in NSX zone", name)); + return; + } + + List routeAdvertisementTypes = getRouterAdvertisementTypeList(sourceNatEnabled); + + 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(routeAdvertisementTypes) + .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); + if (getTier1Gateway(tier1Id) == null) { + logger.warn(String.format("The Tier 1 Gateway %s does not exist, cannot be removed", tier1Id)); + return; + } + removeTier1GatewayNatRules(tier1Id); + localeService.delete(tier1Id, TIER_1_LOCALE_SERVICE_ID); + Tier1s tier1service = (Tier1s) nsxService.apply(Tier1s.class); + tier1service.delete(tier1Id); + } + + private void removeTier1GatewayNatRules(String tier1Id) { + NatRules natRulesService = (NatRules) nsxService.apply(NatRules.class); + PolicyNatRuleListResult result = natRulesService.list(tier1Id, NAT_ID, null, false, null, null, null, null); + List natRules = result.getResults(); + if (CollectionUtils.isEmpty(natRules)) { + logger.debug(String.format("Didn't find any NAT rule to remove on the Tier 1 Gateway %s", tier1Id)); + } else { + for (PolicyNatRule natRule : natRules) { + logger.debug(String.format("Removing NAT rule %s from Tier 1 Gateway %s", natRule.getId(), tier1Id)); + natRulesService.delete(tier1Id, NAT_ID, natRule.getId()); + } + } + + } + + public String getDefaultSiteId() { + SiteListResult sites = getSites(); + if (CollectionUtils.isEmpty(sites.getResults())) { + String errorMsg = "No sites are found in the linked NSX infrastructure"; + logger.error(errorMsg); + throw new CloudRuntimeException(errorMsg); + } + return sites.getResults().get(0).getId(); + } + + protected 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 sites list due to %s", e.getMessage())); + } + } + + public String getDefaultEnforcementPointPath(String siteId) { + EnforcementPointListResult epList = getEnforcementPoints(siteId); + if (CollectionUtils.isEmpty(epList.getResults())) { + String errorMsg = String.format("No enforcement points are found in the linked NSX infrastructure for site ID %s", siteId); + logger.error(errorMsg); + throw new CloudRuntimeException(errorMsg); + } + return epList.getResults().get(0).getPath(); + } + + protected 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 enforcement points 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, null, null, null, null, TransportType.OVERLAY.name(), null); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to fetch transport zones due to %s", e.getMessage())); + } + } + + public void createSegment(String segmentName, String tier1GatewayName, String gatewayAddress, 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(TIER_1_GATEWAY_PATH_PREFIX + tier1GatewayName) + .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 { + removeSegmentDistributedFirewallRules(segmentName); + if (Objects.isNull(vpcId)) { + String t1GatewayName = getTier1GatewayName(domainId, accountId, zoneId, networkId, false); + deleteLoadBalancer(getLoadBalancerName(t1GatewayName)); + } + removeSegment(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); + } + } + + protected void removeSegment(String segmentName) { + logger.debug(String.format("Removing the segment with ID %s", segmentName)); + Segments segmentService = (Segments) nsxService.apply(Segments.class); + String errMsg = String.format("The segment with ID %s is not found, skipping removal", segmentName); + try { + Segment segment = segmentService.get(segmentName); + if (segment == null) { + logger.warn(errMsg); + return; + } + } catch (Exception e) { + logger.warn(errMsg); + return; + } + String siteId = getDefaultSiteId(); + String enforcementPointPath = getDefaultEnforcementPointPath(siteId); + SegmentPorts segmentPortsService = (SegmentPorts) nsxService.apply(SegmentPorts.class); + PolicyGroupMembersListResult segmentPortsList = getSegmentPortList(segmentPortsService, segmentName, enforcementPointPath); + Long portCount = segmentPortsList.getResultCount(); + portCount = retrySegmentDeletion(segmentPortsService, portCount, segmentName, enforcementPointPath); + logger.info("Port count: " + portCount); + if (portCount == 0L) { + logger.debug(String.format("Removing the segment with ID %s", segmentName)); + removeGroupForSegment(segmentName); + segmentService.delete(segmentName); + } else { + String msg = String.format("Cannot remove the NSX segment %s because there are still %s port group(s) attached to it", segmentName, portCount); + logger.debug(msg); + throw new CloudRuntimeException(msg); + } + } + + private PolicyGroupMembersListResult getSegmentPortList(SegmentPorts segmentPortsService, String segmentName, String enforcementPointPath) { + return segmentPortsService.list(DEFAULT_DOMAIN, segmentName, null, enforcementPointPath, + false, null, 50L, false, null); + } + + private Long retrySegmentDeletion(SegmentPorts segmentPortsService, Long portCount, String segmentName, String enforcementPointPath) { + int retries = 20; + int count = 1; + do { + try { + logger.info("Waiting for all port groups to be unlinked from the segment - Attempt: " + count++ + " Waiting for 5 secs"); + Thread.sleep(5000); + portCount = getSegmentPortList(segmentPortsService, segmentName, enforcementPointPath).getResultCount(); + retries--; + } catch (InterruptedException e) { + throw new CloudRuntimeException(String.format("Unable to delete segment %s due to: %s", segmentName, e.getLocalizedMessage())); + } + } while (retries > 0 && portCount > 0); + return portCount; + } + + public void createStaticNatRule(String vpcName, String tier1GatewayName, + String ruleName, String publicIp, String vmIp) { + try { + NatRules natService = (NatRules) nsxService.apply(NatRules.class); + PolicyNatRule rule = new PolicyNatRule.Builder() + .setId(ruleName) + .setDisplayName(ruleName) + .setAction(NatAction.DNAT.name()) + .setFirewallMatch(FirewallMatch.MATCH_INTERNAL_ADDRESS.name()) + .setDestinationNetwork(publicIp) + .setTranslatedNetwork(vmIp) + .setEnabled(true) + .build(); + + logger.debug(String.format("Creating NSX static NAT rule %s for tier-1 gateway %s (VPC: %s)", ruleName, tier1GatewayName, vpcName)); + natService.patch(tier1GatewayName, NatId.USER.name(), ruleName, rule); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Error creating NSX Static NAT rule %s for tier-1 gateway %s (VPC: %s), due to %s", + ruleName, tier1GatewayName, vpcName, ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public void deleteNatRule(Network.Service service, String privatePort, String protocol, String networkName, String tier1GatewayName, String ruleName) { + try { + NatRules natService = (NatRules) nsxService.apply(NatRules.class); + logger.debug(String.format("Deleting NSX static NAT rule %s for tier-1 gateway %s (network: %s)", ruleName, tier1GatewayName, networkName)); + // delete NAT rule + natService.delete(tier1GatewayName, NatId.USER.name(), ruleName); + if (service == Network.Service.PortForwarding) { + String svcName = getServiceName(ruleName, privatePort, protocol, null, null); + // Delete service + Services services = (Services) nsxService.apply(Services.class); + services.delete(svcName); + } + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to delete NSX Static NAT rule %s for tier-1 gateway %s (VPC: %s), due to %s", + ruleName, tier1GatewayName, networkName, ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public void createPortForwardingRule(String ruleName, String tier1GatewayName, String networkName, String publicIp, + String vmIp, String publicPort, String service) { + try { + NatRules natService = (NatRules) nsxService.apply(NatRules.class); + logger.debug(String.format("Creating NSX Port-Forwarding NAT %s for network %s", ruleName, networkName)); + PolicyNatRule rule = new PolicyNatRule.Builder() + .setId(ruleName) + .setDisplayName(ruleName) + .setAction(NatAction.DNAT.name()) + .setFirewallMatch(FirewallMatch.MATCH_INTERNAL_ADDRESS.name()) + .setDestinationNetwork(publicIp) + .setTranslatedNetwork(vmIp) + .setTranslatedPorts(String.valueOf(publicPort)) + .setService(service) + .setEnabled(true) + .build(); + natService.patch(tier1GatewayName, NatId.USER.name(), ruleName, rule); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to add NSX Port-forward rule %s for network: %s, due to %s", + ruleName, networkName, ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public boolean doesPfRuleExist(String ruleName, String tier1GatewayName) { + try { + NatRules natService = (NatRules) nsxService.apply(NatRules.class); + PolicyNatRule rule = natService.get(tier1GatewayName, NAT_ID, ruleName); + return !Objects.isNull(rule); + } catch (Error error) { + logger.debug(String.format("Found a port forward rule named: %s on NSX", ruleName)); + return false; + } + } + + List getLbPoolMembers(List memberList, String tier1GatewayName) { + List members = new ArrayList<>(); + for (NsxLoadBalancerMember member : memberList) { + try { + String serverPoolMemberName = getServerPoolMemberName(tier1GatewayName, member.getVmId()); + LBPoolMember lbPoolMember = new LBPoolMember.Builder() + .setDisplayName(serverPoolMemberName) + .setIpAddress(member.getVmIp()) + .setPort(String.valueOf(member.getPort())) + .build(); + members.add(lbPoolMember); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to create NSX LB pool members, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + return members; + } + public void createNsxLbServerPool(List memberList, String tier1GatewayName, String lbServerPoolName, + String algorithm, String privatePort, String protocol) { + try { + String activeMonitorPath = getLbActiveMonitorPath(lbServerPoolName, privatePort, protocol); + List members = getLbPoolMembers(memberList, tier1GatewayName); + LbPools lbPools = (LbPools) nsxService.apply(LbPools.class); + LBPool lbPool = new LBPool.Builder() + .setId(lbServerPoolName) + .setDisplayName(lbServerPoolName) + .setAlgorithm(getLoadBalancerAlgorithm(algorithm)) + .setMembers(members) + .setPassiveMonitorPath(NSX_LB_PASSIVE_MONITOR) + .setActiveMonitorPaths(List.of(activeMonitorPath)) + .build(); + lbPools.patch(lbServerPoolName, lbPool); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to create NSX LB server pool, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + private String getLbActiveMonitorPath(String lbServerPoolName, String port, String protocol) { + LbMonitorProfiles lbActiveMonitor = (LbMonitorProfiles) nsxService.apply(LbMonitorProfiles.class); + String lbMonitorProfileId = getActiveMonitorProfileName(lbServerPoolName, port, protocol); + if ("TCP".equals(protocol.toUpperCase(Locale.ROOT))) { + LBTcpMonitorProfile lbTcpMonitorProfile = new LBTcpMonitorProfile.Builder(TCP_MONITOR_PROFILE) + .setDisplayName(lbMonitorProfileId) + .setMonitorPort(Long.parseLong(port)) + .build(); + lbActiveMonitor.patch(lbMonitorProfileId, lbTcpMonitorProfile); + } else if ("UDP".equals(protocol.toUpperCase(Locale.ROOT))) { + LBUdpMonitorProfile lbUdpMonitorProfile = new LBUdpMonitorProfile.Builder(UDP_MONITOR_PROFILE) + .setDisplayName(lbMonitorProfileId) + .setMonitorPort(Long.parseLong(port)) + .setSend("") + .setReceive("") + .build(); + lbActiveMonitor.patch(lbMonitorProfileId, lbUdpMonitorProfile); + } + + LBMonitorProfileListResult listResult = listLBActiveMonitors(lbActiveMonitor); + Optional monitorProfile = listResult.getResults().stream().filter(profile -> profile._getDataValue().getField("id").toString().equals(lbMonitorProfileId)).findFirst(); + return monitorProfile.map(structure -> structure._getDataValue().getField("path").toString()).orElse(null); + } + + LBMonitorProfileListResult listLBActiveMonitors(LbMonitorProfiles lbActiveMonitor) { + return lbActiveMonitor.list(null, false, null, null, null, null); + } + + public void createNsxLoadBalancer(String tier1GatewayName) { + try { + String lbName = getLoadBalancerName(tier1GatewayName); + LbServices lbServices = (LbServices) nsxService.apply(LbServices.class); + LBService lbService = getLbService(lbName); + if (Objects.nonNull(lbService)) { + return; + } + lbService = new LBService.Builder() + .setId(lbName) + .setDisplayName(lbName) + .setEnabled(true) + .setSize(LBSize.SMALL.name()) + .setConnectivityPath(TIER_1_GATEWAY_PATH_PREFIX + tier1GatewayName) + .build(); + lbServices.patch(lbName, lbService); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to create NSX load balancer, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public void createAndAddNsxLbVirtualServer(String tier1GatewayName, long lbId, String publicIp, String publicPort, + List memberList, String algorithm, String protocol, String privatePort) { + try { + String lbServerPoolName = getServerPoolName(tier1GatewayName, lbId); + createNsxLbServerPool(memberList, tier1GatewayName, lbServerPoolName, algorithm, privatePort, protocol); + createNsxLoadBalancer(tier1GatewayName); + + String lbVirtualServerName = getVirtualServerName(tier1GatewayName, lbId); + String lbServiceName = getLoadBalancerName(tier1GatewayName); + LbVirtualServers lbVirtualServers = (LbVirtualServers) nsxService.apply(LbVirtualServers.class); + if (Objects.nonNull(getLbVirtualServerService(lbVirtualServers, lbServiceName))) { + return; + } + LBVirtualServer lbVirtualServer = new LBVirtualServer.Builder() + .setId(lbVirtualServerName) + .setDisplayName(lbVirtualServerName) + .setApplicationProfilePath(getLbProfileForProtocol(protocol)) + .setIpAddress(publicIp) + .setLbServicePath(getLbPath(lbServiceName)) + .setPoolPath(getLbPoolPath(lbServerPoolName)) + .setPorts(List.of(publicPort)) + .build(); + lbVirtualServers.patch(lbVirtualServerName, lbVirtualServer); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to create and add NSX virtual server to the Load Balancer, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + private LBVirtualServer getLbVirtualServerService(LbVirtualServers lbVirtualServers, String lbVSName) { + try { + LBVirtualServer lbVirtualServer = lbVirtualServers.get(lbVSName); + if (Objects.nonNull(lbVirtualServer)) { + return lbVirtualServer; + } + } catch (Exception e) { + logger.debug(String.format("Found an LB virtual server named: %s on NSX", lbVSName)); + return null; + } + return null; + } + + public void deleteNsxLbResources(String tier1GatewayName, long lbId) { + try { + // Delete associated Virtual servers + LbVirtualServers lbVirtualServers = (LbVirtualServers) nsxService.apply(LbVirtualServers.class); + String lbVirtualServerName = getVirtualServerName(tier1GatewayName, lbId); + lbVirtualServers.delete(lbVirtualServerName, false); + + // Delete LB pool + LbPools lbPools = (LbPools) nsxService.apply(LbPools.class); + String lbServerPoolName = getServerPoolName(tier1GatewayName, lbId); + lbPools.delete(lbServerPoolName, false); + + // delete associated LB Active monitor profile + LbMonitorProfiles lbActiveMonitor = (LbMonitorProfiles) nsxService.apply(LbMonitorProfiles.class); + LBMonitorProfileListResult listResult = listLBActiveMonitors(lbActiveMonitor); + List profileIds = listResult.getResults().stream().filter(profile -> profile._getDataValue().getField("id").toString().contains(lbServerPoolName)) + .map(profile -> profile._getDataValue().getField("id").toString()).collect(Collectors.toList()); + for(String profileId : profileIds) { + lbActiveMonitor.delete(profileId, true); + } + // Delete load balancer + LBVirtualServerListResult lbVsListResult = lbVirtualServers.list(null, null, null, null, null, null); + LBPoolListResult lbPoolListResult = lbPools.list(null, null, null, null, null, null); + if (CollectionUtils.isEmpty(lbVsListResult.getResults()) && CollectionUtils.isEmpty(lbPoolListResult.getResults())) { + String lbName = getLoadBalancerName(tier1GatewayName); + deleteLoadBalancer(lbName); + } + + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to delete NSX Load Balancer resources, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public void deleteLoadBalancer(String lbName) { + LbServices lbServices = (LbServices) nsxService.apply(LbServices.class); + lbServices.delete(lbName, true); + } + + private String getLbPoolPath(String lbPoolName) { + try { + LbPools lbPools = (LbPools) nsxService.apply(LbPools.class); + LBPool lbPool = lbPools.get(lbPoolName); + return Objects.nonNull(lbPool) ? lbPool.getPath() : null; + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to get NSX LB server pool, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + private LBService getLbService(String lbName) { + try { + LbServices lbServices = (LbServices) nsxService.apply(LbServices.class); + LBService lbService = lbServices.get(lbName); + if (Objects.nonNull(lbService)) { + return lbService; + } + } catch (Exception e) { + return null; + } + return null; + } + + private String getLbPath(String lbServiceName) { + try { + LbServices lbServices = (LbServices) nsxService.apply(LbServices.class); + LBService lbService = lbServices.get(lbServiceName); + return Objects.nonNull(lbService) ? lbService.getPath() : null; + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to get NSX LB server pool, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + private String getLbProfileForProtocol(String protocol) { + try { + LbAppProfiles lbAppProfiles = (LbAppProfiles) nsxService.apply(LbAppProfiles.class); + LBAppProfileListResult lbAppProfileListResults = lbAppProfiles.list(null, null, + null, null, null, null); + Optional appProfile = lbAppProfileListResults.getResults().stream().filter(profile -> profile._getDataValue().getField("path").toString().contains(protocol.toLowerCase(Locale.ROOT))).findFirst(); + return appProfile.map(structure -> structure._getDataValue().getField("path").toString()).orElse(null); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to list NSX LB App profiles, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public String getNsxInfraServices(String ruleName, String port, String protocol, Integer icmpType, Integer icmpCode) { + try { + Services service = (Services) nsxService.apply(Services.class); + + // Find default service if present + ServiceListResult serviceList = service.list(null, true, false, null, null, null, null); + + List services = serviceList.getResults(); + List matchedDefaultSvc = services.parallelStream().filter(svc -> + (svc.getServiceEntries().get(0)._getDataValue().getField("resource_type").toString().equals("L4PortSetServiceEntry")) && + svc.getServiceEntries().get(0)._getDataValue().getField("destination_ports").toString().equals("["+port+"]") + && svc.getServiceEntries().get(0)._getDataValue().getField("l4_protocol").toString().equals(protocol)) + .map(svc -> svc.getServiceEntries().get(0)._getDataValue().getField("parent_path").toString()) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(matchedDefaultSvc)) { + return matchedDefaultSvc.get(0); + } + + // Else, find if there's a service matching the rule name + String servicePath = getServiceById(ruleName); + if (Objects.nonNull(servicePath)) { + return servicePath; + } + + // Else, create a service entry + return getServicePath(ruleName, port, protocol, icmpType, icmpCode); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to list NSX infra service, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + + private com.vmware.nsx_policy.model.Service getInfraService(String ruleName, String port, String protocol, Integer icmpType, Integer icmpCode) { + Services service = (Services) nsxService.apply(Services.class); + String serviceName = getServiceName(ruleName, port, protocol, icmpType, icmpCode); + createNsxInfraService(service, serviceName, ruleName, port, protocol, icmpType, icmpCode); + return service.get(serviceName); + } + + public String getServicePath(String ruleName, String port, String protocol, Integer icmpType, Integer icmpCode) { + com.vmware.nsx_policy.model.Service svc = getInfraService(ruleName, port, protocol, icmpType, icmpCode); + return svc.getServiceEntries().get(0)._getDataValue().getField("parent_path").toString(); + } + + public void createNsxInfraService(Services service, String serviceName, String ruleName, String port, String protocol, + Integer icmpType, Integer icmpCode) { + try { + List serviceEntries = new ArrayList<>(); + protocol = "ICMP".equalsIgnoreCase(protocol) ? "ICMPv4" : protocol; + String serviceEntryName = getServiceEntryName(ruleName, port, protocol); + if (protocol.equals("ICMPv4")) { + serviceEntries.add(new ICMPTypeServiceEntry.Builder() + .setId(serviceEntryName) + .setDisplayName(serviceEntryName) +// .setIcmpCode(Long.valueOf(icmpCode)) + .setIcmpType(Long.valueOf(icmpType)) + .setProtocol(protocol) + .build() + ); + } else { + serviceEntries.add(new L4PortSetServiceEntry.Builder() + .setId(serviceEntryName) + .setDisplayName(serviceEntryName) + .setDestinationPorts(List.of(port)) + .setL4Protocol(protocol) + .build()); + } + com.vmware.nsx_policy.model.Service infraService = new com.vmware.nsx_policy.model.Service.Builder() + .setServiceEntries(serviceEntries) + .setId(serviceName) + .setDisplayName(serviceName) + .build(); + service.patch(serviceName, infraService); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to create NSX infra service, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + private String getServiceById(String ruleName) { + try { + Services service = (Services) nsxService.apply(Services.class); + com.vmware.nsx_policy.model.Service svc1 = service.get(ruleName); + if (Objects.nonNull(svc1)) { + return ((L4PortSetServiceEntry) svc1.getServiceEntries().get(0)).getParentPath(); + } + } catch (Exception e) { + return null; + } + return null; + } + + /** + * Create a Group for the Segment on the Inventory, with the same name as the segment and being the segment the only member of the group + */ + public void createGroupForSegment(String segmentName) { + logger.info(String.format("Creating Group for Segment %s", segmentName)); + + PathExpression pathExpression = new PathExpression(); + List paths = List.of(String.format("%s/%s", SEGMENTS_PATH, segmentName)); + pathExpression.setPaths(paths); + + Groups service = (Groups) nsxService.apply(Groups.class); + Group group = new Group.Builder() + .setId(segmentName) + .setDisplayName(segmentName) + .setExpression(List.of(pathExpression)) + .build(); + service.patch(DEFAULT_DOMAIN, segmentName, group); + } + + /** + * Remove Segment Group from the Inventory + */ + private void removeGroupForSegment(String segmentName) { + logger.info(String.format("Removing Group for Segment %s", segmentName)); + Groups service = (Groups) nsxService.apply(Groups.class); + service.delete(DEFAULT_DOMAIN, segmentName, true, false); + } + + private void removeSegmentDistributedFirewallRules(String segmentName) { + try { + SecurityPolicies services = (SecurityPolicies) nsxService.apply(SecurityPolicies.class); + services.delete(DEFAULT_DOMAIN, segmentName); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to remove NSX distributed firewall policy for segment %s, due to: %s", segmentName, ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public void createSegmentDistributedFirewall(String segmentName, List nsxRules) { + try { + String groupPath = getGroupPath(segmentName); + if (Objects.isNull(groupPath)) { + throw new CloudRuntimeException(String.format("Failed to find group for segment %s", segmentName)); + } + SecurityPolicies services = (SecurityPolicies) nsxService.apply(SecurityPolicies.class); + List rules = getRulesForDistributedFirewall(segmentName, nsxRules); + SecurityPolicy policy = new SecurityPolicy.Builder() + .setDisplayName(segmentName) + .setId(segmentName) + .setCategory("Application") + .setRules(rules) + .setScope(List.of(groupPath)) + .build(); + services.patch(DEFAULT_DOMAIN, segmentName, policy); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to create NSX distributed firewall policy for segment %s, due to: %s", segmentName, ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + public void deleteDistributedFirewallRules(String segmentName, List nsxRules) { + for(NsxNetworkRule rule : nsxRules) { + String ruleId = NsxControllerUtils.getNsxDistributedFirewallPolicyRuleId(segmentName, rule.getRuleId()); + String svcName = getServiceName(ruleId, rule.getPrivatePort(), rule.getProtocol(), rule.getIcmpType(), rule.getIcmpCode()); + // delete rules + Rules rules = (Rules) nsxService.apply(Rules.class); + rules.delete(DEFAULT_DOMAIN, segmentName, ruleId); + // delete service - if any + Services services = (Services) nsxService.apply(Services.class); + services.delete(svcName); + } + } + + private List getRulesForDistributedFirewall(String segmentName, List nsxRules) { + List rules = new ArrayList<>(); + String groupPath = getGroupPath(segmentName); + if (Objects.isNull(groupPath)) { + throw new CloudRuntimeException(String.format("Failed to find group for segment %s", segmentName)); + } + for (NsxNetworkRule rule : nsxRules) { + String ruleId = NsxControllerUtils.getNsxDistributedFirewallPolicyRuleId(segmentName, rule.getRuleId()); + Rule ruleToAdd = new Rule.Builder() + .setAction(rule.getAclAction().toString()) + .setId(ruleId) + .setDisplayName(ruleId) + .setResourceType("SecurityPolicy") + .setSourceGroups(getGroupsForTraffic(rule, segmentName, true)) + .setDestinationGroups(getGroupsForTraffic(rule, segmentName, false)) + .setServices(getServicesListForDistributedFirewallRule(rule, segmentName)) + .setScope(List.of(groupPath)) + .build(); + rules.add(ruleToAdd); + } + return rules; + } + + private List getServicesListForDistributedFirewallRule(NsxNetworkRule rule, String segmentName) { + List services = List.of("ANY"); + if (!rule.getProtocol().equalsIgnoreCase("all")) { + String ruleName = String.format("%s-R%s", segmentName, rule.getRuleId()); + String serviceName = getNsxInfraServices(ruleName, rule.getPrivatePort(), rule.getProtocol(), + rule.getIcmpType(), rule.getIcmpCode()); + services = List.of(serviceName); + } + return services; + } + + protected List getGroupsForTraffic(NsxNetworkRule rule, + String segmentName, boolean source) { + List segmentGroup = List.of(String.format("%s/%s", GROUPS_PATH_PREFIX, segmentName)); + List sourceCidrList = rule.getSourceCidrList(); + List destCidrList = rule.getDestinationCidrList(); + List ingressSource = (rule.getService() == Network.Service.NetworkACL ? segmentGroup : destCidrList); + List egressSource = (rule.getService() == Network.Service.NetworkACL ? sourceCidrList : destCidrList); + + String trafficType = rule.getTrafficType(); + if (trafficType.equalsIgnoreCase("ingress")) { + return source ? sourceCidrList : ingressSource; + } else if (trafficType.equalsIgnoreCase("egress")) { + return source ? segmentGroup : egressSource; + } + String err = String.format("Unsupported traffic type %s", trafficType); + logger.error(err); + throw new CloudRuntimeException(err); + } + + + private List listNsxGroups() { + try { + Groups groups = (Groups) nsxService.apply(Groups.class); + GroupListResult result = groups.list(DEFAULT_DOMAIN, null, false, null, null, null, null, null); + return result.getResults(); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + String msg = String.format("Failed to list NSX groups, due to: %s", ae.getErrorMessage()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + private String getGroupPath(String segmentName) { + List groups = listNsxGroups(); + Optional matchingGroup = groups.stream().filter(group -> group.getDisplayName().equals(segmentName)).findFirst(); + return matchingGroup.map(Group::getPath).orElse(null); + + } +} 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 new file mode 100644 index 00000000000..1fb546ed122 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java @@ -0,0 +1,902 @@ +// 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.amazonaws.util.CollectionUtils; +import com.cloud.agent.AgentManager; +import com.cloud.agent.Listener; +import com.cloud.agent.api.AgentControlAnswer; +import com.cloud.agent.api.AgentControlCommand; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.to.LoadBalancerTO; +import com.cloud.api.ApiDBUtils; +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; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.Status; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LoadBalancerVMMapDao; +import com.cloud.network.dao.LoadBalancerVMMapVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.element.DhcpServiceProvider; +import com.cloud.network.element.DnsServiceProvider; +import com.cloud.network.element.FirewallServiceProvider; +import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.LoadBalancingServiceProvider; +import com.cloud.network.element.NetworkACLServiceProvider; +import com.cloud.network.element.PortForwardingServiceProvider; +import com.cloud.network.element.StaticNatServiceProvider; +import com.cloud.network.element.VirtualRouterElement; +import com.cloud.network.element.VirtualRouterProviderVO; +import com.cloud.network.element.VpcProvider; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.StaticNat; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.StaticRouteProfile; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceStateAdapter; +import com.cloud.resource.ServerResource; +import com.cloud.resource.UnableDeleteHostException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.uservm.UserVm; +import com.cloud.utils.Pair; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.db.QueryBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.VMInstanceDao; +import net.sf.ehcache.config.InvalidConfigurationException; +import org.apache.cloudstack.StartupNsxCommand; +import org.apache.cloudstack.api.command.admin.internallb.ConfigureInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.CreateInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalancerElementsCmd; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.cloudstack.resource.NsxLoadBalancerMember; +import org.apache.cloudstack.resource.NsxNetworkRule; +import org.apache.cloudstack.resource.NsxOpObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.LongFunction; + +@Component +public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsServiceProvider, VpcProvider, + StaticNatServiceProvider, IpDeployer, PortForwardingServiceProvider, NetworkACLServiceProvider, + LoadBalancingServiceProvider, FirewallServiceProvider, InternalLoadBalancerElementService, ResourceStateAdapter, Listener { + + + @Inject + AccountManager accountMgr; + @Inject + NsxServiceImpl nsxService; + @Inject + DataCenterDao dataCenterDao; + @Inject + NetworkDao networkDao; + @Inject + AgentManager agentManager; + @Inject + ResourceManager resourceManager; + @Inject + PhysicalNetworkDao physicalNetworkDao; + @Inject + NetworkModel networkModel; + @Inject + DomainDao domainDao; + @Inject + protected VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + @Inject + IPAddressDao ipAddressDao; + @Inject + VMInstanceDao vmInstanceDao; + @Inject + VpcDao vpcDao; + @Inject + LoadBalancerVMMapDao lbVmMapDao; + @Inject + VirtualRouterProviderDao vrProviderDao; + @Inject + PhysicalNetworkServiceProviderDao pNtwkSvcProviderDao; + + protected Logger logger = LogManager.getLogger(getClass()); + + private final Map> capabilities = initCapabilities(); + + + private static Map> initCapabilities() { + Map> capabilities = new HashMap<>(); + + Map dhcpCapabilities = Map.of(Network.Capability.DhcpAccrossMultipleSubnets, "true"); + capabilities.put(Network.Service.Dhcp, dhcpCapabilities); + + Map dnsCapabilities = new HashMap<>(); + dnsCapabilities.put(Network.Capability.AllowDnsSuffixModification, "true"); + capabilities.put(Network.Service.Dns, dnsCapabilities); + + capabilities.put(Network.Service.StaticNat, null); + + // Set capabilities for LB service + Map lbCapabilities = new HashMap(); + lbCapabilities.put(Network.Capability.SupportedLBAlgorithms, "roundrobin,leastconn"); + lbCapabilities.put(Network.Capability.SupportedLBIsolation, "dedicated"); + lbCapabilities.put(Network.Capability.SupportedProtocols, "tcp, udp"); + lbCapabilities.put(Network.Capability.SupportedStickinessMethods, VirtualRouterElement.getHAProxyStickinessCapability()); + lbCapabilities.put(Network.Capability.LbSchemes, String.join(",", LoadBalancerContainer.Scheme.Internal.name(), LoadBalancerContainer.Scheme.Public.name())); + + capabilities.put(Network.Service.Lb, lbCapabilities); + capabilities.put(Network.Service.PortForwarding, null); + capabilities.put(Network.Service.NetworkACL, null); + + Map firewallCapabilities = new HashMap<>(); + firewallCapabilities.put(Network.Capability.SupportedProtocols, "tcp,udp,icmp"); + firewallCapabilities.put(Network.Capability.SupportedEgressProtocols, "tcp,udp,icmp,all"); + firewallCapabilities.put(Network.Capability.MultipleIps, "true"); + firewallCapabilities.put(Network.Capability.TrafficStatistics, "per public ip"); + firewallCapabilities.put(Network.Capability.SupportedTrafficDirection, "ingress, egress"); + capabilities.put(Network.Service.Firewall, firewallCapabilities); + + Map sourceNatCapabilities = new HashMap<>(); + sourceNatCapabilities.put(Network.Capability.RedundantRouter, "true"); + sourceNatCapabilities.put(Network.Capability.SupportedSourceNatTypes, "peraccount"); + capabilities.put(Network.Service.SourceNat, sourceNatCapabilities); + return capabilities; + } + @Override + public boolean addDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + return true; + } + + @Override + public boolean configDhcpSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + return true; + } + + @Override + public boolean removeDhcpSupportForSubnet(Network network) throws ResourceUnavailableException { + return true; + } + + @Override + public boolean setExtraDhcpOptions(Network network, long nicId, Map dhcpOptions) { + return true; + } + + @Override + public boolean removeDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile vmProfile) throws ResourceUnavailableException { + return true; + } + + @Override + public boolean addDnsEntry(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + return true; + } + + @Override + public boolean configDnsSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + return true; + } + + @Override + public boolean removeDnsSupportForSubnet(Network network) throws ResourceUnavailableException { + return true; + } + + @Override + public Map> getCapabilities() { + return capabilities; + } + + @Override + public boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException { + return true; + } + + @Override + public Network.Provider getProvider() { + return Network.Provider.Nsx; + } + + @Override + public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + // TODO: Check if the network is NSX based (was already implemented as part of the guru.setup() + return true; + } + + @Override + public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + return false; + } + + @Override + public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { + return canHandle(network, Network.Service.Connectivity); + } + + @Override + public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + Account account = accountMgr.getAccount(network.getAccountId()); + NetworkVO networkVO = networkDao.findById(network.getId()); + 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 + public boolean isReady(PhysicalNetworkServiceProvider provider) { + return true; + } + + @Override + public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean canEnableIndividualServices() { + return true; + } + + @Override + public boolean verifyServicesCombination(Set services) { + 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 true; + } + + @Override + public boolean start() { + return false; + } + + @Override + public boolean stop() { + return false; + } + + @Override + public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { + return null; + } + + @Override + public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map details, List hostTags) { + if (!(startup[0] instanceof StartupNsxCommand)) { + return null; + } + host.setType(Host.Type.L2Networking); + return host; + } + + @Override + public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { + 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()); + Pair isNsxAndAccount = validateVpcConfigurationAndGetAccount(zone, vpc); + if (Boolean.FALSE.equals(isNsxAndAccount.first())) { + return true; + } + if (Boolean.TRUE.equals(isNsxAndAccount.first()) && Objects.isNull(isNsxAndAccount.second())) { + throw new InvalidParameterValueException(String.format("Failed to find account with id %s", vpc.getAccountId())); + } + return true; + } + + @Override + public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws ConcurrentOperationException { + DataCenterVO zone = zoneFunction.apply(vpc.getZoneId()); + Pair isNsxAndAccount = validateVpcConfigurationAndGetAccount(zone, vpc); + if (Boolean.FALSE.equals(isNsxAndAccount.first())) { + return true; + } + if (Boolean.TRUE.equals(isNsxAndAccount.first()) && Objects.isNull(isNsxAndAccount.second())) { + throw new InvalidParameterValueException(String.format("Failed to find account with id %s", vpc.getAccountId())); + } + Account account = isNsxAndAccount.second(); + DomainVO domain = getDomainFromAccount(account); + return nsxService.deleteVpcNetwork(vpc.getZoneId(), account.getId(), domain.getId(), vpc.getId(), vpc.getName()); + } + + private Pair validateVpcConfigurationAndGetAccount(DataCenterVO zone, Vpc vpc) { + if (Objects.isNull(zone)) { + throw new InvalidParameterValueException(String.format("Failed to find zone with id %s", vpc.getZoneId())); + } + Account account = null; + boolean forNsx = false; + List physicalNetworks = physicalNetworkDao.listByZoneAndTrafficType(zone.getId(), Networks.TrafficType.Guest); + if (CollectionUtils.isNullOrEmpty(physicalNetworks) || physicalNetworks.size() > 1 ) { + throw new InvalidConfigurationException(String.format("Desired number of physical networks is not present in the zone %s for traffic type %s. ", zone.getName(), Networks.TrafficType.Guest.name())); + } + if (physicalNetworks.get(0).getIsolationMethods().contains("NSX")) { + account = accountMgr.getAccount(vpc.getAccountId()); + forNsx = true; + } + return new Pair<>(forNsx, account); + } + + @Override + public boolean createPrivateGateway(PrivateGateway gateway) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean deletePrivateGateway(PrivateGateway privateGateway) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean applyStaticRoutes(Vpc vpc, List routes) throws ResourceUnavailableException { + return false; + } + + @Override + public boolean applyACLItemsToPrivateGw(PrivateGateway gateway, List rules) throws ResourceUnavailableException { + return false; + } + + @Override + public boolean processAnswers(long agentId, long seq, Answer[] answers) { + return false; + } + + @Override + public boolean processCommands(long agentId, long seq, Command[] commands) { + return false; + } + + @Override + public AgentControlAnswer processControlCommand(long agentId, AgentControlCommand cmd) { + return null; + } + + @Override + public void processHostAdded(long hostId) { + // Do nothing + } + + @Override + public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { + // Do nothing + } + + @Override + public boolean processDisconnect(long agentId, Status state) { + return false; + } + + @Override + public void processHostAboutToBeRemoved(long hostId) { + // Do nothing + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + // Do nothing + } + + @Override + public boolean isRecurring() { + return false; + } + + @Override + public int getTimeout() { + return 0; + } + + @Override + public boolean processTimeout(long agentId, long seq) { + return false; + } + + protected boolean canHandle(Network network, Network.Service service) { + logger.debug("Checking if Nsx Element can handle service " + service.getName() + " on network " + + network.getDisplayText()); + + if (!networkModel.isProviderForNetwork(getProvider(), network.getId())) { + logger.debug("Nsx Element is not a provider for network " + network.getDisplayText()); + return false; + } + + return true; + } + + private final LongFunction zoneFunction = zoneId -> dataCenterDao.findById(zoneId); + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + for(StaticNat staticNat : rules) { + long sourceIpAddressId = staticNat.getSourceIpAddressId(); + IPAddressVO ipAddressVO = ipAddressDao.findByIdIncludingRemoved(sourceIpAddressId); + VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(ipAddressVO.getAssociatedWithVmId()); + // floating ip is released when nic was deleted + if (vm == null || networkModel.getNicInNetworkIncludingRemoved(vm.getId(), config.getId()) == null) { + continue; + } + Pair vpcOrNetwork = getVpcOrNetwork(config.getVpcId(), config.getId()); + VpcVO vpc = vpcOrNetwork.first(); + NetworkVO network = vpcOrNetwork.second(); + Long networkResourceId = Objects.nonNull(vpc) ? vpc.getId() : network.getId(); + String networkResourceName = Objects.nonNull(vpc) ? vpc.getName() : network.getName(); + boolean isVpcResource = Objects.nonNull(vpc); + if (!staticNat.isForRevoke()) { + return nsxService.createStaticNatRule(config.getDataCenterId(), config.getDomainId(), config.getAccountId(), + networkResourceId, networkResourceName, isVpcResource, vm.getId(), + ipAddressVO.getAddress().addr(), staticNat.getDestIpAddress()); + } else { + return nsxService.deleteStaticNatRule(config.getDataCenterId(), config.getDomainId(), config.getAccountId(), + networkResourceId, networkResourceName, isVpcResource); + } + } + return false; + } + + @Override + public boolean applyPFRules(Network network, List rules) throws ResourceUnavailableException { + if (!canHandle(network, Network.Service.PortForwarding)) { + return false; + } + boolean result = true; + for (PortForwardingRule rule : rules) { + IPAddressVO publicIp = ApiDBUtils.findIpAddressById(rule.getSourceIpAddressId()); + UserVm vm = ApiDBUtils.findUserVmById(rule.getVirtualMachineId()); + if (vm == null && rule.getState() != FirewallRule.State.Revoke) { + continue; + } + NsxOpObject nsxObject = getNsxOpObject(network); + String publicPort = getPublicPortRange(rule); + + String privatePort = getPrivatePFPortRange(rule); + + NsxNetworkRule networkRule = new NsxNetworkRule.Builder() + .setDomainId(nsxObject.getDomainId()) + .setAccountId(nsxObject.getAccountId()) + .setZoneId(nsxObject.getZoneId()) + .setNetworkResourceId(nsxObject.getNetworkResourceId()) + .setNetworkResourceName(nsxObject.getNetworkResourceName()) + .setVpcResource(nsxObject.isVpcResource()) + .setVmId(Objects.nonNull(vm) ? vm.getId() : 0) + .setVmIp(Objects.nonNull(vm) ? vm.getPrivateIpAddress() : null) + .setPublicIp(publicIp.getAddress().addr()) + .setPrivatePort(privatePort) + .setPublicPort(publicPort) + .setRuleId(rule.getId()) + .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)) + .build(); + if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(rule.getState())) { + result &= nsxService.createPortForwardRule(networkRule); + } else if (rule.getState() == FirewallRule.State.Revoke) { + result &= nsxService.deletePortForwardRule(networkRule); + } + } + return result; + } + + public Pair getVpcOrNetwork(Long vpcId, long networkId) { + VpcVO vpc = null; + NetworkVO network = null; + if (Objects.nonNull(vpcId)) { + vpc = vpcDao.findById(vpcId); + if (Objects.isNull(vpc)) { + throw new CloudRuntimeException(String.format("Failed to find VPC with id: %s", vpcId)); + } + } else { + network = networkDao.findById(networkId); + if (Objects.isNull(network)) { + throw new CloudRuntimeException(String.format("Failed to find network with id: %s", networkId)); + } + } + return new Pair<>(vpc, network); + } + + private static String getPublicPortRange(PortForwardingRule rule) { + return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? + String.valueOf(rule.getSourcePortStart()) : + String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); + } + + private static String getPrivatePFPortRange(PortForwardingRule rule) { + return rule.getDestinationPortStart() == rule.getDestinationPortEnd() ? + String.valueOf(rule.getDestinationPortStart()) : + String.valueOf(rule.getDestinationPortStart()).concat("-").concat(String.valueOf(rule.getDestinationPortEnd())); + } + + private static String getPrivatePortRange(FirewallRule rule) { + return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? + String.valueOf(rule.getSourcePortStart()) : + String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); + } + + private static String getPrivatePortRangeForACLRule(NetworkACLItem rule) { + return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? + String.valueOf(rule.getSourcePortStart()) : + String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); + } + + private long getResourceId(String resource, VpcVO vpc, NetworkVO network) { + switch (resource) { + case "domain": + return Objects.nonNull(vpc) ? vpc.getDomainId() : network.getDomainId(); + case "account": + return Objects.nonNull(vpc) ? vpc.getAccountId() : network.getAccountId(); + case "zone": + return Objects.nonNull(vpc) ? vpc.getZoneId() : network.getDataCenterId(); + default: + return 0; + } + } + + private NsxOpObject getNsxOpObject(Network network) { + Pair vpcOrNetwork = getVpcOrNetwork(network.getVpcId(), network.getId()); + VpcVO vpc = vpcOrNetwork.first(); + NetworkVO networkVO = vpcOrNetwork.second(); + long domainId = getResourceId("domain", vpc, networkVO); + long accountId = getResourceId("account", vpc, networkVO); + long zoneId = getResourceId("zone", vpc, networkVO); + + return new NsxOpObject.Builder() + .vpcVO(vpc) + .networkVO(networkVO) + .domainId(domainId) + .accountId(accountId) + .zoneId(zoneId) + .build(); + } + + @Override + public boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException { + boolean result = true; + for (LoadBalancingRule loadBalancingRule : rules) { + IPAddressVO publicIp = ipAddressDao.findByIpAndDcId(network.getDataCenterId(), + loadBalancingRule.getSourceIp().addr()); + NsxOpObject nsxObject = getNsxOpObject(network); + + List lbMembers = getLoadBalancerMembers(loadBalancingRule); + NsxNetworkRule networkRule = new NsxNetworkRule.Builder() + .setDomainId(nsxObject.getDomainId()) + .setAccountId(nsxObject.getAccountId()) + .setZoneId(nsxObject.getZoneId()) + .setNetworkResourceId(nsxObject.getNetworkResourceId()) + .setNetworkResourceName(nsxObject.getNetworkResourceName()) + .setVpcResource(nsxObject.isVpcResource()) + .setMemberList(lbMembers) + .setPublicIp(LoadBalancerContainer.Scheme.Public == loadBalancingRule.getScheme() ? + publicIp.getAddress().addr() : loadBalancingRule.getSourceIp().addr()) + .setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart())) + .setPrivatePort(String.valueOf(loadBalancingRule.getDefaultPortStart())) + .setRuleId(loadBalancingRule.getId()) + .setProtocol(loadBalancingRule.getLbProtocol().toUpperCase(Locale.ROOT)) + .setAlgorithm(loadBalancingRule.getAlgorithm()) + .build(); + if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(loadBalancingRule.getState())) { + result &= nsxService.createLbRule(networkRule); + } else if (loadBalancingRule.getState() == FirewallRule.State.Revoke) { + result &= nsxService.deleteLbRule(networkRule); + } + } + return result; + } + + @Override + public boolean validateLBRule(Network network, LoadBalancingRule rule) { + return true; + } + + @Override + public List updateHealthChecks(Network network, List lbrules) { + return new ArrayList<>(); + } + + @Override + public boolean handlesOnlyRulesInTransitionState() { + return false; + } + + private List getLoadBalancerMembers(LoadBalancingRule lbRule) { + List lbVms = lbVmMapDao.listByLoadBalancerId(lbRule.getId(), false); + List lbMembers = new ArrayList<>(); + + for (LoadBalancerVMMapVO lbVm : lbVms) { + NsxLoadBalancerMember member = new NsxLoadBalancerMember(lbVm.getInstanceId(), lbVm.getInstanceIp(), lbRule.getDefaultPortStart()); + lbMembers.add(member); + } + return lbMembers; + } + + @Override + public boolean applyNetworkACLs(Network network, List rules) throws ResourceUnavailableException { + if (!canHandle(network, Network.Service.NetworkACL)) { + return false; + } + + List nsxDelNetworkRules = new ArrayList<>(); + boolean success = true; + for (NetworkACLItem rule : rules) { + String privatePort = getPrivatePortRangeForACLRule(rule); + NsxNetworkRule networkRule = getNsxNetworkRuleForAcl(rule, privatePort); + if (Arrays.asList(NetworkACLItem.State.Active, NetworkACLItem.State.Add).contains(rule.getState())) { + success = success && nsxService.addFirewallRules(network, List.of(networkRule)); + } else if (NetworkACLItem.State.Revoke == rule.getState()) { + nsxDelNetworkRules.add(networkRule); + } + } + + if (!nsxDelNetworkRules.isEmpty()) { + success = nsxService.deleteFirewallRules(network, nsxDelNetworkRules); + if (!success) { + logger.warn("Not all firewall rules were successfully deleted"); + } + } + return success; + } + + @Override + public boolean reorderAclRules(Vpc vpc, List networks, List networkACLItems) { + List aclRulesList = new ArrayList<>(); + for (NetworkACLItem rule : networkACLItems) { + String privatePort = getPrivatePortRangeForACLRule(rule); + aclRulesList.add(getNsxNetworkRuleForAcl(rule, privatePort)); + } + for (Network network: networks) { + nsxService.deleteFirewallRules(network, aclRulesList); + } + boolean success = true; + for (Network network : networks) { + for (NsxNetworkRule aclRule : aclRulesList) { + success = success && nsxService.addFirewallRules(network, List.of(aclRule)); + } + } + return success; + } + + private NsxNetworkRule getNsxNetworkRuleForAcl(NetworkACLItem rule, String privatePort) { + return new NsxNetworkRule.Builder() + .setRuleId(rule.getId()) + .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) + .setAclAction(transformActionValue(rule.getAction())) + .setTrafficType(rule.getTrafficType().toString()) + .setProtocol(rule.getProtocol().toUpperCase()) + .setPublicPort(String.valueOf(rule.getSourcePortStart())) + .setPrivatePort(privatePort) + .setIcmpCode(rule.getIcmpCode()) + .setIcmpType(rule.getIcmpType()) + .setService(Network.Service.NetworkACL) + .build(); + } + @Override + public boolean applyFWRules(Network network, List rules) throws ResourceUnavailableException { + + if (!canHandle(network, Network.Service.Firewall)) { + return false; + } + List nsxAddNetworkRules = new ArrayList<>(); + List nsxDelNetworkRules = new ArrayList<>(); + for (FirewallRule rule : rules) { + NsxNetworkRule networkRule = new NsxNetworkRule.Builder() + .setRuleId(rule.getId()) + .setAclAction(NsxNetworkRule.NsxRuleAction.ALLOW) + .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? + transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) + .setDestinationCidrList(Objects.nonNull(rule.getDestinationCidrList()) ? + transformCidrListValues(rule.getDestinationCidrList()) : List.of("ANY")) + .setIcmpCode(rule.getIcmpCode()) + .setIcmpType(rule.getIcmpType()) + .setPrivatePort(getPrivatePortRange(rule)) + .setTrafficType(rule.getTrafficType().toString()) + .setService(Network.Service.Firewall) + .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)) + .build(); + if (rule.getState() == FirewallRule.State.Add) { + nsxAddNetworkRules.add(networkRule); + } else if (rule.getState() == FirewallRule.State.Revoke) { + nsxDelNetworkRules.add(networkRule); + } + } + boolean success = true; + if (!nsxDelNetworkRules.isEmpty()) { + success = nsxService.deleteFirewallRules(network, nsxDelNetworkRules); + if (!success) { + logger.warn("Not all firewall rules were successfully deleted"); + } + } + return success && nsxService.addFirewallRules(network, nsxAddNetworkRules); + } + + protected NsxNetworkRule.NsxRuleAction transformActionValue(NetworkACLItem.Action action) { + if (action == NetworkACLItem.Action.Allow) { + return NsxNetworkRule.NsxRuleAction.ALLOW; + } else if (action == NetworkACLItem.Action.Deny) { + return NsxNetworkRule.NsxRuleAction.DROP; + } + String err = String.format("Unsupported action %s", action.toString()); + logger.error(err); + throw new CloudRuntimeException(err); + } + + /** + * Replace 0.0.0.0/0 to ANY on each occurrence + */ + protected List transformCidrListValues(List sourceCidrList) { + List list = new ArrayList<>(); + if (org.apache.commons.collections.CollectionUtils.isNotEmpty(sourceCidrList)) { + for (String cidr : sourceCidrList) { + if (cidr.equals("0.0.0.0/0")) { + list.add("ANY"); + } else { + list.add(cidr); + } + } + } + return list; + } + + @Override + public VirtualRouterProvider configureInternalLoadBalancerElement(long id, boolean enable) { + VirtualRouterProviderVO element = vrProviderDao.findById(id); + if (element == null || element.getType() != VirtualRouterProvider.Type.Nsx) { + throw new InvalidParameterValueException("Can't find " + getName() + " " + + "element with network service provider id " + id + " to be used as a provider for " + + getName()); + } + + element.setEnabled(enable); + element = vrProviderDao.persist(element); + + return element; + } + + @Override + public VirtualRouterProvider addInternalLoadBalancerElement(long ntwkSvcProviderId) { + VirtualRouterProviderVO element = vrProviderDao.findByNspIdAndType(ntwkSvcProviderId, VirtualRouterProvider.Type.Nsx); + if (element != null) { + logger.debug("There is already an " + getName() + " with service provider id " + ntwkSvcProviderId); + return null; + } + + PhysicalNetworkServiceProvider provider = pNtwkSvcProviderDao.findById(ntwkSvcProviderId); + if (provider == null || !provider.getProviderName().equalsIgnoreCase(getName())) { + throw new InvalidParameterValueException("Invalid network service provider is specified"); + } + + element = new VirtualRouterProviderVO(ntwkSvcProviderId, VirtualRouterProvider.Type.Nsx); + element = vrProviderDao.persist(element); + return element; + } + + @Override + public VirtualRouterProvider getInternalLoadBalancerElement(long id) { + VirtualRouterProvider provider = vrProviderDao.findById(id); + if (provider == null || provider.getType() != VirtualRouterProvider.Type.Nsx) { + throw new InvalidParameterValueException("Unable to find " + getName() + " by id"); + } + return provider; + } + + @Override + public List searchForInternalLoadBalancerElements(Long id, Long ntwkSvsProviderId, Boolean enabled) { + QueryBuilder sc = QueryBuilder.create(VirtualRouterProviderVO.class); + if (id != null) { + sc.and(sc.entity().getId(), SearchCriteria.Op.EQ, id); + } + if (ntwkSvsProviderId != null) { + sc.and(sc.entity().getNspId(), SearchCriteria.Op.EQ, ntwkSvsProviderId); + } + if (enabled != null) { + sc.and(sc.entity().isEnabled(), SearchCriteria.Op.EQ, enabled); + } + + //return only Internal LB elements + sc.and(sc.entity().getType(), SearchCriteria.Op.EQ, VirtualRouterProvider.Type.Nsx); + + return sc.list(); + } + + @Override + public VirtualRouterProvider.Type getProviderType() { + return VirtualRouterProvider.Type.Nsx; + } + + @Override + public List> getCommands() { + List> cmdList = new ArrayList>(); + cmdList.add(CreateInternalLoadBalancerElementCmd.class); + cmdList.add(ConfigureInternalLoadBalancerElementCmd.class); + cmdList.add(ListInternalLoadBalancerElementsCmd.class); + return cmdList; + } +} 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 new file mode 100644 index 00000000000..0d556da9f2c --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java @@ -0,0 +1,342 @@ +// 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 static java.util.Objects.isNull; +import static java.util.Objects.nonNull; + +import com.cloud.dc.DataCenter; +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; +import com.cloud.network.NetworkMigrationResponder; +import com.cloud.network.NetworkModel; +import com.cloud.network.NetworkProfile; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.guru.GuestNetworkGuru; +import com.cloud.network.vpc.VpcVO; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachine; +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.agent.api.CreateNsxTier1GatewayCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; +import org.apache.cloudstack.utils.NsxControllerUtils; + +import org.apache.cloudstack.utils.NsxHelper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.inject.Inject; +import java.util.List; +import java.util.Objects; + +public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigrationResponder { + protected Logger logger = LogManager.getLogger(getClass()); + + @Inject + NetworkOfferingServiceMapDao networkOfferingServiceMapDao; + @Inject + NsxControllerUtils nsxControllerUtils; + @Inject + AccountDao accountDao; + @Inject + DomainDao domainDao; + @Inject + NetworkModel networkModel; + + public NsxGuestNetworkGuru() { + super(); + _isolationMethods = new PhysicalNetwork.IsolationMethod[] {new PhysicalNetwork.IsolationMethod("NSX")}; + } + + @Override + public boolean canHandle(NetworkOffering offering, DataCenter.NetworkType networkType, + PhysicalNetwork physicalNetwork) { + return networkType == DataCenter.NetworkType.Advanced && isMyTrafficType(offering.getTrafficType()) + && isMyIsolationMethod(physicalNetwork) && (NetworkOffering.NsxMode.ROUTED.name().equals(offering.getNsxMode()) + || (networkOfferingServiceMapDao.isProviderForNetworkOffering( + offering.getId(), Network.Provider.Nsx) && NetworkOffering.NsxMode.NATTED.name().equals(offering.getNsxMode()))); + } + + @Override + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { + PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); + DataCenter dc = _dcDao.findById(plan.getDataCenterId()); + + if (!canHandle(offering, dc.getNetworkType(), physnet)) { + logger.debug("Refusing to design this network"); + return null; + } + + NetworkVO network = (NetworkVO) super.design(offering, plan, userSpecified, name, vpcId, owner); + if (network == null) { + return null; + } + network.setBroadcastDomainType(Networks.BroadcastDomainType.NSX); + + if (userSpecified != null) { + if ((userSpecified.getIp6Cidr() == null && userSpecified.getIp6Gateway() != null) || ( + userSpecified.getIp6Cidr() != null && userSpecified.getIp6Gateway() == null)) { + throw new InvalidParameterValueException("cidrv6 and gatewayv6 must be specified together."); + } + + if (userSpecified.getIp6Cidr() != null) { + network.setIp6Cidr(userSpecified.getIp6Cidr()); + network.setIp6Gateway(userSpecified.getIp6Gateway()); + } + } + + network.setBroadcastDomainType(Networks.BroadcastDomainType.NSX); + network.setState(Network.State.Allocated); + + NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), + network.getBroadcastDomainType(), network.getNetworkOfferingId(), Network.State.Implemented, + network.getDataCenterId(), network.getPhysicalNetworkId(), offering.isRedundantRouter()); + implemented.setAccountId(owner.getAccountId()); + + if (network.getGateway() != null) { + implemented.setGateway(network.getGateway()); + } + + if (network.getCidr() != null) { + implemented.setCidr(network.getCidr()); + } + + if (vpcId != null) { + implemented.setVpcId(vpcId); + } + + if (name != null) { + 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 = _dcDao.findById(zoneId); + if (isNull(zone)) { + throw new CloudRuntimeException(String.format("Failed to find zone with id: %s", zoneId)); + } + createNsxSegment(designedNetwork, zone); + } catch (Exception ex) { + throw new CloudRuntimeException("unable to create NSX network " + network.getUuid() + "due to: " + ex.getMessage()); + } + } + + @Override + @DB + public void deallocate(Network config, NicProfile nic, VirtualMachineProfile vm) { + // Do nothing + } + + @Override + public Network implement(Network network, NetworkOffering offering, DeployDestination dest, + ReservationContext context) { + NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), + network.getBroadcastDomainType(), network.getNetworkOfferingId(), Network.State.Implemented, + network.getDataCenterId(), network.getPhysicalNetworkId(), offering.isRedundantRouter()); + implemented.setAccountId(network.getAccountId()); + + if (network.getGateway() != null) { + implemented.setGateway(network.getGateway()); + } + + if (network.getCidr() != null) { + implemented.setCidr(network.getCidr()); + } + + if (network.getVpcId() != null) { + implemented.setVpcId(network.getVpcId()); + } + + if (network.getName() != null) { + implemented.setName(network.getName()); + } + implemented.setBroadcastUri(Networks.BroadcastDomainType.NSX.toUri("nsx")); + return implemented; + } + + @Override + public NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + NicProfile nicProfile = super.allocate(network, nic, vm); + if (vm.getType() != VirtualMachine.Type.DomainRouter) { + return nicProfile; + } + + final DataCenter zone = _dcDao.findById(network.getDataCenterId()); + long zoneId = network.getDataCenterId(); + if (Objects.isNull(zone)) { + String msg = String.format("Unable to find zone with id: %s", zoneId); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + Account account = accountDao.findById(network.getAccountId()); + if (Objects.isNull(account)) { + String msg = String.format("Unable to find account with id: %s", network.getAccountId()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + VpcVO vpc = _vpcDao.findById(network.getVpcId()); + if (Objects.isNull(vpc)) { + String msg = String.format("Unable to find VPC with id: %s, allocating for network %s", network.getVpcId(), network.getName()); + logger.debug(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); + } + + NetworkOfferingVO networkOfferingVO = networkOfferingDao.findById(network.getNetworkOfferingId()); + + if (isNull(network.getVpcId()) && networkOfferingVO.getNsxMode().equals(NetworkOffering.NsxMode.NATTED.name())) { + long domainId = domain.getId(); + long accountId = account.getId(); + long dataCenterId = zone.getId(); + long resourceId = network.getId(); + PublicIpAddress ipAddress = networkModel.getSourceNatIpAddressForGuestNetwork(account, network); + String translatedIp = ipAddress.getAddress().addr(); + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(domainId, accountId, dataCenterId, resourceId, false); + logger.debug(String.format("Creating NSX NAT Rule for Tier1 GW %s for translated IP %s for Isolated network %s", tier1GatewayName, translatedIp, network.getName())); + String natRuleId = NsxControllerUtils.getNsxNatRuleId(domainId, accountId, dataCenterId, resourceId, false); + CreateOrUpdateNsxTier1NatRuleCommand cmd = NsxHelper.createOrUpdateNsxNatRuleCommand(domainId, accountId, dataCenterId, tier1GatewayName, "SNAT", translatedIp, natRuleId); + NsxAnswer nsxAnswer = nsxControllerUtils.sendNsxCommand(cmd, dataCenterId); + if (!nsxAnswer.getResult()) { + String msg = String.format("Could not create NSX NAT Rule on Tier1 Gateway %s for IP %s for Isolated network %s", tier1GatewayName, translatedIp, network.getName()); + 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 = 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()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + return nicProfile; + } + + @Override + public void reserve(final NicProfile nic, final Network network, final VirtualMachineProfile vm, + final DeployDestination dest, final ReservationContext context) + throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + // Do nothing + } + + @Override + public boolean release(final NicProfile nic, final VirtualMachineProfile vm, final String reservationId) { + return true; + } + + @Override + public void shutdown(final NetworkProfile profile, final NetworkOffering offering) { + // Do nothing + } + + @Override + public boolean trash(Network network, NetworkOffering offering) { + return true; + } + + @Override + public boolean prepareMigration(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) { + return false; + } + + @Override + public void rollbackMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) { + // Do nothing + } + + @Override + public void commitMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) { + // Do nothing + } + + public void createNsxSegment(NetworkVO networkVO, DataCenter zone) { + Account account = accountDao.findById(networkVO.getAccountId()); + if (isNull(account)) { + throw new CloudRuntimeException(String.format("Unable to find account with id: %s", networkVO.getAccountId())); + } + 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); + } + String vpcName = null; + if (nonNull(networkVO.getVpcId())) { + VpcVO vpc = _vpcDao.findById(networkVO.getVpcId()); + if (isNull(vpc)) { + throw new CloudRuntimeException(String.format("Failed to find VPC network with id: %s", networkVO.getVpcId())); + } + vpcName = vpc.getName(); + } else { + logger.debug(String.format("Creating a Tier 1 Gateway for the network %s before creating the NSX segment", networkVO.getName())); + long networkOfferingId = networkVO.getNetworkOfferingId(); + NetworkOfferingVO networkOfferingVO = networkOfferingDao.findById(networkOfferingId); + boolean isSourceNatSupported = !NetworkOffering.NsxMode.ROUTED.name().equals(networkOfferingVO.getNsxMode()) && + networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(networkVO.getNetworkOfferingId(), Network.Service.SourceNat); + CreateNsxTier1GatewayCommand nsxTier1GatewayCommand = new CreateNsxTier1GatewayCommand(domain.getId(), account.getId(), zone.getId(), networkVO.getId(), networkVO.getName(), false, isSourceNatSupported); + + NsxAnswer nsxAnswer = nsxControllerUtils.sendNsxCommand(nsxTier1GatewayCommand, zone.getId()); + if (!nsxAnswer.getResult()) { + String msg = String.format("Could not create a Tier 1 Gateway for network %s: %s", networkVO.getName(), nsxAnswer.getDetails()); + 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/NsxProviderService.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderService.java new file mode 100644 index 00000000000..47dfe04db3e --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderService.java @@ -0,0 +1,35 @@ +// 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.nsx.NsxProvider; +import com.cloud.utils.component.PluggableService; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.command.AddNsxControllerCmd; +import org.apache.cloudstack.api.response.NsxControllerResponse; + +import java.util.List; + +public interface NsxProviderService extends PluggableService { + NsxProvider addProvider(AddNsxControllerCmd cmd); + + NsxControllerResponse createNsxControllerResponse(NsxProvider nsxProvider); + + List listNsxProviders(Long zoneId); + + boolean deleteNsxController(Long nsxControllerId); +} 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 new file mode 100644 index 00000000000..c59ebfd8755 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderServiceImpl.java @@ -0,0 +1,213 @@ +// 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.amazonaws.util.CollectionUtils; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.DetailVO; +import com.cloud.host.Host; +import com.cloud.host.dao.HostDetailsDao; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.nsx.NsxProvider; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.element.NsxProviderVO; +import com.cloud.resource.ResourceManager; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.annotations.VisibleForTesting; +import org.apache.cloudstack.api.command.DeleteNsxControllerCmd; +import org.apache.cloudstack.api.command.ListNsxControllersCmd; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.command.AddNsxControllerCmd; +import org.apache.cloudstack.api.response.NsxControllerResponse; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.cloudstack.resource.NsxResource; +import org.apache.commons.lang3.StringUtils; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +public class NsxProviderServiceImpl implements NsxProviderService { + + @Inject + NsxProviderDao nsxProviderDao; + @Inject + DataCenterDao dataCenterDao; + @Inject + PhysicalNetworkDao physicalNetworkDao; + @Inject + NetworkDao networkDao; + @Inject + ResourceManager resourceManager; + @Inject + HostDetailsDao hostDetailsDao; + + @Override + public NsxProvider addProvider(AddNsxControllerCmd cmd) { + final Long zoneId = cmd.getZoneId(); + final String name = cmd.getName(); + final String hostname = cmd.getHostname(); + final String port = cmd.getPort() == null || cmd.getPort().equals(StringUtils.EMPTY) ? "443" : cmd.getPort(); + final String username = cmd.getUsername(); + final String password = cmd.getPassword(); + final String tier0Gateway = cmd.getTier0Gateway(); + final String edgeCluster = cmd.getEdgeCluster(); + final String transportZone = cmd.getTransportZone(); + + Map params = new HashMap<>(); + params.put("guid", UUID.randomUUID().toString()); + params.put("zoneId", zoneId.toString()); + params.put("name", name); + params.put("hostname", hostname); + params.put("port", port); + params.put("username", username); + params.put("password", password); + params.put("tier0Gateway", tier0Gateway); + params.put("edgeCluster", edgeCluster); + params.put("transportZone", transportZone); + + Map hostdetails = new HashMap<>(params); + NsxProvider nsxProvider; + + NsxResource nsxResource = new NsxResource(); + try { + nsxResource.configure(hostname, hostdetails); + final Host host = resourceManager.addHost(zoneId, nsxResource, nsxResource.getType(), params); + if (host != null) { + nsxProvider = Transaction.execute((TransactionCallback) status -> { + NsxProviderVO nsxProviderVO = new NsxProviderVO.Builder() + .setZoneId(zoneId) + .setHostId(host.getId()) + .setProviderName(name) + .setHostname(hostname) + .setPort(port) + .setUsername(username) + .setPassword(password) + .setTier0Gateway(tier0Gateway) + .setEdgeCluster(edgeCluster) + .setTransportZone(transportZone) + .build(); + + nsxProviderDao.persist(nsxProviderVO); + + DetailVO detail = new DetailVO(host.getId(), "nsxcontrollerid", + String.valueOf(nsxProviderVO.getId())); + hostDetailsDao.persist(detail); + + return nsxProviderVO; + }); + } else { + throw new CloudRuntimeException("Failed to add NSX controller due to internal error."); + } + } catch (ConfigurationException e) { + throw new CloudRuntimeException(e.getMessage()); + } + return nsxProvider; + } + + @Override + public NsxControllerResponse createNsxControllerResponse(NsxProvider nsxProvider) { + DataCenterVO zone = dataCenterDao.findById(nsxProvider.getZoneId()); + if (Objects.isNull(zone)) { + throw new CloudRuntimeException(String.format("Failed to find zone with id %s", nsxProvider.getZoneId())); + } + NsxControllerResponse response = new NsxControllerResponse(); + response.setName(nsxProvider.getProviderName()); + response.setUuid(nsxProvider.getUuid()); + response.setHostname(nsxProvider.getHostname()); + response.setPort(nsxProvider.getPort()); + response.setZoneId(zone.getUuid()); + response.setZoneName(zone.getName()); + response.setTier0Gateway(nsxProvider.getTier0Gateway()); + response.setEdgeCluster(nsxProvider.getEdgeCluster()); + response.setTransportZone(nsxProvider.getTransportZone()); + response.setObjectName("nsxController"); + return response; + } + + @Override + public List listNsxProviders(Long zoneId) { + List nsxControllersResponseList = new ArrayList<>(); + if (zoneId != null) { + NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(zoneId); + if (Objects.nonNull(nsxProviderVO)) { + nsxControllersResponseList.add(createNsxControllerResponse(nsxProviderVO)); + } + } else { + List nsxProviderVOList = nsxProviderDao.listAll(); + for (NsxProviderVO nsxProviderVO : nsxProviderVOList) { + nsxControllersResponseList.add(createNsxControllerResponse(nsxProviderVO)); + } + } + + return nsxControllersResponseList; + } + + @Override + public boolean deleteNsxController(Long nsxControllerId) { + NsxProviderVO nsxProvider = nsxProviderDao.findById(nsxControllerId); + if (Objects.isNull(nsxProvider)) { + throw new InvalidParameterValueException(String.format("Failed to find NSX controller with id: %s", nsxControllerId)); + } + Long zoneId = nsxProvider.getZoneId(); + // Find the physical network we work for + List physicalNetworks = physicalNetworkDao.listByZone(zoneId); + for (PhysicalNetworkVO physicalNetwork : physicalNetworks) { + List networkList = networkDao.listByPhysicalNetwork(physicalNetwork.getId()); + if (!CollectionUtils.isNullOrEmpty(networkList)) { + validateNetworkState(networkList); + } + } + nsxProviderDao.remove(nsxControllerId); + return true; + } + + @Override + public List> getCommands() { + List> cmdList = new ArrayList<>(); + if (Boolean.TRUE.equals(NetworkOrchestrationService.NSX_ENABLED.value())) { + cmdList.add(AddNsxControllerCmd.class); + cmdList.add(ListNsxControllersCmd.class); + cmdList.add(DeleteNsxControllerCmd.class); + } + return cmdList; + } + + @VisibleForTesting + void validateNetworkState(List networkList) { + for (NetworkVO network : networkList) { + if (network.getBroadcastDomainType() == Networks.BroadcastDomainType.NSX && + ((network.getState() != Network.State.Shutdown) && (network.getState() != Network.State.Destroy))) { + throw new CloudRuntimeException("This NSX Controller cannot be deleted as there are one or more logical networks provisioned by CloudStack on it."); + } + } + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java new file mode 100644 index 00000000000..7463a19fd4e --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java @@ -0,0 +1,170 @@ +// 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.VlanDetailsVO; +import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.nsx.NsxService; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.guru.PublicNetworkGuru; +import com.cloud.network.vpc.VpcOffering; +import com.cloud.network.vpc.VpcOfferingVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.user.Account; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.utils.NsxControllerUtils; +import org.apache.cloudstack.utils.NsxHelper; +import org.apache.commons.collections.CollectionUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.inject.Inject; +import java.util.List; +import java.util.stream.Collectors; + +public class NsxPublicNetworkGuru extends PublicNetworkGuru { + + @Inject + private VlanDetailsDao vlanDetailsDao; + @Inject + private VpcDao vpcDao; + @Inject + private VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + @Inject + private NsxControllerUtils nsxControllerUtils; + @Inject + private NsxService nsxService; + @Inject + private VpcOfferingDao vpcOfferingDao; + @Inject + private NetworkOfferingDao offeringDao; + + protected Logger logger = LogManager.getLogger(getClass()); + + public NsxPublicNetworkGuru() { + super(); + } + + @Override + protected boolean canHandle(NetworkOffering offering) { + return isMyTrafficType(offering.getTrafficType()) && offering.isSystemOnly() && offering.isForNsx(); + } + + @Override + public Network design(NetworkOffering offering, DeploymentPlan plan, Network network, String name, Long vpcId, Account owner) { + if (!canHandle(offering)) { + return null; + } + + if (offering.getTrafficType() == Networks.TrafficType.Public) { + return new NetworkVO(offering.getTrafficType(), Networks.Mode.Static, network.getBroadcastDomainType(), offering.getId(), Network.State.Setup, plan.getDataCenterId(), + plan.getPhysicalNetworkId(), offering.isRedundantRouter()); + } + return null; + } + + @Override + public NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException { + logger.debug("NSX Public network guru: allocate"); + + IPAddressVO ipAddress = _ipAddressDao.findByIp(nic.getIPv4Address()); + if (ipAddress == null) { + String err = String.format("Cannot find the IP address %s", nic.getIPv4Address()); + logger.error(err); + throw new CloudRuntimeException(err); + } + Long vpcId = ipAddress.getVpcId(); + boolean isForVpc = vpcId != null; + VpcVO vpc = vpcDao.findById(vpcId); + if (vpc == null) { + String err = String.format("Cannot find a VPC with ID %s", vpcId); + logger.error(err); + throw new CloudRuntimeException(err); + } + + // For NSX, use VR Public IP != Source NAT + List ips = _ipAddressDao.listByAssociatedVpc(vpc.getId(), true); + if (CollectionUtils.isEmpty(ips)) { + String err = String.format("Cannot find a source NAT IP for the VPC %s", vpc.getName()); + logger.error(err); + throw new CloudRuntimeException(err); + } + ips = ips.stream().filter(x -> !x.getAddress().addr().equals(nic.getIPv4Address())).collect(Collectors.toList()); + // Use Source NAT IP address from the NSX Public Range. Do not Use the VR Public IP address + ipAddress = ips.get(0); + if (ipAddress.isSourceNat() && !ipAddress.isForSystemVms()) { + VlanDetailsVO detail = vlanDetailsDao.findDetail(ipAddress.getVlanId(), ApiConstants.NSX_DETAIL_KEY); + if (detail != null && detail.getValue().equalsIgnoreCase("true")) { + long accountId = vpc.getAccountId(); + long domainId = vpc.getDomainId(); + long dataCenterId = vpc.getZoneId(); + long resourceId = vpc.getId(); + Network.Service[] services = { Network.Service.SourceNat }; + long networkOfferingId = vpc.getVpcOfferingId(); + VpcOfferingVO vpcVO = vpcOfferingDao.findById(networkOfferingId); + boolean sourceNatEnabled = !NetworkOffering.NsxMode.ROUTED.name().equals(vpcVO.getNsxMode()) && + vpcOfferingServiceMapDao.areServicesSupportedByVpcOffering(vpc.getVpcOfferingId(), services); + + logger.info(String.format("Creating Tier 1 Gateway for VPC %s", vpc.getName())); + boolean result = nsxService.createVpcNetwork(dataCenterId, accountId, domainId, resourceId, vpc.getName(), sourceNatEnabled); + if (!result) { + String msg = String.format("Error creating Tier 1 Gateway for VPC %s", vpc.getName()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + + boolean hasNatSupport = false; + VpcOffering vpcOffering = vpcOfferingDao.findById(vpc.getVpcOfferingId()); + hasNatSupport = NetworkOffering.NsxMode.NATTED.name().equals(vpcOffering.getNsxMode()); + + if (!hasNatSupport) { + return nic; + } + + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(domainId, accountId, dataCenterId, resourceId, isForVpc); + String translatedIp = ipAddress.getAddress().addr(); + logger.debug(String.format("Creating NSX Nat Rule for Tier1 GW %s for translated IP %s", tier1GatewayName, translatedIp)); + String natRuleId = NsxControllerUtils.getNsxNatRuleId(domainId, accountId, dataCenterId, resourceId, isForVpc); + CreateOrUpdateNsxTier1NatRuleCommand cmd = NsxHelper.createOrUpdateNsxNatRuleCommand(domainId, accountId, dataCenterId, tier1GatewayName, "SNAT", translatedIp, natRuleId); + NsxAnswer nsxAnswer = nsxControllerUtils.sendNsxCommand(cmd, dataCenterId); + if (!nsxAnswer.getResult()) { + String msg = String.format("Could not create NSX Nat Rule on Tier1 Gateway %s for IP %s", tier1GatewayName, translatedIp); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + } + return nic; + } +} 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 new file mode 100644 index 00000000000..f8880826a3f --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java @@ -0,0 +1,193 @@ +// 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.IpAddress; +import com.cloud.network.Network; +import com.cloud.network.nsx.NsxService; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.CreateNsxDistributedFirewallRulesCommand; +import org.apache.cloudstack.agent.api.CreateNsxLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.CreateNsxPortForwardRuleCommand; +import org.apache.cloudstack.agent.api.CreateNsxStaticNatCommand; +import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxDistributedFirewallRulesCommand; +import org.apache.cloudstack.agent.api.DeleteNsxLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand; +import org.apache.cloudstack.agent.api.DeleteNsxNatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand; +import org.apache.cloudstack.resource.NsxNetworkRule; +import org.apache.cloudstack.utils.NsxControllerUtils; +import org.apache.cloudstack.utils.NsxHelper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.inject.Inject; +import java.util.List; +import java.util.Objects; + +public class NsxServiceImpl implements NsxService { + @Inject + NsxControllerUtils nsxControllerUtils; + @Inject + VpcDao vpcDao; + @Inject + NetworkDao networkDao; + + protected Logger logger = LogManager.getLogger(getClass()); + + public boolean createVpcNetwork(Long zoneId, long accountId, long domainId, Long vpcId, String vpcName, boolean sourceNatEnabled) { + CreateNsxTier1GatewayCommand createNsxTier1GatewayCommand = + new CreateNsxTier1GatewayCommand(domainId, accountId, zoneId, vpcId, vpcName, true, sourceNatEnabled); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(createNsxTier1GatewayCommand, zoneId); + return result.getResult(); + } + + @Override + public boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address) { + if (vpc == null || address == null) { + return false; + } + long accountId = vpc.getAccountId(); + long domainId = vpc.getDomainId(); + long zoneId = vpc.getZoneId(); + long vpcId = vpc.getId(); + + logger.debug(String.format("Updating the source NAT IP for NSX VPC %s to IP: %s", vpc.getName(), address.getAddress().addr())); + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(domainId, accountId, zoneId, vpcId, true); + String sourceNatRuleId = NsxControllerUtils.getNsxNatRuleId(domainId, accountId, zoneId, vpcId, true); + CreateOrUpdateNsxTier1NatRuleCommand cmd = NsxHelper.createOrUpdateNsxNatRuleCommand(domainId, accountId, zoneId, tier1GatewayName, "SNAT", address.getAddress().addr(), sourceNatRuleId); + NsxAnswer answer = nsxControllerUtils.sendNsxCommand(cmd, zoneId); + if (!answer.getResult()) { + logger.error(String.format("Could not update the source NAT IP address for VPC %s: %s", vpc.getName(), answer.getDetails())); + return false; + } + return true; + } + + public boolean createNetwork(Long zoneId, long accountId, long domainId, Long networkId, String networkName) { + CreateNsxTier1GatewayCommand createNsxTier1GatewayCommand = + new CreateNsxTier1GatewayCommand(domainId, accountId, zoneId, networkId, networkName, false, false); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(createNsxTier1GatewayCommand, zoneId); + return result.getResult(); + } + + public boolean deleteVpcNetwork(Long zoneId, long accountId, long domainId, Long vpcId, String vpcName) { + DeleteNsxTier1GatewayCommand deleteNsxTier1GatewayCommand = + new DeleteNsxTier1GatewayCommand(domainId, accountId, zoneId, vpcId, vpcName, true); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(deleteNsxTier1GatewayCommand, zoneId); + return result.getResult(); + } + + 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(domainId, accountId, zoneId, + network.getVpcId(), vpcName, network.getId(), network.getName()); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(deleteNsxSegmentCommand, network.getDataCenterId()); + if (!result.getResult()) { + String msg = String.format("Could not remove the NSX segment for network %s: %s", network.getName(), result.getDetails()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + + if (Objects.isNull(network.getVpcId())) { + DeleteNsxTier1GatewayCommand deleteNsxTier1GatewayCommand = new DeleteNsxTier1GatewayCommand(domainId, accountId, zoneId, network.getId(), network.getName(), false); + result = nsxControllerUtils.sendNsxCommand(deleteNsxTier1GatewayCommand, zoneId); + } + return result.getResult(); + } + + public boolean createStaticNatRule(long zoneId, long domainId, long accountId, Long networkResourceId, String networkResourceName, + boolean isVpcResource, long vmId, String publicIp, String vmIp) { + CreateNsxStaticNatCommand createNsxStaticNatCommand = new CreateNsxStaticNatCommand(domainId, accountId, zoneId, + networkResourceId, networkResourceName, isVpcResource, vmId, publicIp, vmIp); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(createNsxStaticNatCommand, zoneId); + return result.getResult(); + } + + public boolean deleteStaticNatRule(long zoneId, long domainId, long accountId, Long networkResourceId, String networkResourceName, + boolean isVpcResource) { + DeleteNsxNatRuleCommand deleteNsxStaticNatCommand = new DeleteNsxNatRuleCommand(domainId, accountId, zoneId, + networkResourceId, networkResourceName, isVpcResource, null, null, null, null); + deleteNsxStaticNatCommand.setService(Network.Service.StaticNat); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(deleteNsxStaticNatCommand, zoneId); + return result.getResult(); + } + + public boolean createPortForwardRule(NsxNetworkRule netRule) { + // TODO: if port doesn't exist in default list of services, create a service entry + CreateNsxPortForwardRuleCommand createPortForwardCmd = new CreateNsxPortForwardRuleCommand(netRule.getDomainId(), + netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(), + netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getVmId(), netRule.getRuleId(), + netRule.getPublicIp(), netRule.getVmIp(), netRule.getPublicPort(), netRule.getPrivatePort(), netRule.getProtocol()); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(createPortForwardCmd, netRule.getZoneId()); + return result.getResult(); + } + + public boolean deletePortForwardRule(NsxNetworkRule netRule) { + DeleteNsxNatRuleCommand deleteCmd = new DeleteNsxNatRuleCommand(netRule.getDomainId(), + netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(), + netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getVmId(), netRule.getRuleId(), netRule.getPrivatePort(), netRule.getProtocol()); + deleteCmd.setService(Network.Service.PortForwarding); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(deleteCmd, netRule.getZoneId()); + return result.getResult(); + } + + public boolean createLbRule(NsxNetworkRule netRule) { + CreateNsxLoadBalancerRuleCommand command = new CreateNsxLoadBalancerRuleCommand(netRule.getDomainId(), + netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(), + netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getMemberList(), netRule.getRuleId(), + netRule.getPublicPort(), netRule.getPrivatePort(), netRule.getAlgorithm(), netRule.getProtocol()); + command.setPublicIp(netRule.getPublicIp()); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, netRule.getZoneId()); + return result.getResult(); + } + + public boolean deleteLbRule(NsxNetworkRule netRule) { + DeleteNsxLoadBalancerRuleCommand command = new DeleteNsxLoadBalancerRuleCommand(netRule.getDomainId(), + netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(), + netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getMemberList(), netRule.getRuleId(), + netRule.getVmId()); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, netRule.getZoneId()); + return result.getResult(); + } + + public boolean addFirewallRules(Network network, List netRules) { + CreateNsxDistributedFirewallRulesCommand command = new CreateNsxDistributedFirewallRulesCommand(network.getDomainId(), + network.getAccountId(), network.getDataCenterId(), network.getVpcId(), network.getId(), netRules); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, network.getDataCenterId()); + return result.getResult(); + } + + public boolean deleteFirewallRules(Network network, List netRules) { + DeleteNsxDistributedFirewallRulesCommand command = new DeleteNsxDistributedFirewallRulesCommand(network.getDomainId(), + network.getAccountId(), network.getDataCenterId(), network.getVpcId(), network.getId(), netRules); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, network.getDataCenterId()); + return result.getResult(); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java new file mode 100644 index 00000000000..e064a6b6291 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java @@ -0,0 +1,148 @@ +// 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.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NsxProviderVO; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.NsxCommand; +import org.apache.cloudstack.service.NsxApiClient; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; + +import static java.util.Objects.isNull; + +@Component +public class NsxControllerUtils { + protected Logger logger = LogManager.getLogger(getClass()); + + @Inject + private AgentManager agentMgr; + @Inject + private NsxProviderDao nsxProviderDao; + + public static String getNsxNatRuleId(long domainId, long accountId, long dataCenterId, long resourceId, boolean isForVpc) { + String resourcePrefix = isForVpc ? "V" : "N"; + return String.format("D%s-A%s-Z%s-%s%s-NAT", domainId, accountId, dataCenterId, resourcePrefix, resourceId); + } + + public static String getNsxDistributedFirewallPolicyRuleId(String segmentName, long ruleId) { + return String.format("%s-R%s", segmentName, ruleId); + } + + public NsxAnswer sendNsxCommand(NsxCommand cmd, long zoneId) throws IllegalArgumentException { + NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(zoneId); + if (nsxProviderVO == null) { + logger.error("No NSX controller was found!"); + throw new InvalidParameterValueException("Failed to find an NSX controller"); + } + Answer answer = agentMgr.easySend(nsxProviderVO.getHostId(), cmd); + + if (answer == null || !answer.getResult()) { + logger.error("NSX API Command failed"); + throw new InvalidParameterValueException("Failed API call to NSX controller"); + } + + return (NsxAnswer) answer; + } + + /** + * Generates the Tier 1 Gateway name and identifier for the resource on the NSX manager + */ + public static String getTier1GatewayName(long domainId, long accountId, long zoneId, + Long networkResourceId, boolean isResourceVpc) { + String resourcePrefix = isResourceVpc ? "V" : "N"; + return String.format("D%s-A%s-Z%s-%s%s", domainId, accountId, zoneId, resourcePrefix, networkResourceId); + } + + 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); + } + + public static String getStaticNatRuleName(long domainId, long accountId, long zoneId, Long networkResourceId, boolean isVpcResource) { + String suffix = "-STATICNAT"; + return getTier1GatewayName(domainId, accountId, zoneId, networkResourceId, isVpcResource) + suffix; + } + + public static String getPortForwardRuleName(long domainId, long accountId, long zoneId, Long networkResourceId, long ruleId, boolean isVpcResource) { + String suffix = "-PF"; + return getTier1GatewayName(domainId, accountId, zoneId, networkResourceId, isVpcResource) + suffix + ruleId; + } + + public static String getServiceName(String ruleName, String port, String protocol, Integer icmpType, Integer icmpCode) { + return protocol.equalsIgnoreCase("icmp") ? + String.format("%s-SVC-%s-%s-%s", ruleName, icmpType, icmpCode, protocol) : + String.format("%s-SVC-%s-%s", ruleName, port, protocol); + } + + public static String getServiceEntryName(String ruleName, String port, String protocol) { + return ruleName + "-SE-" + port + "-" + protocol; + } + + public static String getLoadBalancerName(String tier1GatewayName) { + return tier1GatewayName + "-LB"; + } + + public static String getLoadBalancerRuleName(String tier1GatewayName, long lbId) { + return tier1GatewayName + "-LB" + lbId; + } + + public static String getServerPoolName(String tier1GatewayName, long lbId) { + return getLoadBalancerRuleName(tier1GatewayName, lbId) + "-SP"; + } + + public static String getActiveMonitorProfileName(String lbServerPoolName, String port, String protocol) { + return lbServerPoolName + "-" + protocol + "-" + port + "-AM"; + } + + public static String getVirtualServerName(String tier1GatewayName, long lbId) { + return getLoadBalancerRuleName(tier1GatewayName, lbId) + "-VS"; + } + + public static String getServerPoolMemberName(String tier1GatewayName, long vmId) { + return tier1GatewayName + "-VM" + vmId; + } + + public static String getLoadBalancerAlgorithm(String algorithm) { + switch (algorithm) { + case "leastconn": + return NsxApiClient.LBAlgorithm.LEAST_CONNECTION.name(); + case "source": + return NsxApiClient.LBAlgorithm.IP_HASH.name(); + default: + return NsxApiClient.LBAlgorithm.ROUND_ROBIN.name(); + } + } +} 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..b0668a0704f --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxHelper.java @@ -0,0 +1,53 @@ +// 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 org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; + +import java.util.List; + +public class NsxHelper { + + private NsxHelper() { + } + + public static CreateNsxDhcpRelayConfigCommand createNsxDhcpRelayConfigCommand(DomainVO domain, Account account, DataCenter zone, VpcVO vpc, Network network, List addresses) { + Long vpcId = vpc != null ? vpc.getId() : null; + String vpcName = vpc != null ? vpc.getName() : null; + return new CreateNsxDhcpRelayConfigCommand(domain.getId(), account.getId(), zone.getId(), + vpcId, vpcName, 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()); + } + + public static CreateOrUpdateNsxTier1NatRuleCommand createOrUpdateNsxNatRuleCommand(long domainId, long accountId, long zoneId, + String tier1Gateway, String action, String ipAddress, + String natRuleId) { + return new CreateOrUpdateNsxTier1NatRuleCommand(domainId, accountId, zoneId, tier1Gateway, action, ipAddress, natRuleId); + } +} diff --git a/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/core/spring-nsx-core-managers-context.xml b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/core/spring-nsx-core-managers-context.xml new file mode 100644 index 00000000000..7010b8c07f4 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/core/spring-nsx-core-managers-context.xml @@ -0,0 +1,32 @@ + + + + + + + diff --git a/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/module.properties b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/module.properties new file mode 100644 index 00000000000..1630826d102 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/module.properties @@ -0,0 +1,21 @@ +# +# 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. +# + +name=nsx +parent=network 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 new file mode 100644 index 00000000000..d5e3e212de1 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + 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..ee4f4fb64c2 --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/resource/NsxResourceTest.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.resource; + +import com.cloud.network.dao.NetworkVO; +import com.cloud.utils.exception.CloudRuntimeException; +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.Site; +import junit.framework.Assert; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.CreateNsxDistributedFirewallRulesCommand; +import org.apache.cloudstack.agent.api.CreateNsxLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.CreateNsxPortForwardRuleCommand; +import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand; +import org.apache.cloudstack.agent.api.CreateNsxStaticNatCommand; +import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxDistributedFirewallRulesCommand; +import org.apache.cloudstack.agent.api.DeleteNsxNatRuleCommand; +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.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.Mockito; +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.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +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 + TransportZoneListResult transportZoneListResult; + + private static final String transportZone = "Overlay"; + private static final String tier0Gateway = "Tier0-GW01"; + private static final String edgeCluster = "EdgeCluster"; + + private static final long domainId = 1L; + private static final long accountId = 2L; + private static final long zoneId = 1L; + + @Before + public void setup() { + closeable = MockitoAnnotations.openMocks(this); + nsxResource = new NsxResource(); + nsxResource.nsxApiClient = nsxApi; + nsxResource.transportZone = transportZone; + nsxResource.tier0Gateway = tier0Gateway; + nsxResource.edgeCluster = edgeCluster; + } + + @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", tier0Gateway); + params.put("edgeCluster", edgeCluster); + params.put("transportZone", transportZone); + 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(domainId, accountId, zoneId, + 3L, "VPC01", true, false); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertTrue(answer.getResult()); + } + + @Test + public void testCreateNsxTier1GatewayError() { + NsxCommand command = new CreateNsxTier1GatewayCommand(domainId, accountId, zoneId, + 3L, "VPC01", true, false); + Mockito.doThrow(new CloudRuntimeException("ERROR")) + .when(nsxApi).createTier1Gateway(anyString(), anyString(), anyString(), anyBoolean()); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertFalse(answer.getResult()); + } + + @Test + public void testDeleteTier1Gateway() { + NsxCommand command = new DeleteNsxTier1GatewayCommand(domainId, accountId, zoneId, + 2L, "VPC01", true); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertTrue(answer.getResult()); + } + + @Test + public void testDeleteTier1GatewayError() { + NsxCommand command = new DeleteNsxTier1GatewayCommand(domainId, accountId, zoneId, + 2L, "VPC01", true); + Mockito.doThrow(new CloudRuntimeException("ERROR")).when(nsxApi).deleteTier1Gateway(anyString()); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertFalse(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(transportZone).build()); + + NsxCommand command = new CreateNsxSegmentCommand(domainId, accountId, zoneId, + 2L, "VPC01", 3L, "Web", "10.10.10.1", "10.10.10.0/24"); + + when(nsxApi.getDefaultSiteId()).thenReturn("site1"); + + when(nsxApi.getDefaultEnforcementPointPath(anyString())).thenReturn("enforcementPointPath"); + + when(nsxApi.getTransportZones()).thenReturn(transportZoneListResult); + when(transportZoneListResult.getResults()).thenReturn(transportZoneList); + + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertTrue(answer.getResult()); + } + + @Test + public void testCreateNsxSegmentEmptySites() { + when(nsxApi.getDefaultSiteId()).thenReturn(null); + CreateNsxSegmentCommand command = Mockito.mock(CreateNsxSegmentCommand.class); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertFalse(answer.getResult()); + } + + @Test + public void testCreateNsxSegmentEmptyEnforcementPoints() { + Site site = mock(Site.class); + when(nsxApi.getDefaultSiteId()).thenReturn("site1"); + when(nsxApi.getDefaultEnforcementPointPath(anyString())).thenReturn(null); + CreateNsxSegmentCommand command = Mockito.mock(CreateNsxSegmentCommand.class); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertFalse(answer.getResult()); + } + + @Test + public void testCreateNsxSegmentEmptyTransportZones() { + Site site = mock(Site.class); + when(nsxApi.getDefaultSiteId()).thenReturn("site1"); + CreateNsxSegmentCommand command = Mockito.mock(CreateNsxSegmentCommand.class); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertFalse(answer.getResult()); + } + + @Test + public void testDeleteNsxSegment() { + NetworkVO tierNetwork = new NetworkVO(); + tierNetwork.setName("tier1"); + DeleteNsxSegmentCommand command = new DeleteNsxSegmentCommand(domainId, accountId, zoneId, + 3L, "VPC01", 2L, "Web"); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertTrue(answer.getResult()); + } + + @Test + public void testDeleteNsxSegmentError() { + NetworkVO tierNetwork = new NetworkVO(); + tierNetwork.setName("tier1"); + DeleteNsxSegmentCommand command = new DeleteNsxSegmentCommand(domainId, accountId, zoneId, + 3L, "VPC01", 2L, "Web"); + doThrow(new CloudRuntimeException("ERROR")).when(nsxApi).deleteSegment(anyLong(), anyLong(), anyLong(), anyLong(), anyLong(), anyString()); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertFalse(answer.getResult()); + } + + @Test + public void testCreateStaticNat() { + CreateNsxStaticNatCommand cmd = new CreateNsxStaticNatCommand(domainId, accountId, zoneId, 3L, "VPC01", true, 2L, "10.1.12.10", "172.30.20.12"); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(cmd); + assertTrue(answer.getResult()); + } + + @Test + public void testCreatePortForwardRule() { + CreateNsxPortForwardRuleCommand cmd = new CreateNsxPortForwardRuleCommand(domainId, accountId, zoneId, 3L, "VPC01", true, 2L, 5L, "10.1.12.10", "172.30.20.12", "2222", "22", "tcp"); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(cmd); + assertTrue(answer.getResult()); + } + + @Test + public void testDeleteNsxNatRule() { + DeleteNsxNatRuleCommand cmd = new DeleteNsxNatRuleCommand(domainId, accountId, zoneId, 3L, "VPC01", true, 2L, 5L, "22", "tcp"); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(cmd); + assertTrue(answer.getResult()); + } + + @Test + public void testCreateNsxLoadBalancerRule() { + List loadBalancerMembers = List.of(new NsxLoadBalancerMember( + 1L, "172.30.20.12", 6443 + )); + CreateNsxLoadBalancerRuleCommand cmd = new CreateNsxLoadBalancerRuleCommand(domainId, accountId, zoneId, + 3L, "VPC01", true, loadBalancerMembers, 1L, "6443", "6443", "RoundRobin", "TCP"); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(cmd); + assertTrue(answer.getResult()); + } + + + @Test + public void testCreateNsxDistributedFirewallRule() { + List networkRules = List.of(new NsxNetworkRule()); + CreateNsxDistributedFirewallRulesCommand cmd = new CreateNsxDistributedFirewallRulesCommand(domainId, accountId, zoneId, + 3L, 1L, networkRules); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(cmd); + assertTrue(answer.getResult()); + } + + @Test + public void testDeleteNsxDistributedFirewallRule() { + List networkRules = List.of(new NsxNetworkRule()); + DeleteNsxDistributedFirewallRulesCommand cmd = new DeleteNsxDistributedFirewallRulesCommand(domainId, accountId, zoneId, + 3L, 1L, networkRules); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(cmd); + assertTrue(answer.getResult()); + } + + @Test + public void testCreateTier1NatRule() { + long vpcId = 5L; + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(domainId, accountId, zoneId, vpcId, true); + CreateOrUpdateNsxTier1NatRuleCommand command = new CreateOrUpdateNsxTier1NatRuleCommand(domainId, accountId, zoneId, + tier1GatewayName, "SNAT", "10.1.10.10", "natRuleId"); + NsxAnswer answer = (NsxAnswer) nsxResource.executeRequest(command); + assertTrue(answer.getResult()); + } +} diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java new file mode 100644 index 00000000000..a0fde08ade8 --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java @@ -0,0 +1,96 @@ +// 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.Network; +import com.vmware.nsx_policy.infra.domains.Groups; +import com.vmware.nsx_policy.model.Group; +import com.vmware.nsx_policy.model.PathExpression; +import com.vmware.vapi.bindings.Service; +import org.apache.cloudstack.resource.NsxNetworkRule; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockedConstruction; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.List; +import java.util.function.Function; + +public class NsxApiClientTest { + + @Mock + private Function, Service> nsxService; + @Mock + private Groups groupService; + + private NsxApiClient client = new NsxApiClient(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + client.nsxService = nsxService; + Mockito.when(nsxService.apply(Groups.class)).thenReturn(groupService); + } + + @Test + public void testCreateGroupForSegment() { + final Group[] groups = new Group[1]; + final PathExpression[] pathExpressions = new PathExpression[1]; + try (MockedConstruction ignored = Mockito.mockConstruction(Group.class, (mock, context) -> { + groups[0] = mock; + }); MockedConstruction ignoredExp = Mockito.mockConstruction(PathExpression.class, (mock, context) -> { + pathExpressions[0] = mock; + }) + ) { + String segmentName = "segment1"; + client.createGroupForSegment(segmentName); + Mockito.verify(groupService).patch(NsxApiClient.DEFAULT_DOMAIN, segmentName, groups[0]); + String segmentPath = String.format("%s/%s", NsxApiClient.SEGMENTS_PATH, segmentName); + Mockito.verify(groups[0]).setExpression(List.of(pathExpressions[0])); + Mockito.verify(pathExpressions[0]).setPaths(List.of(segmentPath)); + } + } + + @Test + public void testGetGroupsForTrafficIngress() { + NsxNetworkRule rule = Mockito.mock(NsxNetworkRule.class); + Mockito.when(rule.getSourceCidrList()).thenReturn(List.of("ANY")); + Mockito.when(rule.getTrafficType()).thenReturn("Ingress"); + Mockito.when(rule.getService()).thenReturn(Network.Service.NetworkACL); + String segmentName = "segment"; + List sourceGroups = client.getGroupsForTraffic(rule, segmentName, true); + List destinationGroups = client.getGroupsForTraffic(rule, segmentName, false); + Assert.assertEquals(List.of("ANY"), sourceGroups); + Assert.assertEquals(List.of(String.format("%s/%s", NsxApiClient.GROUPS_PATH_PREFIX, segmentName)), destinationGroups); + } + + @Test + public void testGetGroupsForTrafficEgress() { + NsxNetworkRule rule = Mockito.mock(NsxNetworkRule.class); + Mockito.when(rule.getSourceCidrList()).thenReturn(List.of("ANY")); + Mockito.when(rule.getTrafficType()).thenReturn("Egress"); + Mockito.when(rule.getService()).thenReturn(Network.Service.NetworkACL); + String segmentName = "segment"; + List sourceGroups = client.getGroupsForTraffic(rule, segmentName, true); + List destinationGroups = client.getGroupsForTraffic(rule, segmentName, false); + Assert.assertEquals(List.of(String.format("%s/%s", NsxApiClient.GROUPS_PATH_PREFIX, segmentName)), sourceGroups); + Assert.assertEquals(List.of("ANY"), destinationGroups); + } +} 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..ff7fa5427ee --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java @@ -0,0 +1,493 @@ +// 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.api.ApiDBUtils; +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.hypervisor.Hypervisor; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LoadBalancerVMMapDao; +import com.cloud.network.dao.LoadBalancerVO; +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.lb.LoadBalancingRule; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.PortForwardingRuleVO; +import com.cloud.network.rules.StaticNatImpl; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.NetworkACLItemVO; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.resource.ResourceManager; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.utils.Pair; +import com.cloud.utils.net.Ip; +import com.cloud.vm.NicVO; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.resource.NsxNetworkRule; +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.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +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; + @Mock + IPAddressDao ipAddressDao; + @Mock + VMInstanceDao vmInstanceDao; + @Mock + VpcDao vpcDao; + @Mock + UserVmDao userVmDao; + @Mock + private VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + @Mock + LoadBalancerVMMapDao lbVmMapDao; + + NsxElement nsxElement; + ReservationContext reservationContext; + DeployDestination deployDestination; + @Mock + DomainDao domainDao; + + @Before + public void setup() throws NoSuchFieldException, IllegalAccessException { + 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; + nsxElement.vpcOfferingServiceMapDao = vpcOfferingServiceMapDao; + nsxElement.ipAddressDao = ipAddressDao; + nsxElement.vmInstanceDao = vmInstanceDao; + nsxElement.vpcDao = vpcDao; + nsxElement.lbVmMapDao = lbVmMapDao; + + Field field = ApiDBUtils.class.getDeclaredField("s_ipAddressDao"); + field.setAccessible(true); + field.set(null, ipAddressDao); + + field = ApiDBUtils.class.getDeclaredField("s_userVmDao"); + field.setAccessible(true); + field.set(null, userVmDao); + 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 { + 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)); + } + + @Test + public void testTransformActionValue() { + NsxNetworkRule.NsxRuleAction action = nsxElement.transformActionValue(NetworkACLItem.Action.Deny); + Assert.assertEquals(NsxNetworkRule.NsxRuleAction.DROP, action); + } + + @Test + public void testTransformCidrListValuesEmptyList() { + List values = nsxElement.transformCidrListValues(null); + Assert.assertNotNull(values); + Assert.assertTrue(values.isEmpty()); + } + + @Test + public void testTransformCidrListValuesList() { + List values = nsxElement.transformCidrListValues(List.of("0.0.0.0/0")); + Assert.assertEquals(1, values.size()); + Assert.assertEquals("ANY", values.get(0)); + } + + @Test + public void testCanHandleService() { + when(networkModel.isProviderForNetwork(any(Network.Provider.class), anyLong())).thenReturn(true); + + Network.Service service = new Network.Service("service1", new Network.Capability("capability")); + NetworkVO network = new NetworkVO(); + network.setName("network1"); + assertTrue(nsxElement.canHandle(network, service)); + } + + @Test + public void testApplyStaticNatRules() throws ResourceUnavailableException { + StaticNatImpl rule = new StaticNatImpl(1L , 1L, 3L, 7L, "172.30.10.15", false); + NetworkVO networkVO = new NetworkVO(1L, Networks.TrafficType.Public, Networks.Mode.Static, + Networks.BroadcastDomainType.NSX, 12L, 2L, 5L, 1L, "network1", + "network1", null, Network.GuestType.Isolated, 2L, 2L, + ControlledEntity.ACLType.Domain, false, 1L, false ); + + Ip ip = new Ip("10.1.13.15"); + IPAddressVO ipAddress = new IPAddressVO(ip, 2L, 0xaabbccddeeffL, 3L, false); + ipAddress.setAssociatedWithVmId(10L); + + VMInstanceVO vm = new VMInstanceVO(10L, 9L, "vm1", "i-5-10-VM" , VirtualMachine.Type.User, + 18L, Hypervisor.HypervisorType.VMware, 26L, + 2L, 5L, 6L, false, false); + + NicVO nic = Mockito.mock(NicVO.class); + VpcVO vpc = Mockito.mock(VpcVO.class); + + when(ipAddressDao.findByIdIncludingRemoved(anyLong())).thenReturn(ipAddress); + when(vmInstanceDao.findByIdIncludingRemoved(anyLong())).thenReturn(vm); + when(networkModel.getNicInNetworkIncludingRemoved(anyLong(), anyLong())).thenReturn(nic); + when(vpcDao.findById(anyLong())).thenReturn(vpc); + when(vpc.getId()).thenReturn(1L); + when(vpc.getName()).thenReturn("vpc1"); + when(nsxService.createStaticNatRule(anyLong(), anyLong(), anyLong(), anyLong(), anyString(), anyBoolean(), anyLong(), anyString(), anyString())).thenReturn(true); + + assertTrue(nsxElement.applyStaticNats(networkVO, List.of(rule))); + } + + @Test + public void testApplyPFRules_add() throws ResourceUnavailableException { + NetworkVO networkVO = new NetworkVO(1L, Networks.TrafficType.Public, Networks.Mode.Static, + Networks.BroadcastDomainType.NSX, 12L, 2L, 5L, 1L, "network1", + "network1", null, Network.GuestType.Isolated, 2L, 2L, + ControlledEntity.ACLType.Domain, false, 1L, false ); + PortForwardingRuleVO rule = new PortForwardingRuleVO("1", 11L, 80, 90, new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L, + 5L, 2L, 15L); + rule.setState(FirewallRule.State.Add); + Network.Service service = new Network.Service("service1", new Network.Capability("capability")); + + when(nsxElement.canHandle(networkVO, service)).thenReturn(true); + assertTrue(nsxElement.applyPFRules(networkVO, List.of(rule))); + } + + @Test + public void testApplyPFRules_delete() throws ResourceUnavailableException { + NetworkVO networkVO = new NetworkVO(1L, Networks.TrafficType.Public, Networks.Mode.Static, + Networks.BroadcastDomainType.NSX, 12L, 2L, 5L, 1L, "network1", + "network1", null, Network.GuestType.Isolated, 2L, 2L, + ControlledEntity.ACLType.Domain, false, 1L, false ); + PortForwardingRuleVO rule = new PortForwardingRuleVO("1", 11L, 80, 90, new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L, + 5L, 2L, 15L); + rule.setState(FirewallRule.State.Revoke); + Network.Service service = new Network.Service("service1", new Network.Capability("capability")); + VpcVO vpcVO = Mockito.mock(VpcVO.class); + when(vpcDao.findById(1L)).thenReturn(vpcVO); + when(vpcVO.getDomainId()).thenReturn(2L); + IPAddressVO ipAddress = new IPAddressVO(new Ip("10.1.13.10"), 1L, 1L, 1L,false); + when(ApiDBUtils.findIpAddressById(anyLong())).thenReturn(ipAddress); + when(nsxElement.canHandle(networkVO, service)).thenReturn(true); + when(nsxService.deletePortForwardRule(any(NsxNetworkRule.class))).thenReturn(true); + assertTrue(nsxElement.applyPFRules(networkVO, List.of(rule))); + } + + @Test + public void testGetVpcOrNetworkReturnsVpcIfVpcIdPresent() { + VpcVO vpc = new VpcVO(); + when(vpcDao.findById(anyLong())).thenReturn(vpc); + + Pair vpcNetworkPair = nsxElement.getVpcOrNetwork(1L, 1L); + assertNotNull(vpcNetworkPair.first()); + assertNull(vpcNetworkPair.second()); + } + + @Test + public void testGetVpcOrNetworkReturnsNetworkIfVpcIdNotPresent() { + NetworkVO network = new NetworkVO(); + when(networkDao.findById(anyLong())).thenReturn(network); + + Pair vpcNetworkPair = nsxElement.getVpcOrNetwork(null, 1L); + assertNull(vpcNetworkPair.first()); + assertNotNull(vpcNetworkPair.second()); + } + + private Method getPublicPortRangeMethod() throws NoSuchMethodException { + Method method = NsxElement.class.getDeclaredMethod("getPublicPortRange", PortForwardingRule.class); + method.setAccessible(true); + return method; + } + + private Method getPrivatePFPortRangeMethod() throws NoSuchMethodException { + Method method = NsxElement.class.getDeclaredMethod("getPrivatePFPortRange", PortForwardingRule.class); + method.setAccessible(true); + return method; + } + + private Method getPrivatePortRangeMethod() throws NoSuchMethodException { + Method method = NsxElement.class.getDeclaredMethod("getPrivatePortRange", FirewallRule.class); + method.setAccessible(true); + return method; + } + + private Method getPrivatePortRangeForACLRuleMethod() throws NoSuchMethodException { + Method method = NsxElement.class.getDeclaredMethod("getPrivatePortRangeForACLRule", NetworkACLItem.class); + method.setAccessible(true); + return method; + } + + @Test + public void testGetPublicPortRangeWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 90, new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L, + 5L, 2L, 15L); + assertEquals("80-90", getPublicPortRangeMethod().invoke(null, rule)); + } + + @Test + public void testGetPublicPortRangeWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 80, new Ip("172.30.10.11"), 8080, 8080, "tcp", 12L, + 5L, 2L, 15L); + assertEquals("80", getPublicPortRangeMethod().invoke(null, rule)); + } + + @Test + public void testGetPrivatePFPortRangeWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 90, new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L, + 5L, 2L, 15L); + assertEquals("8080-8090", getPrivatePFPortRangeMethod().invoke(null, rule)); + } + + @Test + public void testGetPrivatePFPortRangeWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 80, new Ip("172.30.10.11"), 8080, 8080, "tcp", 12L, + 5L, 2L, 15L); + assertEquals("8080", getPrivatePFPortRangeMethod().invoke(null, rule)); + } + + @Test + public void testGetPrivatePortRangeWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 80, "tcp", 23L, 5L, 2L, + FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), null, null, null, null, FirewallRule.TrafficType.Egress, FirewallRule.FirewallRuleType.User); + assertEquals("80", getPrivatePortRangeMethod().invoke(null, rule)); + } + + @Test + public void testGetPrivatePortRangeWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 90, "tcp", 23L, 5L, 2L, + FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), null, null, null, null, FirewallRule.TrafficType.Egress, FirewallRule.FirewallRuleType.User); + assertEquals("80-90", getPrivatePortRangeMethod().invoke(null, rule)); + } + + @Test + public void testGetPrivatePortRangeForACLWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + NetworkACLItem rule = new NetworkACLItemVO(80, 80, "udp", 10L, List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, NetworkACLItem.Action.Allow, + 2, null); + assertEquals("80", getPrivatePortRangeForACLRuleMethod().invoke(null, rule)); + } + + @Test + public void testGetPrivatePortRangeForACLWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + NetworkACLItem rule = new NetworkACLItemVO(80, 90, "udp", 10L, List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, NetworkACLItem.Action.Allow, + 2, null); + assertEquals("80-90", getPrivatePortRangeForACLRuleMethod().invoke(null, rule)); + } + + @Test + public void testApplyLBRules_add() throws ResourceUnavailableException { + NetworkVO networkVO = new NetworkVO(1L, Networks.TrafficType.Public, Networks.Mode.Static, + Networks.BroadcastDomainType.NSX, 12L, 2L, 5L, 1L, "network1", + "network1", null, Network.GuestType.Isolated, 2L, 2L, + ControlledEntity.ACLType.Domain, false, 1L, false ); + LoadBalancerVO lb = new LoadBalancerVO(null, null, null, 0L, 8080, 8081, null, 0L, 0L, 1L, null, null); + lb.setState(FirewallRule.State.Add); + LoadBalancingRule.LbDestination destination = new LoadBalancingRule.LbDestination(6443, 6443, "172.30.110.11", false); + LoadBalancingRule rule = new LoadBalancingRule(lb, List.of(destination), null, null, new Ip("10.1.13.10"), null, "TCP"); + + VpcVO vpc = Mockito.mock(VpcVO.class); + + IPAddressVO ipAddress = new IPAddressVO(new Ip("10.1.13.10"), 1L, 1L, 1L,false); + when(vpcDao.findById(anyLong())).thenReturn(vpc); + when(vpc.getDomainId()).thenReturn(2L); + when(vpc.getAccountId()).thenReturn(5L); + when(ipAddressDao.findByIpAndDcId(anyLong(), anyString())).thenReturn(ipAddress); + when(nsxService.createLbRule(any(NsxNetworkRule.class))).thenReturn(true); + + assertTrue(nsxElement.applyLBRules(networkVO, List.of(rule))); + } + + @Test + public void testApplyLBRules_delete() throws ResourceUnavailableException { + NetworkVO networkVO = new NetworkVO(1L, Networks.TrafficType.Public, Networks.Mode.Static, + Networks.BroadcastDomainType.NSX, 12L, 2L, 5L, 1L, "network1", + "network1", null, Network.GuestType.Isolated, 2L, 2L, + ControlledEntity.ACLType.Domain, false, 1L, false ); + LoadBalancerVO lb = new LoadBalancerVO(null, null, null, 0L, 8080, 8081, null, 0L, 0L, 1L, null, null); + lb.setState(FirewallRule.State.Revoke); + LoadBalancingRule.LbDestination destination = new LoadBalancingRule.LbDestination(6443, 6443, "172.30.110.11", false); + LoadBalancingRule rule = new LoadBalancingRule(lb, List.of(destination), null, null, new Ip("10.1.13.10"), null, "TCP"); + + VpcVO vpc = Mockito.mock(VpcVO.class); + + IPAddressVO ipAddress = new IPAddressVO(new Ip("10.1.13.10"), 1L, 1L, 1L,false); + when(vpcDao.findById(anyLong())).thenReturn(vpc); + when(vpc.getDomainId()).thenReturn(2L); + when(vpc.getAccountId()).thenReturn(5L); + when(ipAddressDao.findByIpAndDcId(anyLong(), anyString())).thenReturn(ipAddress); + when(nsxService.deleteLbRule(any(NsxNetworkRule.class))).thenReturn(true); + + assertTrue(nsxElement.applyLBRules(networkVO, List.of(rule))); + } + + @Test + public void testApplyNetworkAclRules() throws ResourceUnavailableException { + NetworkVO networkVO = new NetworkVO(1L, Networks.TrafficType.Public, Networks.Mode.Static, + Networks.BroadcastDomainType.NSX, 12L, 2L, 5L, 1L, "network1", + "network1", null, Network.GuestType.Isolated, 2L, 2L, + ControlledEntity.ACLType.Domain, false, 1L, false ); + NetworkACLItem rule = new NetworkACLItemVO(80, 80, "udp", 10L, List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, NetworkACLItem.Action.Allow, + 2, null); + Network.Service service = new Network.Service("service1", new Network.Capability("capability")); + + when(nsxElement.canHandle(networkVO, service)).thenReturn(true); + assertTrue(nsxElement.applyNetworkACLs(networkVO, List.of(rule))); + } + + @Test + public void testDeleteNetworkAclRules() throws ResourceUnavailableException { + NetworkVO networkVO = new NetworkVO(1L, Networks.TrafficType.Public, Networks.Mode.Static, + Networks.BroadcastDomainType.NSX, 12L, 2L, 5L, 1L, "network1", + "network1", null, Network.GuestType.Isolated, 2L, 2L, + ControlledEntity.ACLType.Domain, false, 1L, false ); + NetworkACLItemVO rule = new NetworkACLItemVO(80, 80, "udp", 10L, List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, NetworkACLItem.Action.Allow, + 2, null); + rule.setState(NetworkACLItem.State.Revoke); + Network.Service service = new Network.Service("service1", new Network.Capability("capability")); + + when(nsxElement.canHandle(networkVO, service)).thenReturn(true); + when(nsxService.deleteFirewallRules(any(Network.class), any(List.class))).thenReturn(true); + assertTrue(nsxElement.applyNetworkACLs(networkVO, List.of(rule))); + } + + @Test + public void testApplyFirewallRules() throws ResourceUnavailableException { + NetworkVO networkVO = new NetworkVO(1L, Networks.TrafficType.Public, Networks.Mode.Static, + Networks.BroadcastDomainType.NSX, 12L, 2L, 5L, 1L, "network1", + "network1", null, Network.GuestType.Isolated, 2L, 2L, + ControlledEntity.ACLType.Domain, false, 1L, false ); + FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 80, "tcp", 23L, 5L, 2L, + FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), null, null, null, null, FirewallRule.TrafficType.Egress, FirewallRule.FirewallRuleType.User); + Network.Service service = new Network.Service("service1", new Network.Capability("capability")); + + when(nsxElement.canHandle(networkVO, service)).thenReturn(true); + when(nsxService.addFirewallRules(any(Network.class), any(List.class))).thenReturn(true); + assertTrue(nsxElement.applyFWRules(networkVO, List.of(rule))); + } + + @Test + public void testRevokeFirewallRules() throws ResourceUnavailableException { + NetworkVO networkVO = new NetworkVO(1L, Networks.TrafficType.Public, Networks.Mode.Static, + Networks.BroadcastDomainType.NSX, 12L, 2L, 5L, 1L, "network1", + "network1", null, Network.GuestType.Isolated, 2L, 2L, + ControlledEntity.ACLType.Domain, false, 1L, false ); + FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 80, "tcp", 23L, 5L, 2L, + FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), null, null, null, null, FirewallRule.TrafficType.Egress, FirewallRule.FirewallRuleType.User); + rule.setState(FirewallRule.State.Revoke); + Network.Service service = new Network.Service("service1", new Network.Capability("capability")); + + when(nsxElement.canHandle(networkVO, service)).thenReturn(true); + when(nsxService.deleteFirewallRules(any(Network.class), any(List.class))).thenReturn(true); + when(nsxService.addFirewallRules(any(Network.class), any(List.class))).thenReturn(true); + assertTrue(nsxElement.applyFWRules(networkVO, List.of(rule))); + } +} 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..66b9684203b --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxGuestNetworkGuruTest.java @@ -0,0 +1,329 @@ +// 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.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.network.IpAddressManager; +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.guru.GuestNetworkGuru; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; +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.utils.Pair; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachine; +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.agent.api.CreateNsxTier1GatewayCommand; +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.ArgumentMatchers.nullable; +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; + @Mock + IpAddressManager ipAddressManager; + @Mock + NetworkOfferingDao networkOfferingDao; + + NsxGuestNetworkGuru guru; + AutoCloseable closeable; + + @Before + public void setUp() throws IllegalAccessException, NoSuchFieldException { + closeable = MockitoAnnotations.openMocks(this); + guru = new NsxGuestNetworkGuru(); + + ReflectionTestUtils.setField(guru, "_dcDao", dcDao); + ReflectionTestUtils.setField(guru, "_networkDao", networkDao); + ReflectionTestUtils.setField(guru, "_networkModel", networkModel); + ReflectionTestUtils.setField(guru, "_vpcDao", vpcDao); + ReflectionTestUtils.setField((GuestNetworkGuru) guru, "_ipAddrMgr", ipAddressManager); + ReflectionTestUtils.setField((GuestNetworkGuru) guru, "_networkModel", networkModel); + ReflectionTestUtils.setField((GuestNetworkGuru) guru, "networkOfferingDao", networkOfferingDao); + ReflectionTestUtils.setField((GuestNetworkGuru) guru, "_physicalNetworkDao", physicalNetworkDao); + + 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.getNsxMode()).thenReturn(NetworkOffering.NsxMode.NATTED.name()); + 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()); + } + + @Test + public void testAllocateForUserVM() throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + Network network = Mockito.mock(Network.class); + NicProfile nicProfile = Mockito.mock(NicProfile.class); + VirtualMachineProfile vmProfile = Mockito.mock(VirtualMachineProfile.class); + VirtualMachine virtualMachine = Mockito.mock(VirtualMachine.class); + Pair dns = new Pair<>("10.1.5.1", "8.8.8.8"); + String macAddress = "00:00:00:11:1D:1E:CD"; + + when(network.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + when(vmProfile.getVirtualMachine()).thenReturn(virtualMachine); + when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.User); + when(networkModel.getNetworkIp4Dns(any(Network.class), nullable(DataCenter.class))).thenReturn(dns); + when(nicProfile.getMacAddress()).thenReturn(macAddress); + when(networkOfferingDao.isIpv6Supported(anyLong())).thenReturn(false); + + NicProfile profile = guru.allocate(network, nicProfile, vmProfile); + assertNotNull(profile); + } + + @Test + public void testAllocateForDomainRouter() throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + Network network = Mockito.mock(Network.class); + NicProfile nicProfile = Mockito.mock(NicProfile.class); + VirtualMachineProfile vmProfile = Mockito.mock(VirtualMachineProfile.class); + VirtualMachine virtualMachine = Mockito.mock(VirtualMachine.class); + Pair dns = new Pair<>("10.1.5.1", "8.8.8.8"); + String macAddress = "00:00:00:11:1D:1E:CD"; + + when(network.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + when(vmProfile.getType()).thenReturn(VirtualMachine.Type.DomainRouter); + when(vmProfile.getVirtualMachine()).thenReturn(virtualMachine); + when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.DomainRouter); + when(network.getId()).thenReturn(2L); + when(nicProfile.getMacAddress()).thenReturn(macAddress); + when(networkOfferingDao.isIpv6Supported(anyLong())).thenReturn(false); + when(network.getDataCenterId()).thenReturn(1L); + when(network.getAccountId()).thenReturn(5L); + when(network.getVpcId()).thenReturn(51L); + when(dcDao.findById(anyLong())).thenReturn(Mockito.mock(DataCenterVO.class)); + when(accountDao.findById(anyLong())).thenReturn(Mockito.mock(AccountVO.class)); + when(vpcDao.findById(anyLong())).thenReturn(Mockito.mock(VpcVO.class)); + when(domainDao.findById(anyLong())).thenReturn(Mockito.mock(DomainVO.class)); + when(nicProfile.getIPv4Address()).thenReturn("10.1.13.10"); + when(nsxControllerUtils.sendNsxCommand(any(CreateNsxDhcpRelayConfigCommand.class), + anyLong())).thenReturn(new NsxAnswer(new NsxCommand(), true, "")); + + NicProfile profile = guru.allocate(network, nicProfile, vmProfile); + + assertNotNull(profile); + verify(nsxControllerUtils, times(1)).sendNsxCommand(any(CreateNsxDhcpRelayConfigCommand.class), + anyLong()); + } + + @Test + public void testCreateNsxSegmentForVpc() { + NetworkVO networkVO = Mockito.mock(NetworkVO.class); + DataCenter dataCenter = Mockito.mock(DataCenter.class); + + when(networkVO.getAccountId()).thenReturn(1L); + when(nsxControllerUtils.sendNsxCommand(any(CreateNsxSegmentCommand.class), + anyLong())).thenReturn(new NsxAnswer(new NsxCommand(), true, "")); + guru.createNsxSegment(networkVO, dataCenter); + verify(nsxControllerUtils, times(1)).sendNsxCommand(any(CreateNsxSegmentCommand.class), + anyLong()); + } + + + @Test + public void testCreateNsxSegmentForIsolatedNetwork() { + NetworkVO networkVO = Mockito.mock(NetworkVO.class); + NetworkOfferingVO offeringVO = Mockito.mock(NetworkOfferingVO.class); + DataCenter dataCenter = Mockito.mock(DataCenter.class); + + when(networkVO.getAccountId()).thenReturn(1L); + when(networkVO.getVpcId()).thenReturn(null); + when(nsxControllerUtils.sendNsxCommand(any(CreateNsxTier1GatewayCommand.class), + anyLong())).thenReturn(new NsxAnswer(new NsxCommand(), true, "")); + when(nsxControllerUtils.sendNsxCommand(any(CreateNsxSegmentCommand.class), + anyLong())).thenReturn(new NsxAnswer(new NsxCommand(), true, "")); + when(networkVO.getNetworkOfferingId()).thenReturn(1L); + when(networkOfferingDao.findById(1L)).thenReturn(offeringVO); + when(offeringVO.getNsxMode()).thenReturn(NetworkOffering.NsxMode.NATTED.name()); + guru.createNsxSegment(networkVO, dataCenter); + verify(nsxControllerUtils, times(1)).sendNsxCommand(any(CreateNsxTier1GatewayCommand.class), + anyLong()); + verify(nsxControllerUtils, times(1)).sendNsxCommand(any(CreateNsxSegmentCommand.class), + anyLong()); + } +} 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..cb6f6511d24 --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxProviderServiceImplTest.java @@ -0,0 +1,174 @@ +// 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.Network; +import com.cloud.network.Networks; +import com.cloud.network.nsx.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.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; +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("EdgeCluster", response.getEdgeCluster()); + assertEquals("Tier0Gw", response.getTier0Gateway()); + assertEquals("Overlay", response.getTransportZone()); + assertEquals("ZoneNSX", response.getZoneName()); + } + + @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)); + } + + @Test + public void testNetworkStateValidation() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + NetworkVO networkVO = Mockito.mock(NetworkVO.class); + List networkVOList = List.of(networkVO); + when(networkVO.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.NSX); + when(networkVO.getState()).thenReturn(Network.State.Allocated); + + NsxProviderServiceImpl nsxProviderService = new NsxProviderServiceImpl(); + + assertThrows(CloudRuntimeException.class, () -> nsxProviderService.validateNetworkState(networkVOList)); + } +} diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxPublicNetworkGuruTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxPublicNetworkGuruTest.java new file mode 100644 index 00000000000..da21bf11b64 --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxPublicNetworkGuruTest.java @@ -0,0 +1,178 @@ +// 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.VlanDetailsVO; +import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.guru.PublicNetworkGuru; +import com.cloud.network.vpc.VpcOfferingVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.user.Account; +import com.cloud.utils.net.Ip; +import com.cloud.vm.NicProfile; +import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; +import org.apache.cloudstack.agent.api.NsxCommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.utils.NsxControllerUtils; +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 org.springframework.test.util.ReflectionTestUtils; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.times; + +@RunWith(MockitoJUnitRunner.class) +public class NsxPublicNetworkGuruTest { + + NetworkOffering offering; + + NsxPublicNetworkGuru guru; + @Mock + NsxServiceImpl nsxService; + @Mock + IPAddressDao ipAddressDao; + @Mock + VpcDao vpcDao; + @Mock + VlanDetailsDao vlanDetailsDao; + @Mock + VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + @Mock + VpcOfferingDao vpcOfferingDao; + @Mock + NsxControllerUtils nsxControllerUtils; + + @Before + public void setup() { + guru = new NsxPublicNetworkGuru(); + + ReflectionTestUtils.setField((PublicNetworkGuru) guru, "_ipAddressDao", ipAddressDao); + ReflectionTestUtils.setField(guru, "vpcDao", vpcDao); + ReflectionTestUtils.setField(guru, "vlanDetailsDao", vlanDetailsDao); + ReflectionTestUtils.setField(guru, "vpcOfferingServiceMapDao", vpcOfferingServiceMapDao); + ReflectionTestUtils.setField(guru, "nsxService", nsxService); + ReflectionTestUtils.setField(guru, "vpcOfferingDao", vpcOfferingDao); + ReflectionTestUtils.setField(guru, "nsxControllerUtils", nsxControllerUtils); + + offering = Mockito.mock(NetworkOffering.class); + when(offering.getTrafficType()).thenReturn(Networks.TrafficType.Public); + when(offering.isForNsx()).thenReturn(true); + when(offering.isSystemOnly()).thenReturn(true); + } + + @Test + public void testCanHandle() { + Assert.assertTrue(guru.canHandle(offering)); + } + + @Test + public void testCannotHandle() { + NetworkOffering offering = Mockito.mock(NetworkOffering.class); + + when(offering.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + + Assert.assertFalse(guru.canHandle(offering)); + } + + @Test + public void testDesign() { + DeploymentPlan plan = Mockito.mock(DeploymentPlan.class); + Network network = Mockito.mock(Network.class); + Account account = Mockito.mock(Account.class); + +// when(network.getTrafficType()).thenReturn(Networks.TrafficType.Public); + + Network designedNetwork = guru.design(offering, plan, network, "net1", 1L, account); + Assert.assertEquals(Networks.TrafficType.Public, designedNetwork.getTrafficType()); + } + + @Test + public void testDesign_whenOfferingIsForGuestTraffic() { + DeploymentPlan plan = Mockito.mock(DeploymentPlan.class); + Network network = Mockito.mock(Network.class); + Account account = Mockito.mock(Account.class); + + when(offering.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + + Network designedNetwork = guru.design(offering, plan, network, "net1", 1L, account); + Assert.assertNull(designedNetwork); + } + + @Test + public void testAllocate() throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + String publicIpVR = "10.1.12.10"; + String publicIpNSX = "10.1.13.10"; + Network network = Mockito.mock(Network.class); + NicProfile profile = Mockito.mock(NicProfile.class); + VirtualMachineProfile vmProfile = Mockito.mock(VirtualMachineProfile.class); + IPAddressVO srcNatIpOnVR = new IPAddressVO(new Ip(publicIpVR), 2L , 0xaabbccddeeffL, 2L, true); + srcNatIpOnVR.setVpcId(12L); + IPAddressVO srcNatIpOnNSX = new IPAddressVO(new Ip(publicIpNSX), 2L , 0xaabbccddeeffL, 3L, true); + srcNatIpOnNSX.setVpcId(12L); + VpcVO vpcVO = Mockito.mock(VpcVO.class); + List sourceNatList = List.of(srcNatIpOnNSX); + VlanDetailsVO vlanDetailVO = new VlanDetailsVO(3L,ApiConstants.NSX_DETAIL_KEY, "true", false); + VpcOfferingVO vpcOffering = Mockito.mock(VpcOfferingVO.class); + + + when(profile.getIPv4Address()).thenReturn(publicIpVR); + when(ipAddressDao.findByIp(anyString())).thenReturn(srcNatIpOnVR); + when(vpcDao.findById(anyLong())).thenReturn(vpcVO); + when(ipAddressDao.listByAssociatedVpc(12L, true)).thenReturn(sourceNatList); + when(vlanDetailsDao.findDetail(anyLong(), anyString())).thenReturn(vlanDetailVO); + when(vpcVO.getVpcOfferingId()).thenReturn(12L); + when(vpcVO.getId()).thenReturn(12L); + when(vpcVO.getName()).thenReturn("nsxVPCNet"); + when(vpcOfferingServiceMapDao.areServicesSupportedByVpcOffering(anyLong(), any())).thenReturn(true); + when(nsxService.createVpcNetwork(anyLong(), anyLong(), anyLong(), anyLong(), anyString(), anyBoolean())).thenReturn(true); + when(vpcOfferingDao.findById(anyLong())).thenReturn(vpcOffering); + when(vpcOffering.getNsxMode()).thenReturn(NetworkOffering.NsxMode.NATTED.name()); + when(nsxControllerUtils.sendNsxCommand(any(CreateOrUpdateNsxTier1NatRuleCommand.class), + anyLong())).thenReturn(new NsxAnswer(new NsxCommand(), true, "")); + + guru.allocate(network, profile, vmProfile); + + verify(nsxControllerUtils, times(1)).sendNsxCommand(any(CreateOrUpdateNsxTier1NatRuleCommand.class), + anyLong()); + + } +} 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..41f47bc610e --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxServiceImplTest.java @@ -0,0 +1,162 @@ +// 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.IpAddress; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.utils.net.Ip; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.CreateNsxStaticNatCommand; +import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxNatRuleCommand; +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.Mockito; +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.ArgumentMatchers.eq; +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; + + private static final long domainId = 1L; + private static final long accountId = 2L; + private static final long zoneId = 1L; + + @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", false)); + } + + @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 testDeleteNetworkOnVpc() { + NetworkVO network = new NetworkVO(); + network.setVpcId(1L); + 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(zoneId, accountId, domainId, network)); + } + + @Test + public void testDeleteNetwork() { + NetworkVO network = new NetworkVO(); + network.setVpcId(null); + NsxAnswer deleteNsxSegmentAnswer = mock(NsxAnswer.class); + when(deleteNsxSegmentAnswer.getResult()).thenReturn(true); + when(nsxControllerUtils.sendNsxCommand(any(DeleteNsxSegmentCommand.class), anyLong())).thenReturn(deleteNsxSegmentAnswer); + NsxAnswer deleteNsxTier1GatewayAnswer = mock(NsxAnswer.class); + when(deleteNsxTier1GatewayAnswer.getResult()).thenReturn(true); + when(nsxControllerUtils.sendNsxCommand(any(DeleteNsxTier1GatewayCommand.class), anyLong())).thenReturn(deleteNsxTier1GatewayAnswer); + assertTrue(nsxService.deleteNetwork(zoneId, accountId, domainId, network)); + } + + @Test + public void testUpdateVpcSourceNatIp() { + VpcVO vpc = mock(VpcVO.class); + IpAddress ipAddress = mock(IpAddress.class); + Ip ip = Mockito.mock(Ip.class); + when(ip.addr()).thenReturn("10.1.10.10"); + when(ipAddress.getAddress()).thenReturn(ip); + long vpcId = 1L; + when(vpc.getAccountId()).thenReturn(accountId); + when(vpc.getDomainId()).thenReturn(domainId); + when(vpc.getZoneId()).thenReturn(zoneId); + when(vpc.getId()).thenReturn(vpcId); + NsxAnswer answer = mock(NsxAnswer.class); + when(answer.getResult()).thenReturn(true); + when(nsxControllerUtils.sendNsxCommand(any(CreateOrUpdateNsxTier1NatRuleCommand.class), eq(zoneId))).thenReturn(answer); + nsxService.updateVpcSourceNatIp(vpc, ipAddress); + Mockito.verify(nsxControllerUtils).sendNsxCommand(any(CreateOrUpdateNsxTier1NatRuleCommand.class), eq(zoneId)); + } + + @Test + public void testCreateStaticNatRule() { + long networkId = 1L; + String networkName = "Network-Test"; + long vmId = 1L; + String publicIp = "10.10.1.10"; + String vmIp = "192.168.1.20"; + NsxAnswer answer = Mockito.mock(NsxAnswer.class); + when(answer.getResult()).thenReturn(true); + when(nsxControllerUtils.sendNsxCommand(any(CreateNsxStaticNatCommand.class), eq(zoneId))).thenReturn(answer); + nsxService.createStaticNatRule(zoneId, domainId, accountId, + networkId, networkName, true, vmId, publicIp, vmIp); + Mockito.verify(nsxControllerUtils).sendNsxCommand(any(CreateNsxStaticNatCommand.class), eq(zoneId)); + } + + @Test + public void testDeleteStaticNatRule() { + long networkId = 1L; + String networkName = "Network-Test"; + NsxAnswer answer = Mockito.mock(NsxAnswer.class); + when(answer.getResult()).thenReturn(true); + when(nsxControllerUtils.sendNsxCommand(any(DeleteNsxNatRuleCommand.class), eq(zoneId))).thenReturn(answer); + nsxService.deleteStaticNatRule(zoneId, domainId, accountId, networkId, networkName, true); + Mockito.verify(nsxControllerUtils).sendNsxCommand(any(DeleteNsxNatRuleCommand.class), eq(zoneId)); + } +} diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/utils/NsxControllerUtilsTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/utils/NsxControllerUtilsTest.java new file mode 100644 index 00000000000..9139fdef68f --- /dev/null +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/utils/NsxControllerUtilsTest.java @@ -0,0 +1,198 @@ +// 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.agent.AgentManager; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NsxProviderVO; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.NsxCommand; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class NsxControllerUtilsTest { + + private static final long domainId = 2L; + private static final long accountId = 10L; + private static final long zoneId = 1L; + private static final long nsxProviderHostId = 1L; + + private static final String commonPrefix = String.format("D%s-A%s-Z%s", domainId, accountId, zoneId); + + @Mock + private NsxProviderDao nsxProviderDao; + @Mock + private AgentManager agentMgr; + + @Spy + @InjectMocks + private NsxControllerUtils nsxControllerUtils = new NsxControllerUtils(); + + @Mock + private NsxProviderVO nsxProviderVO; + + @Before + public void setup() { + Mockito.when(nsxProviderDao.findByZoneId(zoneId)).thenReturn(nsxProviderVO); + Mockito.when(nsxProviderVO.getHostId()).thenReturn(nsxProviderHostId); + } + + @Test(expected = InvalidParameterValueException.class) + public void testSendCommandAnswerFailure() { + NsxCommand cmd = Mockito.mock(NsxCommand.class); + Mockito.when(nsxProviderDao.findByZoneId(zoneId)).thenReturn(null); + nsxControllerUtils.sendNsxCommand(cmd, zoneId); + } + + @Test(expected = InvalidParameterValueException.class) + public void testSendCommandNoNsxProvider() { + NsxCommand cmd = Mockito.mock(NsxCommand.class); + Mockito.when(agentMgr.easySend(nsxProviderHostId, cmd)).thenReturn(null); + nsxControllerUtils.sendNsxCommand(cmd, zoneId); + } + + @Test + public void testSendCommand() { + NsxCommand cmd = Mockito.mock(NsxCommand.class); + NsxAnswer answer = Mockito.mock(NsxAnswer.class); + Mockito.when(answer.getResult()).thenReturn(true); + Mockito.when(agentMgr.easySend(nsxProviderHostId, cmd)).thenReturn(answer); + NsxAnswer nsxAnswer = nsxControllerUtils.sendNsxCommand(cmd, zoneId); + Assert.assertNotNull(nsxAnswer); + } + + @Test + public void testGetNsxNatRuleIdForVpc() { + long vpcId = 5L; + String nsxNatRuleId = NsxControllerUtils.getNsxNatRuleId(domainId, accountId, zoneId, vpcId, true); + String ruleIdPart = String.format("V%s-NAT", vpcId); + String expected = String.format("%s-%s", commonPrefix, ruleIdPart); + Assert.assertEquals(expected, nsxNatRuleId); + } + + @Test + public void testGetNsxNatRuleIdForNetwork() { + long networkId = 5L; + String nsxNatRuleId = NsxControllerUtils.getNsxNatRuleId(domainId, accountId, zoneId, networkId, false); + String ruleIdPart = String.format("N%s-NAT", networkId); + String expected = String.format("%s-%s", commonPrefix, ruleIdPart); + Assert.assertEquals(expected, nsxNatRuleId); + } + + @Test + public void testGetNsxSegmentIdForVpcNetwork() { + long vpcId = 5L; + long networkId = 2L; + String nsxSegmentName = NsxControllerUtils.getNsxSegmentId(domainId, accountId, zoneId, vpcId, networkId); + String segmentPart = String.format("V%s-S%s", vpcId, networkId); + String expected = String.format("%s-%s", commonPrefix, segmentPart); + Assert.assertEquals(expected, nsxSegmentName); + } + + @Test + public void testGetNsxSegmentIdForNonVpcNetwork() { + Long vpcId = null; + long networkId = 2L; + String nsxSegmentName = NsxControllerUtils.getNsxSegmentId(domainId, accountId, zoneId, vpcId, networkId); + String segmentPart = String.format("S%s", networkId); + String expected = String.format("%s-%s", commonPrefix, segmentPart); + Assert.assertEquals(expected, nsxSegmentName); + } + + @Test + public void testGetNsxDistributedFirewallPolicyRuleIdForVpcNetwork() { + long vpcId = 5L; + long networkId = 2L; + long ruleId = 1L; + String nsxSegmentName = NsxControllerUtils.getNsxSegmentId(domainId, accountId, zoneId, vpcId, networkId); + String expected = String.format("%s-R%s", nsxSegmentName, ruleId); + Assert.assertEquals(expected, NsxControllerUtils.getNsxDistributedFirewallPolicyRuleId(nsxSegmentName, ruleId)); + } + + @Test + public void testGetTier1GatewayNameForVpcNetwork() { + long networkOnVpcId = 5L; + String networkPart = String.format("V%s", networkOnVpcId); + String expected = String.format("%s-%s", commonPrefix, networkPart); + Assert.assertEquals(expected, NsxControllerUtils.getTier1GatewayName(domainId, accountId, zoneId, networkOnVpcId, true)); + } + + @Test + public void testGetTier1GatewayNameForNetwork() { + long networkId = 5L; + String networkPart = String.format("N%s", networkId); + String expected = String.format("%s-%s", commonPrefix, networkPart); + Assert.assertEquals(expected, NsxControllerUtils.getTier1GatewayName(domainId, accountId, zoneId, networkId, false)); + } + + @Test + public void testGetNsxDhcpRelayConfigIdForVpcNetwork() { + long vpcId = 5L; + long networkId = 2L; + String relayPart = String.format("V%s-S%s-Relay", vpcId, networkId); + String expected = String.format("%s-%s", commonPrefix, relayPart); + String dhcpRelayConfigId = NsxControllerUtils.getNsxDhcpRelayConfigId(zoneId, domainId, accountId, vpcId, networkId); + Assert.assertEquals(expected, dhcpRelayConfigId); + } + + @Test + public void testGetNsxDhcpRelayConfigIdForNetwork() { + Long vpcId = null; + long networkId = 2L; + String relayPart = String.format("S%s-Relay", networkId); + String expected = String.format("%s-%s", commonPrefix, relayPart); + String dhcpRelayConfigId = NsxControllerUtils.getNsxDhcpRelayConfigId(zoneId, domainId, accountId, vpcId, networkId); + Assert.assertEquals(expected, dhcpRelayConfigId); + } + + @Test + public void testGetStaticNatRuleNameForVpc() { + long vpcId = 5L; + String rulePart = String.format("V%s-STATICNAT", vpcId); + String expected = String.format("%s-%s", commonPrefix, rulePart); + String staticNatRuleName = NsxControllerUtils.getStaticNatRuleName(domainId, accountId, zoneId, vpcId, true); + Assert.assertEquals(expected, staticNatRuleName); + } + + @Test + public void testGetStaticNatRuleNameForNetwork() { + long network = 5L; + String rulePart = String.format("N%s-STATICNAT", network); + String expected = String.format("%s-%s", commonPrefix, rulePart); + String staticNatRuleName = NsxControllerUtils.getStaticNatRuleName(domainId, accountId, zoneId, network, false); + Assert.assertEquals(expected, staticNatRuleName); + } + + @Test + public void testGetPortForwardRuleName() { + long vpcId = 5L; + long ruleId = 2L; + String rulePart = String.format("V%s-PF%s", vpcId, ruleId); + String expected = String.format("%s-%s", commonPrefix, rulePart); + String portForwardRuleName = NsxControllerUtils.getPortForwardRuleName(domainId, accountId, zoneId, vpcId, ruleId, true); + Assert.assertEquals(expected, portForwardRuleName); + } +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightGuestNetworkGuru.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightGuestNetworkGuru.java index 659caf04649..7b4851fc285 100644 --- a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightGuestNetworkGuru.java +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightGuestNetworkGuru.java @@ -97,7 +97,7 @@ public class OpendaylightGuestNetworkGuru extends GuestNetworkGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { PhysicalNetworkVO physnet = physicalNetworkDao.findById(plan.getPhysicalNetworkId()); DataCenter dc = _dcDao.findById(plan.getDataCenterId()); if (!canHandle(offering, dc.getNetworkType(), physnet)) { @@ -113,7 +113,7 @@ public class OpendaylightGuestNetworkGuru extends GuestNetworkGuru { logger.debug("Controller " + devices.get(0).getUuid() + " found on physical network " + physnet.getId()); logger.debug("Physical isolation type is ODL, asking GuestNetworkGuru to design this network"); - NetworkVO networkObject = (NetworkVO)super.design(offering, plan, userSpecified, owner); + NetworkVO networkObject = (NetworkVO)super.design(offering, plan, userSpecified, name, vpcId, owner); if (networkObject == null) { return null; } diff --git a/plugins/network-elements/ovs/src/main/java/com/cloud/network/guru/OvsGuestNetworkGuru.java b/plugins/network-elements/ovs/src/main/java/com/cloud/network/guru/OvsGuestNetworkGuru.java index 240af3ac78c..97531a91537 100644 --- a/plugins/network-elements/ovs/src/main/java/com/cloud/network/guru/OvsGuestNetworkGuru.java +++ b/plugins/network-elements/ovs/src/main/java/com/cloud/network/guru/OvsGuestNetworkGuru.java @@ -94,7 +94,7 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru { @Override public Network design(NetworkOffering offering, DeploymentPlan plan, - Network userSpecified, Account owner) { + Network userSpecified, String name, Long vpcId, Account owner) { PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan .getPhysicalNetworkId()); @@ -104,7 +104,7 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru { return null; } NetworkVO config = (NetworkVO)super.design(offering, plan, - userSpecified, owner); + userSpecified, name, vpcId, owner); if (config == null) { return null; } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java index 818d370cca0..4d22806a139 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java @@ -144,7 +144,7 @@ public class TungstenGuestNetworkGuru extends GuestNetworkGuru implements Networ } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); DataCenter dc = _dcDao.findById(plan.getDataCenterId()); @@ -154,7 +154,7 @@ public class TungstenGuestNetworkGuru extends GuestNetworkGuru implements Networ return null; } - NetworkVO network = (NetworkVO) super.design(offering, plan, userSpecified, owner); + NetworkVO network = (NetworkVO) super.design(offering, plan, userSpecified, name, vpcId, owner); if (network == null) { return null; diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuruTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuruTest.java index 6a5a0132442..f66e026ba91 100644 --- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuruTest.java +++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuruTest.java @@ -233,7 +233,7 @@ public class TungstenGuestNetworkGuruTest { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designedNetwork = guru.design(offering, plan, network, account); + final Network designedNetwork = guru.design(offering, plan, network, "", 1L, account); assertNotNull(designedNetwork); assertSame(Networks.BroadcastDomainType.TUNGSTEN, designedNetwork.getBroadcastDomainType()); assertSame(Network.State.Allocated, designedNetwork.getState()); diff --git a/plugins/network-elements/vxlan/src/main/java/com/cloud/network/guru/VxlanGuestNetworkGuru.java b/plugins/network-elements/vxlan/src/main/java/com/cloud/network/guru/VxlanGuestNetworkGuru.java index 1618c9710f8..a1ff8d309d9 100644 --- a/plugins/network-elements/vxlan/src/main/java/com/cloud/network/guru/VxlanGuestNetworkGuru.java +++ b/plugins/network-elements/vxlan/src/main/java/com/cloud/network/guru/VxlanGuestNetworkGuru.java @@ -66,8 +66,8 @@ public class VxlanGuestNetworkGuru extends GuestNetworkGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { - NetworkVO network = (NetworkVO)super.design(offering, plan, userSpecified, owner); + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { + NetworkVO network = (NetworkVO)super.design(offering, plan, userSpecified, name, vpcId, owner); if (network == null) { return null; } diff --git a/plugins/network-elements/vxlan/src/test/java/com/cloud/network/guru/VxlanGuestNetworkGuruTest.java b/plugins/network-elements/vxlan/src/test/java/com/cloud/network/guru/VxlanGuestNetworkGuruTest.java index 4d485e25a64..71f86791725 100644 --- a/plugins/network-elements/vxlan/src/test/java/com/cloud/network/guru/VxlanGuestNetworkGuruTest.java +++ b/plugins/network-elements/vxlan/src/test/java/com/cloud/network/guru/VxlanGuestNetworkGuruTest.java @@ -138,7 +138,7 @@ public class VxlanGuestNetworkGuruTest { Network network = mock(Network.class); Account account = mock(Account.class); - Network designednetwork = guru.design(offering, plan, network, account); + Network designednetwork = guru.design(offering, plan, network, "", 1L, account); assertTrue(designednetwork != null); assertTrue(designednetwork.getBroadcastDomainType() == BroadcastDomainType.Vxlan); } diff --git a/plugins/pom.xml b/plugins/pom.xml index cbfba8f8217..1083c36275f 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -113,6 +113,7 @@ network-elements/brocade-vcs network-elements/vxlan network-elements/tungsten + network-elements/nsx outofbandmanagement-drivers/ipmitool outofbandmanagement-drivers/nested-cloudstack diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index a0dc0d17c71..bcf89b7f4d8 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TimeZone; import java.util.function.Consumer; @@ -38,6 +39,8 @@ import java.util.stream.Collectors; import javax.inject.Inject; +import com.cloud.dc.VlanDetailsVO; +import com.cloud.dc.dao.VlanDetailsDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.BucketVO; import org.apache.cloudstack.acl.ControlledEntity; @@ -482,6 +485,8 @@ public class ApiResponseHelper implements ResponseGenerator { FirewallRulesDao firewallRulesDao; @Inject UserDataDao userDataDao; + @Inject + VlanDetailsDao vlanDetailsDao; @Inject ObjectStoreDao _objectStoreDao; @@ -959,6 +964,8 @@ public class ApiResponseHelper implements ResponseGenerator { } } vlanResponse.setForSystemVms(isForSystemVms(vlan.getId())); + VlanDetailsVO vlanDetail = vlanDetailsDao.findDetail(vlan.getId(), ApiConstants.NSX_DETAIL_KEY); + vlanResponse.setForNsx(Objects.nonNull(vlanDetail) && vlanDetail.getValue().equals("true")); vlanResponse.setObjectName("vlan"); return vlanResponse; } catch (InstantiationException | IllegalAccessException e) { @@ -1112,6 +1119,7 @@ public class ApiResponseHelper implements ResponseGenerator { ipResponse.setForDisplay(ipAddr.isDisplay()); ipResponse.setPortable(ipAddr.isPortable()); + ipResponse.setForSystemVms(ipAddr.isForSystemVms()); //set tag information List tags = ApiDBUtils.listByResourceTypeAndId(ResourceObjectType.PublicIpAddress, ipAddr.getId()); @@ -2373,6 +2381,8 @@ 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/DataCenterJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java index 24b7df5591f..2bfbb3b9d67 100644 --- a/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java @@ -17,9 +17,12 @@ package com.cloud.api.query.dao; import java.util.List; +import java.util.Objects; import javax.inject.Inject; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NsxProviderVO; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.api.ResponseObject.ResponseView; @@ -51,6 +54,8 @@ public class DataCenterJoinDaoImpl extends GenericDaoBase> sameSubnet) { + final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair> sameSubnet, boolean forNsx) { final GlobalLock commitVlanLock = GlobalLock.getInternLock("CommitVlan"); commitVlanLock.lock(5); logger.debug("Acquiring lock for committing vlan"); @@ -4615,7 +4628,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati newVlanNetmask = sameSubnet.second().second(); } final Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, forSystemVms, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, - false, domain, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr); + false, domain, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr, forNsx); // create an entry in the nic_secondary table. This will be the new // gateway that will be configured on the corresponding routervm. return vlan; @@ -4739,7 +4752,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Override @DB public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final boolean forVirtualNetwork, final boolean forSystemVms, final Long podId, final String startIP, final String endIP, - final String vlanGateway, final String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, final Account vlanOwner, final String startIPv6, final String endIPv6, final String vlanIp6Gateway, final String vlanIp6Cidr) { + final String vlanGateway, final String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, final Account vlanOwner, final String startIPv6, final String endIPv6, final String vlanIp6Gateway, final String vlanIp6Cidr, boolean forNsx) { final Network network = _networkModel.getNetwork(networkId); boolean ipv4 = false, ipv6 = false; @@ -4821,11 +4834,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } else { vlanId = networkVlanId; } - } else if (network.getTrafficType() == TrafficType.Public && vlanId == null) { + } else if (network.getTrafficType() == TrafficType.Public && vlanId == null && !forNsx) { throw new InvalidParameterValueException("Unable to determine vlan id or untagged vlan for public network"); } - if (vlanId == null) { + if (vlanId == null && !forNsx) { vlanId = Vlan.UNTAGGED; } @@ -4922,7 +4935,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (isSharedNetworkWithoutSpecifyVlan) { bypassVlanOverlapCheck = true; } - if (!bypassVlanOverlapCheck && _zoneDao.findVnet(zoneId, physicalNetworkId, BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlanId))).size() > 0) { + if (!bypassVlanOverlapCheck && !forNsx && !_zoneDao.findVnet(zoneId, physicalNetworkId, BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlanId))).isEmpty()) { throw new InvalidParameterValueException("The VLAN tag " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName()); } @@ -4938,7 +4951,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // Everything was fine, so persist the VLAN final VlanVO vlan = commitVlanAndIpRange(zoneId, networkId, physicalNetworkId, podId, startIP, endIP, vlanGateway, vlanNetmask, vlanId, domain, vlanOwner, vlanIp6Gateway, vlanIp6Cidr, - ipv4, zone, vlanType, ipv6Range, ipRange, forSystemVms); + ipv4, zone, vlanType, ipv6Range, ipRange, forSystemVms, forNsx); return vlan; } @@ -4960,9 +4973,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati continue; } // from here, subnet overlaps - if (vlanId.toLowerCase().contains(Vlan.UNTAGGED) || UriUtils.checkVlanUriOverlap( + VlanDetailsVO vlanDetail = vlanDetailsDao.findDetail(vlan.getId(), ApiConstants.NSX_DETAIL_KEY); + if ((Objects.isNull(vlanId) && Objects.nonNull(vlanDetail) && vlanDetail.getValue().equals("true")) || Objects.nonNull(vlanId) && + (vlanId.toLowerCase().contains(Vlan.UNTAGGED) || UriUtils.checkVlanUriOverlap( BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlanId)), - BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlan.getVlanTag())))) { + BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlan.getVlanTag()))))) { // For untagged VLAN Id and overlapping URIs we need to expand and verify IP ranges final String[] otherVlanIpRange = vlan.getIpRange().split("\\-"); final String otherVlanStartIP = otherVlanIpRange[0]; @@ -5007,13 +5022,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati private VlanVO commitVlanAndIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final Long podId, final String startIP, final String endIP, final String vlanGateway, final String vlanNetmask, final String vlanId, final Domain domain, final Account vlanOwner, final String vlanIp6Gateway, final String vlanIp6Cidr, - final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange, final boolean forSystemVms) { + final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange, final boolean forSystemVms, final boolean forNsx) { return Transaction.execute(new TransactionCallback() { @Override public VlanVO doInTransaction(final TransactionStatus status) { VlanVO vlan = new VlanVO(vlanType, vlanId, vlanGateway, vlanNetmask, zone.getId(), ipRange, networkId, physicalNetworkId, vlanIp6Gateway, vlanIp6Cidr, ipv6Range); logger.debug("Saving vlan range " + vlan); vlan = _vlanDao.persist(vlan); + vlanDetailsDao.addDetail(vlan.getId(), ApiConstants.NSX_DETAIL_KEY, String.valueOf(forNsx), true); // IPv6 use a used ip map, is different from ipv4, no need to save // public ip range @@ -5992,7 +6008,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Map detailsStr = cmd.getDetails(); final Boolean egressDefaultPolicy = cmd.getEgressDefaultPolicy(); Boolean forVpc = cmd.getForVpc(); + Boolean forNsx = cmd.isForNsx(); Boolean forTungsten = cmd.getForTungsten(); + String nsxMode = cmd.getNsxMode(); + boolean nsxSupportInternalLbSvc = cmd.getNsxSupportsInternalLbService(); Integer maxconn = null; boolean enableKeepAlive = false; String servicePackageuuid = cmd.getServicePackageId(); @@ -6026,6 +6045,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 (logger.isTraceEnabled()) { + 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)) { @@ -6290,7 +6329,12 @@ 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, domainIds, zoneIds, enable, internetProtocol); + serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, forTungsten, forNsx, nsxMode, domainIds, zoneIds, enable, internetProtocol); + if (Boolean.TRUE.equals(forNsx) && nsxSupportInternalLbSvc) { + offering.setInternalLb(true); + offering.setPublicLb(false); + _networkOfferingDao.update(offering.getId(), offering); + } CallContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name); CallContext.current().putContextParameter(NetworkOffering.class, offering.getId()); return offering; @@ -6430,12 +6474,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Override @DB public NetworkOfferingVO createNetworkOffering(final String name, final String displayText, final TrafficType trafficType, String tags, final boolean specifyVlan, - final Availability availability, - final Integer networkRate, final Map> serviceProviderMap, final boolean isDefault, final GuestType type, final boolean systemOnly, - 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, final List domainIds, final List zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol) { + final Availability availability, + final Integer networkRate, final Map> serviceProviderMap, final boolean isDefault, final GuestType type, final boolean systemOnly, + 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, String mode, final List domainIds, final List zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol) { String servicePackageUuid; String spDescription = null; @@ -6596,6 +6640,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } offeringFinal.setForTungsten(Objects.requireNonNullElse(forTungsten, false)); + offeringFinal.setForNsx(Objects.requireNonNullElse(forNsx, false)); + if (Boolean.TRUE.equals(forNsx)) { + offeringFinal.setNsxMode(mode); + } if (enableOffering) { offeringFinal.setState(NetworkOffering.State.Enabled); @@ -6660,7 +6708,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati 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); @@ -7749,8 +7797,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati public ConfigKey[] getConfigKeys() { return new ConfigKey[] {SystemVMUseLocalStorage, IOPS_MAX_READ_LENGTH, IOPS_MAX_WRITE_LENGTH, BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE, VM_SERVICE_OFFERING_MAX_CPU_CORES, - VM_SERVICE_OFFERING_MAX_RAM_SIZE, VM_USERDATA_MAX_LENGTH, MIGRATE_VM_ACROSS_CLUSTERS, - ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN, ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS + VM_SERVICE_OFFERING_MAX_RAM_SIZE, VM_USERDATA_MAX_LENGTH, MIGRATE_VM_ACROSS_CLUSTERS, ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, + ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN, ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, AllowNonRFC1918CompliantIPs }; } diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java index d0d728d4410..236a2869421 100644 --- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java @@ -18,10 +18,20 @@ package com.cloud.hypervisor; import java.util.List; import java.util.Map; +import java.util.Objects; 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; @@ -76,6 +86,14 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis protected NetworkDao networkDao; @Inject + protected VpcDao vpcDao; + @Inject + protected AccountManager accountManager; + @Inject + private DomainDao domainDao; + @Inject + private DataCenterDao dcDao; + @Inject private NetworkOfferingDetailsDao networkOfferingDetailsDao; @Inject protected @@ -145,9 +163,27 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis to.setMtu(profile.getMtu()); to.setIp6Dns1(profile.getIPv6Dns1()); to.setIp6Dns2(profile.getIPv6Dns2()); + to.setNetworkId(profile.getNetworkId()); 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.getVpcId())) { + vpc = vpcDao.findById(network.getVpcId()); + } + 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()); @@ -176,6 +212,15 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis return to; } + 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 prefix + "-S" + networkId; + } + return prefix + "-V" + vpc.getId() + "-S" + networkId; + } + + /** * Add extra configuration from VM details. Extra configuration is stored as details starting with 'extraconfig' */ diff --git a/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java b/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java index b8c464cfe3e..16473e837a9 100644 --- a/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java @@ -460,7 +460,7 @@ public class NetworkMigrationManagerImpl implements NetworkMigrationManager { DataCenterDeployment plan = new DataCenterDeployment(network.getDataCenterId(), null, null, null, null, newPhysicalNetworkId); for (final NetworkGuru guru : _networkMgr.getNetworkGurus()) { - final Network designedNetwork = guru.design(newOffering, plan, network, networkAccount); + final Network designedNetwork = guru.design(newOffering, plan, network, network.getName(), vpcId, networkAccount); if (designedNetwork == null) { continue; } diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java index af0d25c4c1d..07e471c377f 100644 --- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java @@ -101,8 +101,10 @@ import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.dao.PortForwardingRulesDao; +import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcGatewayVO; import com.cloud.network.vpc.dao.PrivateIpDao; +import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.dao.VpcGatewayDao; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Detail; @@ -178,6 +180,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi ProjectDao projectDao; @Inject NetworkPermissionDao _networkPermissionDao; + @Inject + VpcDao vpcDao; private List networkElements; @@ -489,7 +493,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi @Override public Map> getProviderToIpList(Network network, Map> ipToServices) { NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); - if (!offering.isConserveMode()) { + if (!offering.isConserveMode() && !offering.isForNsx()) { for (PublicIpAddress ip : ipToServices.keySet()) { Set services = new HashSet(); services.addAll(ipToServices.get(ip)); @@ -1615,7 +1619,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi if (!canIpUsedForService(publicIp, service, networkId)) { return false; } - if (!offering.isConserveMode()) { + if (!offering.isConserveMode() && !offering.isForNsx()) { return canIpUsedForNonConserveService(publicIp, service); } return true; @@ -2713,6 +2717,12 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi if (StringUtils.isNotBlank(network.getDns1())) { return new Pair<>(network.getDns1(), network.getDns2()); } + if (network.getVpcId() != null) { + Vpc vpc = vpcDao.findById(network.getVpcId()); + if (vpc != null && StringUtils.isNotBlank(vpc.getIp4Dns1())) { + return new Pair<>(vpc.getIp4Dns1(), vpc.getIp4Dns2()); + } + } return new Pair<>(zone.getDns1(), zone.getDns2()); } @@ -2721,6 +2731,12 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi if (StringUtils.isNotBlank(network.getIp6Dns1())) { return new Pair<>(network.getIp6Dns1(), network.getIp6Dns2()); } + if (network.getVpcId() != null) { + Vpc vpc = vpcDao.findById(network.getVpcId()); + if (vpc != null && StringUtils.isNotBlank(vpc.getIp6Dns1())) { + return new Pair<>(vpc.getIp6Dns1(), vpc.getIp6Dns2()); + } + } return new Pair<>(zone.getIp6Dns1(), zone.getIp6Dns2()); } diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index 2b7e0450935..2d1552d7b0b 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -34,6 +34,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -41,7 +42,13 @@ import java.util.stream.Collectors; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.VlanDetailsVO; +import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.dao.PublicIpQuarantineDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.element.NsxProviderVO; +import com.cloud.network.element.VirtualRouterProviderVO; import com.cloud.offering.ServiceOffering; import com.cloud.service.dao.ServiceOfferingDao; import org.apache.cloudstack.acl.ControlledEntity.ACLType; @@ -79,6 +86,7 @@ import org.apache.cloudstack.network.NetworkPermissionVO; import org.apache.cloudstack.network.dao.NetworkPermissionDao; import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -282,6 +290,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C @Inject VlanDao _vlanDao = null; @Inject + private VlanDetailsDao vlanDetailsDao; + @Inject IPAddressDao _ipAddressDao = null; @Inject AccountDao _accountDao = null; @@ -349,8 +359,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C @Inject HostDao _hostDao; @Inject - InternalLoadBalancerElementService _internalLbElementSvc; - @Inject DataCenterVnetDao _dcVnetDao; @Inject AccountGuestVlanMapDao _accountGuestVlanMapDao; @@ -404,6 +412,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C ServiceOfferingDao serviceOfferingDao; @Inject PublicIpQuarantineDao publicIpQuarantineDao; + @Inject + NsxProviderDao nsxProviderDao; + @Inject + private VirtualRouterProviderDao virtualRouterProviderDao; + List internalLoadBalancerElementServices = new ArrayList<>(); + Map internalLoadBalancerElementServiceMap = new HashMap<>(); @Autowired @Qualifier("networkHelper") @@ -811,9 +825,19 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C @Override public boolean start() { + initializeInternalLoadBalancerElementsMap(); return true; } + private void initializeInternalLoadBalancerElementsMap() { + if (MapUtils.isEmpty(internalLoadBalancerElementServiceMap) && CollectionUtils.isNotEmpty(internalLoadBalancerElementServices)) { + for (InternalLoadBalancerElementService service : internalLoadBalancerElementServices) { + internalLoadBalancerElementServiceMap.put(service.getProviderType().name(), service); + } + logger.debug(String.format("Discovered internal loadbalancer elements configured on NetworkServiceImpl")); + } + } + @Override public boolean stop() { return true; @@ -1137,6 +1161,58 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C return ipVO; } + @Override + public IpAddress reserveIpAddressWithVlanDetail(Account account, DataCenter zone, Boolean displayIp, String vlanDetailKey) throws ResourceAllocationException { + // verify permissions + Account caller = CallContext.current().getCallingAccount(); + _accountMgr.checkAccess(caller, null, true, account); + + VlanVO vlan = findOneVlanRangeMatchingVlanDetailKey(zone, vlanDetailKey); + if (vlan == null) { + String msg = String.format("Cannot find any vlan matching the detail key %s on zone %s", vlanDetailKey, zone.getName()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + + List freeIps = _ipAddressDao.listByVlanIdAndState(vlan.getId(), State.Free); + if (CollectionUtils.isEmpty(freeIps)) { + String msg = String.format("Cannot find any free IP matching on the VLAN range %s on zone %s", vlan.getIpRange(), zone.getName()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + + Collections.shuffle(freeIps); + IPAddressVO selectedIp = freeIps.get(0); + + selectedIp.setAllocatedTime(new Date()); + selectedIp.setAllocatedToAccountId(account.getAccountId()); + selectedIp.setAllocatedInDomainId(account.getDomainId()); + selectedIp.setState(State.Reserved); + if (displayIp != null) { + selectedIp.setDisplay(displayIp); + } + selectedIp = _ipAddressDao.persist(selectedIp); + + Long ipDedicatedAccountId = getIpDedicatedAccountId(selectedIp.getVlanId()); + if (ipDedicatedAccountId == null) { + _resourceLimitMgr.incrementResourceCount(account.getId(), Resource.ResourceType.public_ip); + } + + return selectedIp; + } + + private VlanVO findOneVlanRangeMatchingVlanDetailKey(DataCenter zone, String vlanDetailKey) { + List zoneVlans = _vlanDao.listByZone(zone.getId()); + for (VlanVO zoneVlan : zoneVlans) { + VlanDetailsVO detail = vlanDetailsDao.findDetail(zoneVlan.getId(), vlanDetailKey); + if (detail != null && detail.getValue().equalsIgnoreCase("true")) { + logger.debug(String.format("Found the VLAN range %s is set for NSX on zone %s", zoneVlan.getIpRange(), zone.getName())); + return zoneVlan; + } + } + return null; + } + private Long getIpDedicatedAccountId(Long vlanId) { List accountVlanMaps = _accountVlanMapDao.listAccountVlanMapsByVlan(vlanId); if (CollectionUtils.isNotEmpty(accountVlanMaps)) { @@ -1414,6 +1490,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C _accountMgr.checkAccess(owner, ntwkOff, zone); validateZoneAvailability(caller, zone); + validateNetworkCreationSupported(zone.getId(), zone.getName(), ntwkOff.getGuestType()); ACLType aclType = getAclType(caller, cmd.getAclType(), ntwkOff); @@ -1670,6 +1747,15 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C return network; } + private void validateNetworkCreationSupported(long zoneId, String zoneName, GuestType guestType) { + NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(zoneId); + if (Objects.nonNull(nsxProviderVO) && List.of(GuestType.L2, GuestType.Shared).contains(guestType)) { + throw new InvalidParameterValueException( + String.format("Creation of %s networks is not supported in NSX enabled zone %s", guestType.name(), zoneName) + ); + } + } + void checkAndSetRouterSourceNatIp(Account owner, CreateNetworkCmd cmd, Network network) throws InsufficientAddressCapacityException, ResourceAllocationException { String sourceNatIp = cmd.getSourceNatIP(); if (sourceNatIp == null) { @@ -2119,7 +2205,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C if (createVlan && network != null) { // Create vlan ip range _configMgr.createVlanAndPublicIpRange(pNtwk.getDataCenterId(), network.getId(), physicalNetworkId, false, false, null, startIP, endIP, gateway, netmask, vlanId, - bypassVlanOverlapCheck, null, null, startIPv6, endIPv6, ip6Gateway, ip6Cidr); + bypassVlanOverlapCheck, null, null, startIPv6, endIPv6, ip6Gateway, ip6Cidr, ntwkOff.isForNsx()); } if (associatedNetwork != null) { _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.AssociatedNetworkId, String.valueOf(associatedNetwork.getId()), true)); @@ -3074,7 +3160,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C if (!NetUtils.isValidIp4Cidr(guestVmCidr)) { throw new InvalidParameterValueException("Invalid format of Guest VM CIDR."); } - if (!NetUtils.validateGuestCidr(guestVmCidr)) { + if (!NetUtils.validateGuestCidr(guestVmCidr, !ConfigurationManager.AllowNonRFC1918CompliantIPs.value())) { throw new InvalidParameterValueException("Invalid format of Guest VM CIDR. Make sure it is RFC1918 compliant. "); } @@ -4023,6 +4109,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C // Add the config drive provider addConfigDriveToPhysicalNetwork(pNetwork.getId()); + addNSXProviderToPhysicalNetwork(pNetwork.getId()); CallContext.current().putContextParameter(PhysicalNetwork.class, pNetwork.getUuid()); @@ -5348,7 +5435,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C throw new CloudRuntimeException("Unable to find the Network Element implementing the " + Network.Provider.InternalLbVm.getName() + " Provider"); } - _internalLbElementSvc.addInternalLoadBalancerElement(nsp.getId()); + InternalLoadBalancerElementService service = getInternalLoadBalancerElementByNetworkServiceProviderId(nsp.getId()); + service.addInternalLoadBalancerElement(nsp.getId()); return nsp; } @@ -5417,6 +5505,22 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C } + private PhysicalNetworkServiceProvider addNSXProviderToPhysicalNetwork(long physicalNetworkId) { + PhysicalNetworkVO pvo = _physicalNetworkDao.findById(physicalNetworkId); + DataCenterVO dvo = _dcDao.findById(pvo.getDataCenterId()); + if (dvo.getNetworkType() == NetworkType.Advanced) { + + Provider provider = Network.Provider.getProvider("Nsx"); + if (provider == null) { + return null; + } + + addProviderToPhysicalNetwork(physicalNetworkId, Provider.Nsx.getName(), null, null); + enableProvider(Provider.Nsx.getName()); + } + return null; + } + protected boolean isNetworkSystem(Network network) { NetworkOffering no = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId()); if (no.isSystemOnly()) { @@ -5653,6 +5757,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C _networkGurus = networkGurus; } + public void setInternalLoadBalancerElementServices(List services) { + this.internalLoadBalancerElementServices = services; + } + @Override @ActionEvent(eventType = EventTypes.EVENT_NET_IP_UPDATE, eventDescription = "updating public ip address", async = true) public IpAddress updateIP(Long id, String customId, Boolean displayIp) { @@ -5994,6 +6102,34 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C _ipAddrMgr.removePublicIpAddressFromQuarantine(publicIpQuarantine.getId(), removalReason); } + @Override + public InternalLoadBalancerElementService getInternalLoadBalancerElementByType(Type type) { + return internalLoadBalancerElementServiceMap.getOrDefault(type.name(), null); + } + + @Override + public InternalLoadBalancerElementService getInternalLoadBalancerElementByNetworkServiceProviderId(long networkProviderId) { + PhysicalNetworkServiceProviderVO provider = _pNSPDao.findById(networkProviderId); + if (provider == null) { + String msg = String.format("Cannot find a network service provider with ID %s", networkProviderId); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + Type type = provider.getProviderName().equalsIgnoreCase("nsx") ? Type.Nsx : Type.InternalLbVm; + return getInternalLoadBalancerElementByType(type); + } + + @Override + public InternalLoadBalancerElementService getInternalLoadBalancerElementById(long providerId) { + VirtualRouterProviderVO provider = virtualRouterProviderDao.findById(providerId); + return getInternalLoadBalancerElementByType(provider.getType()); + } + + @Override + public List getInternalLoadBalancerElements() { + return new ArrayList<>(this.internalLoadBalancerElementServiceMap.values()); + } + /** * Retrieves the active quarantine for the given public IP address. It can find by the ID of the quarantine or the address of the public IP. * @throws CloudRuntimeException if it does not find an active quarantine for the given public IP. diff --git a/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java index 3d1920bcbc3..b8960629d80 100644 --- a/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java +++ b/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java @@ -529,6 +529,11 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc return result; } + @Override + public boolean reorderAclRules(Vpc vpc, List networks, List networkACLItems) { + return true; + } + @Override protected Type getVirtualRouterProvider() { return Type.VPCVirtualRouter; diff --git a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java index 5b0d9eb190d..e9a93528d05 100644 --- a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java @@ -22,12 +22,18 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.DataCenter; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NsxProviderVO; +import com.cloud.utils.db.EntityManager; import org.apache.cloudstack.api.command.user.firewall.IListFirewallRulesCmd; import org.apache.cloudstack.api.command.user.ipv6.ListIpv6FirewallRulesCmd; import org.apache.cloudstack.context.CallContext; @@ -135,6 +141,10 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, NetworkDao _networkDao; @Inject VpcManager _vpcMgr; + @Inject + EntityManager entityManager; + @Inject + NsxProviderDao nsxProviderDao; List _firewallElements; List _pfElements; @@ -687,6 +697,9 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, } for (FirewallRuleVO rule : rules) { + // validate rule - for NSX + long networkId = rule.getNetworkId(); + validateNsxConstraints(networkId, rule); // load cidrs if any rule.setSourceCidrList(_firewallCidrsDao.getSourceCidrs(rule.getId())); rule.setDestinationCidrsList(_firewallDcidrsDao.getDestCidrs(rule.getId())); @@ -708,6 +721,31 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, return true; } + private void validateNsxConstraints(long networkId, FirewallRuleVO rule) { + String protocol = rule.getProtocol(); + final Network network = entityManager.findById(Network.class, networkId); + final DataCenter dc = entityManager.findById(DataCenter.class, network.getDataCenterId()); + final NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(dc.getId()); + if (Objects.isNull(nsxProvider)) { + return; + } + + if (NetUtils.ICMP_PROTO.equals(protocol.toLowerCase(Locale.ROOT)) && (rule.getIcmpType() == -1 || rule.getIcmpCode() == -1) + && State.Add.equals(rule.getState())) { + String errorMsg = "Passing -1 for ICMP type is not supported for NSX enabled zones"; + logger.error(errorMsg); + throw new InvalidParameterValueException(errorMsg); + } + + if (List.of(NetUtils.TCP_PROTO, NetUtils.UDP_PROTO).contains(protocol.toLowerCase(Locale.ROOT)) && + (Objects.isNull(rule.getSourcePortStart()) || Objects.isNull(rule.getSourcePortEnd())) && + State.Add.equals(rule.getState())) { + String errorMsg = "Source start and end ports are required to be passed"; + logger.error(errorMsg); + throw new InvalidParameterValueException(errorMsg); + } + } + @Override public boolean applyDefaultEgressFirewallRule(Long networkId, boolean defaultPolicy, boolean add) throws ResourceUnavailableException { 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 d553f81cecf..9cec05446ac 100644 --- a/server/src/main/java/com/cloud/network/guru/ControlNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/ControlNetworkGuru.java @@ -89,7 +89,7 @@ public class ControlNetworkGuru extends PodBasedNetworkGuru implements NetworkGu } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network specifiedConfig, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network specifiedConfig, String name, Long vpcId, Account owner) { if (!canHandle(offering)) { return null; } @@ -103,6 +103,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 c8c32347590..a8c98fc1dee 100644 --- a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java @@ -160,7 +160,7 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { DataCenter dc = _dcDao.findById(plan.getDataCenterId()); PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); @@ -249,6 +249,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/ExternalGuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java index d11483eba6a..bdabc6c03a1 100644 --- a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -108,13 +108,13 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { if (_networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Network.Service.Connectivity)) { return null; } - NetworkVO config = (NetworkVO)super.design(offering, plan, userSpecified, owner); + NetworkVO config = (NetworkVO)super.design(offering, plan, userSpecified, name, vpcId, owner); if (config == null) { return null; } else if (_networkModel.networkIsConfiguredForExternalNetworking(plan.getDataCenterId(), config.getId())) { 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 46a0a0ac67d..ae8ee1ef3aa 100644 --- a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java @@ -114,9 +114,9 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur @Inject ConfigurationServer _configServer; @Inject - IpAddressManager _ipAddrMgr; + protected IpAddressManager _ipAddrMgr; @Inject - NetworkOfferingDao networkOfferingDao; + protected NetworkOfferingDao networkOfferingDao; @Inject Ipv6AddressManager ipv6AddressManager; @Inject @@ -146,6 +146,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) { @@ -217,7 +222,7 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur protected abstract boolean canHandle(NetworkOffering offering, final NetworkType networkType, PhysicalNetwork physicalNetwork); @Override - public Network design(final NetworkOffering offering, final DeploymentPlan plan, final Network userSpecified, final Account owner) { + public Network design(final NetworkOffering offering, final DeploymentPlan plan, final Network userSpecified, String name, Long vpcId, final Account owner) { final DataCenter dc = _dcDao.findById(plan.getDataCenterId()); final PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); 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 a857581397c..5dafa60f1c7 100644 --- a/server/src/main/java/com/cloud/network/guru/PodBasedNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/PodBasedNetworkGuru.java @@ -74,7 +74,7 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { TrafficType type = offering.getTrafficType(); if (!isMyTrafficType(type)) { @@ -87,6 +87,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 9f6551fd78d..bd4f02040c0 100644 --- a/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java @@ -96,7 +96,7 @@ public class PrivateNetworkGuru extends AdapterBase implements NetworkGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { DataCenter dc = _entityMgr.findById(DataCenter.class, plan.getDataCenterId()); if (!canHandle(offering, dc)) { return null; @@ -135,6 +135,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 (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 0061064c896..1b02e145cc9 100644 --- a/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java @@ -68,7 +68,7 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { @Inject NetworkOrchestrationService _networkMgr; @Inject - IPAddressDao _ipAddressDao; + protected IPAddressDao _ipAddressDao; @Inject IpAddressManager _ipAddrMgr; @Inject @@ -98,7 +98,7 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network network, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network network, String name, Long vpcId, Account owner) { if (!canHandle(offering)) { return null; } @@ -113,6 +113,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/guru/StorageNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/StorageNetworkGuru.java index 0f199a75126..221661fea12 100644 --- a/server/src/main/java/com/cloud/network/guru/StorageNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/StorageNetworkGuru.java @@ -80,7 +80,7 @@ public class StorageNetworkGuru extends PodBasedNetworkGuru implements NetworkGu } @Override - public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { if (!canHandle(offering)) { return null; } diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 22061734162..ce5024a5e1b 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -23,6 +23,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import javax.inject.Inject; @@ -790,7 +791,10 @@ public class CommandSetupHelper { // vlan1, then all ip addresses of vlan2, etc.. final Map> vlanIpMap = new HashMap>(); for (final PublicIpAddress ipAddress : ips) { - final String vlanTag = ipAddress.getVlanTag(); + String vlanTag = ipAddress.getVlanTag(); + if (Objects.isNull(vlanTag)) { + vlanTag = "nsx-"+ipAddress.getAddress().addr(); + } ArrayList ipList = vlanIpMap.get(vlanTag); if (ipList == null) { ipList = new ArrayList(); @@ -841,10 +845,18 @@ public class CommandSetupHelper { for (final PublicIpAddress ipAddr : ipAddrList) { final boolean add = ipAddr.getState() == IpAddress.State.Releasing ? false : true; + String vlanTag = ipAddr.getVlanTag(); + String key = null; + if (Objects.isNull(vlanTag)) { + key = "nsx-" + ipAddr.getAddress().addr(); + } else { + key = BroadcastDomainType.getValue(BroadcastDomainType.fromString(ipAddr.getVlanTag())); + } - final String macAddress = vlanMacAddress.get(BroadcastDomainType.getValue(BroadcastDomainType.fromString(ipAddr.getVlanTag()))); + final String macAddress = vlanMacAddress.get(key); - final IpAddressTO ip = new IpAddressTO(ipAddr.getAccountId(), ipAddr.getAddress().addr(), add, firstIP, ipAddr.isSourceNat(), BroadcastDomainType.fromString(ipAddr.getVlanTag()).toString(), ipAddr.getGateway(), + final IpAddressTO ip = new IpAddressTO(ipAddr.getAccountId(), ipAddr.getAddress().addr(), add, firstIP, ipAddr.isSourceNat(), + Objects.isNull(vlanTag) ? null : BroadcastDomainType.fromString(ipAddr.getVlanTag()).toString(), ipAddr.getGateway(), ipAddr.getNetmask(), macAddress, networkRate, ipAddr.isOneToOneNat()); setIpAddressNetworkParams(ip, network, router); if (network.getPublicMtu() != null) { @@ -1048,6 +1060,9 @@ public class CommandSetupHelper { } for (IPAddressVO ip : userIps) { String vlanTag = _vlanDao.findById(ip.getVlanId()).getVlanTag(); + if (Objects.isNull(vlanTag)) { + vlanTag = "nsx-" + ip.getAddress().addr(); + } Boolean lastIp = vlanLastIpMap.get(vlanTag); if (lastIp != null && !lastIp) { continue; @@ -1145,7 +1160,7 @@ public class CommandSetupHelper { public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRouterVO router, final boolean add, final NicProfile guestNic) { final Network network = _networkModel.getNetwork(guestNic.getNetworkId()); - + final NetworkOfferingVO networkOfferingVO = _networkOfferingDao.findById(network.getNetworkOfferingId()); String defaultDns1 = null; String defaultDns2 = null; String defaultIp6Dns1 = null; @@ -1182,6 +1197,7 @@ public class CommandSetupHelper { final SetupGuestNetworkCommand setupCmd = new SetupGuestNetworkCommand(dhcpRange, networkDomain, router.getIsRedundantRouter(), defaultDns1, defaultDns2, add, _itMgr.toNicTO(nicProfile, router.getHypervisorType())); + setupCmd.setVrGuestGateway(networkOfferingVO.isForNsx()); NicVO publicNic = _nicDao.findDefaultNicForVM(router.getId()); if (publicNic != null) { updateSetupGuestNetworkCommandIpv6(setupCmd, network, publicNic, defaultIp6Dns1, defaultIp6Dns2); @@ -1345,7 +1361,8 @@ public class CommandSetupHelper { nicTO.setMac(ipAddress.getVifMacAddress()); nicTO.setType(ipAddress.getTrafficType()); nicTO.setGateway(ipAddress.getVlanGateway()); - nicTO.setBroadcastUri(BroadcastDomainType.fromString(ipAddress.getBroadcastUri())); + URI broadcastUri = ipAddress.getBroadcastUri() != null ? BroadcastDomainType.fromString(ipAddress.getBroadcastUri()) : null; + nicTO.setBroadcastUri(broadcastUri); nicTO.setType(network.getTrafficType()); nicTO.setName(_networkModel.getNetworkTag(router.getHypervisorType(), network)); nicTO.setBroadcastType(network.getBroadcastDomainType()); diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index 9c093e37ead..1f4642bbd85 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -28,6 +28,8 @@ import java.util.Map; import javax.annotation.PostConstruct; import javax.inject.Inject; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.utils.validation.ChecksumUtil; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -102,7 +104,6 @@ import com.cloud.user.dao.UserDao; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; -import com.cloud.utils.validation.ChecksumUtil; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; @@ -173,6 +174,8 @@ public class NetworkHelperImpl implements NetworkHelper { Ipv6Service ipv6Service; @Inject CapacityManager capacityMgr; + @Inject + VpcDao vpcDao; protected final Map> hypervisorsMap = new HashMap<>(); @@ -709,8 +712,8 @@ public class NetworkHelperImpl implements NetworkHelper { defaultNic.setIsolationUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag())); } else { defaultNic.setBroadcastType(BroadcastDomainType.Vlan); - defaultNic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(sourceNatIp.getVlanTag())); - defaultNic.setIsolationUri(IsolationType.Vlan.toUri(sourceNatIp.getVlanTag())); + defaultNic.setBroadcastUri(sourceNatIp.getVlanTag() != null ? BroadcastDomainType.Vlan.toUri(sourceNatIp.getVlanTag()) : null); + defaultNic.setIsolationUri(sourceNatIp.getVlanTag() != null ? IsolationType.Vlan.toUri(sourceNatIp.getVlanTag()) : null); } //If guest nic has already been added we will have 2 devices in the list. diff --git a/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java b/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java index 15c8a2b4155..399019db3e2 100644 --- a/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java @@ -21,6 +21,8 @@ import java.net.URI; import javax.inject.Inject; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.network.router.deployment.RouterDeploymentDefinition; import com.cloud.network.IpAddressManager; @@ -118,7 +120,13 @@ public class NicProfileHelperImpl implements NicProfileHelper { public NicProfile createGuestNicProfileForVpcRouter(final RouterDeploymentDefinition vpcRouterDeploymentDefinition, final Network guestNetwork) { final NicProfile guestNic = new NicProfile(); - if (vpcRouterDeploymentDefinition.isRedundant()) { + if (BroadcastDomainType.NSX == guestNetwork.getBroadcastDomainType()) { + NicVO vrNic = _nicDao.findByNetworkIdAndTypeIncludingRemoved(guestNetwork.getId(), VirtualMachine.Type.DomainRouter); + if (vrNic != null) { + guestNic.setIPv4Address(vrNic.getIPv4Address()); + guestNic.setIPv4Gateway(vrNic.getIPv4Gateway()); + } + } else if (vpcRouterDeploymentDefinition.isRedundant()) { guestNic.setIPv4Address(this.acquireGuestIpAddressForVrouterRedundant(guestNetwork)); } else { guestNic.setIPv4Address(guestNetwork.getGateway()); diff --git a/server/src/main/java/com/cloud/network/router/VpcNetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/VpcNetworkHelperImpl.java index 8c7e4524615..fa2f2aba8ff 100644 --- a/server/src/main/java/com/cloud/network/router/VpcNetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/VpcNetworkHelperImpl.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; @@ -84,8 +85,11 @@ public class VpcNetworkHelperImpl extends NetworkHelperImpl { final TreeSet publicVlans = new TreeSet(); if (vpcRouterDeploymentDefinition.isPublicNetwork()) { - publicVlans.add(vpcRouterDeploymentDefinition.getSourceNatIP() - .getVlanTag()); + String vlanTag = ""; + if (Objects.nonNull(vpcRouterDeploymentDefinition.getSourceNatIP().getVlanTag())) { + vlanTag = vpcRouterDeploymentDefinition.getSourceNatIP().getVlanTag(); + } + publicVlans.add(vlanTag); } //1) allocate nic for control and source nat public ip diff --git a/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index 69f7555696b..b22343081ff 100644 --- a/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -23,10 +23,13 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.vpc.dao.VpcDao; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; @@ -127,6 +130,10 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian private EntityManager _entityMgr; @Inject protected HypervisorGuruManager _hvGuruMgr; + @Inject + protected NetworkDao networkDao; + @Inject + protected VpcDao vpcDao; @Override public boolean configure(final String name, final Map params) throws ConfigurationException { @@ -358,7 +365,12 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } else if (network.getTrafficType() == TrafficType.Public) { final Pair publicNic = new Pair(routerNic, network); publicNics.add(publicNic); - final String vlanTag = BroadcastDomainType.getValue(routerNic.getBroadcastUri()); + String vlanTag = null; + if (Objects.nonNull(routerNic.getBroadcastUri())) { + vlanTag = BroadcastDomainType.getValue(routerNic.getBroadcastUri()); + } else { + vlanTag = "nsx-"+routerNic.getIPv4Address(); + } vlanMacAddress.put(vlanTag, routerNic.getMacAddress()); } } @@ -388,7 +400,8 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian _routerDao.update(routerVO.getId(), routerVO); } } - final PlugNicCommand plugNicCmd = new PlugNicCommand(_nwHelper.getNicTO(domainRouterVO, publicNic.getNetworkId(), publicNic.getBroadcastUri().toString()), + String broadcastURI = publicNic.getBroadcastUri() != null ? publicNic.getBroadcastUri().toString() : null; + final PlugNicCommand plugNicCmd = new PlugNicCommand(_nwHelper.getNicTO(domainRouterVO, publicNic.getNetworkId(), broadcastURI), domainRouterVO.getInstanceName(), domainRouterVO.getType(), details); cmds.addCommand(plugNicCmd); final VpcVO vpc = _vpcDao.findById(domainRouterVO.getVpcId()); diff --git a/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java index 047961467ac..2f37bdda75a 100644 --- a/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java @@ -204,6 +204,7 @@ public class NetworkACLManagerImpl extends ManagerBase implements NetworkACLMana final List aclItems = _networkACLItemDao.listByACL(acl.getId()); if (aclItems == null || aclItems.isEmpty()) { logger.debug("New network ACL is empty. Revoke existing rules before applying ACL"); + } else { if (!revokeACLItemsForNetwork(network.getId())) { throw new CloudRuntimeException("Failed to replace network ACL. Error while removing existing ACL items for network: " + network.getId()); } @@ -367,6 +368,20 @@ public class NetworkACLManagerImpl extends ManagerBase implements NetworkACLMana return applyACLToPrivateGw(gateway, rules); } + @Override + public boolean reorderAclRules(VpcVO vpc, List networks, List networkACLItems) { + List nsxElements = new ArrayList<>(); + nsxElements.add((NetworkACLServiceProvider) _ntwkModel.getElementImplementingProvider(Network.Provider.Nsx.getName())); + try { + for (final NetworkACLServiceProvider provider : nsxElements) { + return provider.reorderAclRules(vpc, networks, networkACLItems); + } + } catch (final Exception ex) { + logger.debug("Failed to reorder ACLs on NSX due to: " + ex.getLocalizedMessage()); + } + return false; + } + private boolean applyACLToPrivateGw(final PrivateGateway gateway, final List rules) throws ResourceUnavailableException { List vpcElements = new ArrayList(); vpcElements.add((VpcProvider)_ntwkModel.getElementImplementingProvider(Network.Provider.VPCVirtualRouter.getName())); diff --git a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java index 94b5ea91ce2..dd0dce5e10f 100644 --- a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java @@ -20,11 +20,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Objects; import javax.inject.Inject; +import com.cloud.dc.DataCenter; import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NsxProviderVO; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd; @@ -97,6 +102,8 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ private VpcDao _vpcDao; @Inject private VpcService _vpcSvc; + @Inject + private NsxProviderDao nsxProviderDao; private String supportedProtocolsForAclRules = "tcp,udp,icmp,all"; @@ -336,6 +343,7 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ if (isGlobalAcl(acl.getVpcId()) && !Account.Type.ADMIN.equals(caller.getType())) { throw new PermissionDeniedException("Only Root Admins can create rules for a global ACL."); } + validateNsxConstraints(acl.getVpcId(), protocol, icmpType, icmpCode, sourcePortStart, sourcePortEnd); validateAclRuleNumber(createNetworkACLCmd, acl); NetworkACLItem.Action ruleAction = validateAndCreateNetworkAclRuleAction(action); @@ -426,6 +434,32 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ } } + private void validateNsxConstraints(long vpcId, String protocol, Integer icmpType, + Integer icmpCode, Integer sourcePortStart, Integer sourcePortEnd) { + VpcVO vpc = _vpcDao.findById(vpcId); + if (Objects.isNull(vpc)) { + return; + } + final DataCenter dc = _entityMgr.findById(DataCenter.class, vpc.getZoneId()); + final NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(dc.getId()); + if (Objects.isNull(nsxProvider)) { + return; + } + + if (NetUtils.ICMP_PROTO.equals(protocol.toLowerCase(Locale.ROOT)) && (icmpType == -1 || icmpCode == -1)) { + String errorMsg = "Passing -1 for ICMP type is not supported for NSX enabled zones"; + logger.error(errorMsg); + throw new InvalidParameterValueException(errorMsg); + } + + if (List.of(NetUtils.TCP_PROTO, NetUtils.UDP_PROTO).contains(protocol.toLowerCase(Locale.ROOT)) && + (Objects.isNull(sourcePortStart) || Objects.isNull(sourcePortEnd))) { + String errorMsg = "Source start and end ports are required to be passed"; + logger.error(errorMsg); + throw new InvalidParameterValueException(errorMsg); + } + } + /** * This methods will simply return the ACL rule list ID if it has been provided by the parameter 'createNetworkACLCmd'. * If no ACL rule List ID has been provided the method behave as follows: @@ -815,7 +849,8 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ NetworkACL acl = _networkAclMgr.getNetworkACL(networkACLItemVo.getAclId()); validateNetworkAcl(acl); - + validateNsxConstraints(acl.getVpcId(), networkACLItemVo.getProtocol(), networkACLItemVo.getIcmpType(), + networkACLItemVo.getIcmpCode(), networkACLItemVo.getSourcePortStart(), networkACLItemVo.getSourcePortEnd()); Account account = CallContext.current().getCallingAccount(); validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account, "Only Root Admins can update global ACLs."); @@ -975,14 +1010,26 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ NetworkACLVO lockedAcl = _networkACLDao.acquireInLockTable(ruleBeingMoved.getAclId()); List allAclRules = getAllAclRulesSortedByNumber(lockedAcl.getId()); validateAclConsistency(moveNetworkAclItemCmd, lockedAcl, allAclRules); - + NetworkACLItem networkACLItem = null; if (previousRule == null) { - return moveRuleToTheTop(ruleBeingMoved, allAclRules); + networkACLItem = moveRuleToTheTop(ruleBeingMoved, allAclRules); + } else if (nextRule == null) { + networkACLItem = moveRuleToTheBottom(ruleBeingMoved, allAclRules); + } else { + networkACLItem = moveRuleBetweenAclRules(ruleBeingMoved, allAclRules, previousRule, nextRule); } - if (nextRule == null) { - return moveRuleToTheBottom(ruleBeingMoved, allAclRules); + VpcVO vpc = _vpcDao.findById(lockedAcl.getVpcId()); + if (Objects.isNull(vpc)) { + return networkACLItem; } - return moveRuleBetweenAclRules(ruleBeingMoved, allAclRules, previousRule, nextRule); + final DataCenter dc = _entityMgr.findById(DataCenter.class, vpc.getZoneId()); + final NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(dc.getId()); + List networks = _networkDao.listByAclId(lockedAcl.getId()); + if (Objects.nonNull(nsxProvider) && !networks.isEmpty()) { + allAclRules = getAllAclRulesSortedByNumber(lockedAcl.getId()); + _networkAclMgr.reorderAclRules(vpc, networks, allAclRules); + } + return networkACLItem; } finally { _networkACLDao.releaseFromLockTable(ruleBeingMoved.getAclId()); } 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 e313b1bfdf0..755cf2bb05c 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -41,6 +41,8 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.network.nsx.NsxService; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.alert.AlertService; import org.apache.cloudstack.annotation.AnnotationService; @@ -63,6 +65,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.jetbrains.annotations.Nullable; import org.springframework.beans.factory.annotation.Autowired; @@ -262,6 +265,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Autowired @Qualifier("networkHelper") protected NetworkHelper networkHelper; + @Inject + private NsxService nsxService; @Inject private VpcPrivateGatewayTransactionCallable vpcTxCallable; @@ -270,7 +275,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis private List vpcElements = null; private final List nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall); private final List supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler, - Provider.JuniperContrailVpcRouter, Provider.Ovs, Provider.BigSwitchBcf, Provider.ConfigDrive); + Provider.JuniperContrailVpcRouter, Provider.Ovs, Provider.BigSwitchBcf, Provider.ConfigDrive, Provider.Nsx); int _cleanupInterval; int _maxNetworks; @@ -324,7 +329,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 @@ -343,7 +350,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); } @@ -363,7 +370,44 @@ 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 in NAT mode + if (_vpcOffDao.findByUniqueName(VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME) == null) { + 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()) { + 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_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) { + 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 if (List.of(Service.SourceNat, Service.NetworkACL).contains(svc)){ + 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()); + } } }); @@ -422,7 +466,11 @@ 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(); + nsxMode = validateNsxMode(forNsx, nsxMode); + // check if valid domain if (CollectionUtils.isNotEmpty(cmd.getDomainIds())) { for (final Long domainId: cmd.getDomainIds()) { @@ -445,14 +493,34 @@ 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)); } + private String validateNsxMode(Boolean forNsx, String nsxMode) { + 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 (logger.isTraceEnabled()) { + logger.trace("nsxMode has is ignored for non-NSX enabled zones"); + } + nsxMode = null; + } + } + return nsxMode; + } + @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())); @@ -537,7 +605,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<>(); @@ -565,7 +633,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 @@ -576,6 +644,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (state != null) { offering.setState(state); } + offering.setForNsx(forNsx); + offering.setNsxMode(mode); logger.debug("Adding vpc offering " + offering); offering = _vpcOffDao.persist(offering); // populate services and providers @@ -1092,8 +1162,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis final boolean useDistributedRouter = vpcOff.isSupportsDistributedRouter(); final VpcVO vpc = new VpcVO(zoneId, vpcName, displayText, owner.getId(), owner.getDomainId(), vpcOffId, cidr, networkDomain, useDistributedRouter, isRegionLevelVpcOff, vpcOff.isRedundantRouter(), ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2); - vpc.setPublicMtu(publicMtu); - vpc.setDisplay(Boolean.TRUE.equals(displayVpc)); + vpc.setPublicMtu(publicMtu); + vpc.setDisplay(Boolean.TRUE.equals(displayVpc)); return createVpc(displayVpc, vpc); } @@ -1106,18 +1176,38 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu()); String sourceNatIP = cmd.getSourceNatIP(); - if (sourceNatIP != null) { + boolean forNsx = isVpcForNsx(vpc); + if (sourceNatIP != null || forNsx) { + if (forNsx) { + logger.info("Provided source NAT IP will be ignored in an NSX-enabled zone"); + sourceNatIP = null; + } logger.info(String.format("Trying to allocate the specified IP [%s] as the source NAT of VPC [%s].", sourceNatIP, vpc)); allocateSourceNatIp(vpc, sourceNatIP); } return vpc; } + private boolean isVpcForNsx(Vpc vpc) { + if (vpc == null) { + return false; + } + VpcOfferingServiceMapVO mapVO = _vpcOffSvcMapDao.findByServiceProviderAndOfferingId(Service.SourceNat.getName(), Provider.Nsx.getName(), vpc.getVpcOfferingId()); + if (mapVO != null) { + logger.debug(String.format("The VPC %s is NSX-based and supports the %s service", vpc.getName(), Service.SourceNat.getName())); + } + return mapVO != null; + } + private void allocateSourceNatIp(Vpc vpc, String sourceNatIP) { Account account = _accountMgr.getAccount(vpc.getAccountId()); DataCenter zone = _dcDao.findById(vpc.getZoneId()); // reserve this ip and then try { + if (isVpcForNsx(vpc) && org.apache.commons.lang3.StringUtils.isBlank(sourceNatIP)) { + logger.debug(String.format("Reserving a source NAT IP for NSX VPC %s", vpc.getName())); + sourceNatIP = reserveSourceNatIpForNsxVpc(account, zone); + } IpAddress ip = _ipAddrMgr.allocateIp(account, false, CallContext.current().getCallingAccount(), CallContext.current().getCallingUserId(), zone, null, sourceNatIP); this.associateIPToVpc(ip.getId(), vpc.getId()); } catch (ResourceAllocationException | ResourceUnavailableException | InsufficientAddressCapacityException e){ @@ -1125,6 +1215,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } + private String reserveSourceNatIpForNsxVpc(Account account, DataCenter zone) throws ResourceAllocationException { + IpAddress ipAddress = _ntwkSvc.reserveIpAddressWithVlanDetail(account, zone, true, ApiConstants.NSX_DETAIL_KEY); + return ipAddress.getAddress().addr(); + } + @DB protected Vpc createVpc(final Boolean displayVpc, final VpcVO vpc) { final String cidr = vpc.getCidr(); @@ -1134,7 +1229,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } // cidr has to be RFC 1918 complient - if (!NetUtils.validateGuestCidr(cidr)) { + if (!NetUtils.validateGuestCidr(cidr, !ConfigurationManager.AllowNonRFC1918CompliantIPs.value())) { throw new InvalidParameterValueException("Guest Cidr " + cidr + " is not RFC1918 compliant"); } @@ -1318,6 +1413,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } return vpcDao.findById(vpcId); + } else if (isVpcForNsx(vpcToUpdate)) { + if (logger.isDebugEnabled()) { + logger.debug("no restart needed."); + } + return vpcDao.findById(vpcId); } else { logger.error(String.format("failed to update vpc %s/%s",vpc.getName(), vpc.getUuid())); return null; @@ -1332,6 +1432,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (! userIps.isEmpty()) { try { _ipAddrMgr.updateSourceNatIpAddress(requestedIp, userIps); + if (isVpcForNsx(vpc)) { + nsxService.updateVpcSourceNatIp(vpc, requestedIp); + // The NSX source NAT IP change does not require to update the VPC VR + return false; + } } catch (Exception e) { // pokemon exception from transaction String msg = String.format("Update of source NAT ip to %s for network \"%s\"/%s failed due to %s", requestedIp.getAddress().addr(), vpc.getName(), vpc.getUuid(), e.getLocalizedMessage()); @@ -1775,7 +1880,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis // 5) When aclId is provided, verify that ACLProvider is supported by // network offering - if (aclId != null && !_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.NetworkACL)) { + if (aclId != null && !_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.NetworkACL) && !guestNtwkOff.isForNsx()) { throw new InvalidParameterValueException("Cannot apply NetworkACL. Network Offering does not support NetworkACL service"); } @@ -1793,7 +1898,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis // 2) Only Isolated networks with Source nat service enabled can be // added to vpc - if (!(guestNtwkOff.getGuestType() == GuestType.Isolated && supportedSvcs.contains(Service.SourceNat))) { + if (!guestNtwkOff.isForNsx() && !(guestNtwkOff.getGuestType() == GuestType.Isolated && supportedSvcs.contains(Service.SourceNat))) { throw new InvalidParameterValueException("Only network offerings of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " are valid for vpc "); @@ -1804,10 +1909,10 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis * TODO This should have never been hardcoded like this in the first * place if (guestNtwkOff.getRedundantRouter()) { throw new * InvalidParameterValueException - * ("No redunant router support when network belnogs to VPC"); } + * ("No redundant router support when network belongs to VPC"); } */ - // 4) Conserve mode should be off in older versions + // 4) Conserve mode should be off in older versions ( < 4.19.0.0) if (guestNtwkOff.isConserveMode()) { logger.info("Creating a network with conserve mode in VPC"); } @@ -3087,7 +3192,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Override public boolean isSrcNatIpRequired(long vpcOfferingId) { final Map> vpcOffSvcProvidersMap = getVpcOffSvcProvidersMap(vpcOfferingId); - return vpcOffSvcProvidersMap.get(Network.Service.SourceNat).contains(Network.Provider.VPCVirtualRouter); + return Objects.nonNull(vpcOffSvcProvidersMap.get(Network.Service.SourceNat)) && (vpcOffSvcProvidersMap.get(Network.Service.SourceNat).contains(Network.Provider.VPCVirtualRouter) || + vpcOffSvcProvidersMap.get(Service.SourceNat).contains(Provider.Nsx)); } /** diff --git a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java index 0ccb6c84fb8..81071db3810 100644 --- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java @@ -1198,10 +1198,72 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio } _networkOfferingDao.persistDefaultL2NetworkOfferings(); + + // Offering #9 - network offering for NSX provider - NATTED mode + createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_NAT_NSX_OFFERING, "Offering for NSX enabled networks - NAT mode", + NetworkOffering.NsxMode.NATTED, false, true); + + // Offering #10 - network offering for NSX provider - ROUTED mode + createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_ROUTED_NSX_OFFERING, "Offering for NSX enabled networks - ROUTED mode", + NetworkOffering.NsxMode.ROUTED, false, true); + + // Offering #11 - network offering for NSX provider for VPCs - NATTED mode + createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_NAT_NSX_OFFERING_FOR_VPC, "Offering for NSX enabled networks on VPCs - NAT mode", + NetworkOffering.NsxMode.NATTED, true, true); + + // Offering #12 - network offering for NSX provider for VPCs - ROUTED mode + createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_ROUTED_NSX_OFFERING_FOR_VPC, "Offering for NSX enabled networks on VPCs - ROUTED mode", + NetworkOffering.NsxMode.ROUTED, true, true); + + // Offering #13 - network offering for NSX provider for VPCs with Internal LB - NATTED mode + createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_NAT_NSX_OFFERING_FOR_VPC_WITH_ILB, "Offering for NSX enabled networks on VPCs with internal LB - NAT mode", + NetworkOffering.NsxMode.NATTED, true, false); } }); } + private void createAndPersistDefaultNsxOffering(String name, String displayText, NetworkOffering.NsxMode nsxMode, + boolean forVpc, boolean publicLB) { + NetworkOfferingVO defaultNatNSXNetworkOffering = + new NetworkOfferingVO(name, displayText, TrafficType.Guest, false, false, null, + null, true, Availability.Optional, null, GuestType.Isolated, false, + false, false, false, false, forVpc); + defaultNatNSXNetworkOffering.setPublicLb(publicLB); + defaultNatNSXNetworkOffering.setInternalLb(!publicLB); + defaultNatNSXNetworkOffering.setForNsx(true); + defaultNatNSXNetworkOffering.setNsxMode(nsxMode.name()); + defaultNatNSXNetworkOffering.setState(NetworkOffering.State.Enabled); + defaultNatNSXNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNatNSXNetworkOffering); + + Map serviceProviderMap = getServicesAndProvidersForNSXNetwork(nsxMode, forVpc, publicLB); + for (Map.Entry service : serviceProviderMap.entrySet()) { + NetworkOfferingServiceMapVO offService = + new NetworkOfferingServiceMapVO(defaultNatNSXNetworkOffering.getId(), service.getKey(), service.getValue()); + _ntwkOfferingServiceMapDao.persist(offService); + logger.trace("Added service for the network offering: " + offService); + } + } + + private Map getServicesAndProvidersForNSXNetwork(NetworkOffering.NsxMode nsxMode, boolean forVpc, boolean publicLB) { + final Map serviceProviderMap = new HashMap<>(); + Provider routerProvider = forVpc ? Provider.VPCVirtualRouter : Provider.VirtualRouter; + serviceProviderMap.put(Service.Dhcp, routerProvider); + serviceProviderMap.put(Service.Dns, routerProvider); + serviceProviderMap.put(Service.UserData, routerProvider); + if (forVpc) { + serviceProviderMap.put(Service.NetworkACL, Provider.Nsx); + } else { + serviceProviderMap.put(Service.Firewall, Provider.Nsx); + } + if (nsxMode == NetworkOffering.NsxMode.NATTED) { + serviceProviderMap.put(Service.SourceNat, Provider.Nsx); + serviceProviderMap.put(Service.StaticNat, Provider.Nsx); + serviceProviderMap.put(Service.PortForwarding, Provider.Nsx); + serviceProviderMap.put(Service.Lb, Provider.Nsx); + } + return serviceProviderMap; + } + private void createDefaultNetworks() { List zones = _dataCenterDao.listAll(); long id = 1; diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 0406ba04f8c..705e86f7186 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -839,6 +839,7 @@ import com.cloud.vm.dao.VMInstanceDao; public class ManagementServerImpl extends ManagerBase implements ManagementServer, Configurable { protected StateMachine2 _stateMachine; + static final String FOR_SYSTEMVMS = "forsystemvms"; static final ConfigKey vmPasswordLength = new ConfigKey("Advanced", Integer.class, "vm.password.length", "6", "Specifies the length of a randomly generated password", false); static final ConfigKey sshKeyLength = new ConfigKey("Advanced", Integer.class, "ssh.key.length", "2048", "Specifies custom SSH key length (bit)", true, ConfigKey.Scope.Global); static final ConfigKey humanReadableSizes = new ConfigKey("Advanced", Boolean.class, "display.human.readable.sizes", "true", "Enables outputting human readable byte sizes to logs and usage records.", false, ConfigKey.Scope.Global); @@ -2568,7 +2569,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe sb.and("vpcId", sb.entity().getVpcId(), SearchCriteria.Op.EQ); sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); sb.and("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ); - sb.and("forsystemvms", sb.entity().isForSystemVms(), SearchCriteria.Op.EQ); + sb.and(FOR_SYSTEMVMS, sb.entity().isForSystemVms(), SearchCriteria.Op.EQ); if (forLoadBalancing != null && forLoadBalancing) { final SearchBuilder lbSearch = _loadbalancerDao.createSearchBuilder(); @@ -2614,6 +2615,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe final Boolean staticNat = cmd.isStaticNat(); final Boolean forDisplay = cmd.getDisplay(); final String state = cmd.getState(); + final Boolean forSystemVms = cmd.getForSystemVMs(); final Map tags = cmd.getTags(); sc.setJoinParameters("vlanSearch", "vlanType", vlanType); @@ -2675,7 +2677,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } if (IpAddressManagerImpl.getSystemvmpublicipreservationmodestrictness().value() && IpAddress.State.Free.name().equalsIgnoreCase(state)) { - sc.setParameters("forsystemvms", false); + sc.setParameters(FOR_SYSTEMVMS, false); + } else { + sc.setParameters(FOR_SYSTEMVMS, forSystemVms); } } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index c2ba8b59bf5..b6cc4595066 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -51,6 +51,9 @@ import javax.naming.ConfigurationException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; +import com.cloud.kubernetes.cluster.KubernetesClusterHelper; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NsxProviderVO; import com.cloud.utils.exception.ExceptionProxyObject; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; @@ -589,6 +592,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir @Inject VMScheduleManager vmScheduleManager; + @Inject + NsxProviderDao nsxProviderDao; private ScheduledExecutorService _executor = null; private ScheduledExecutorService _vmIpFetchExecutor = null; @@ -597,6 +602,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir private boolean _dailyOrHourly = false; private int capacityReleaseInterval; private ExecutorService _vmIpFetchThreadExecutor; + private List kubernetesClusterHelpers; private String _instance; @@ -610,6 +616,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir private static final int NUM_OF_2K_BLOCKS = 512; private static final int MAX_HTTP_POST_LENGTH = NUM_OF_2K_BLOCKS * MAX_USER_DATA_LENGTH_BYTES; + public List getKubernetesClusterHelpers() { + return kubernetesClusterHelpers; + } + + public void setKubernetesClusterHelpers(final List kubernetesClusterHelpers) { + this.kubernetesClusterHelpers = kubernetesClusterHelpers; + } + @Inject private OrchestrationService _orchSrvc; @@ -2562,11 +2576,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } // cleanup port forwarding rules - if (_rulesMgr.revokePortForwardingRulesForVm(vmId)) { - logger.debug("Port forwarding rules are removed successfully as a part of vm id=" + vmId + " expunge"); - } else { - success = false; - logger.warn("Fail to remove port forwarding rules as a part of vm id=" + vmId + " expunge"); + VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(vmId); + NsxProviderVO nsx = nsxProviderDao.findByZoneId(vmInstanceVO.getDataCenterId()); + if (Objects.isNull(nsx) || Objects.isNull(kubernetesClusterHelpers.get(0).findByVmId(vmId))) { + if (_rulesMgr.revokePortForwardingRulesForVm(vmId)) { + logger.debug("Port forwarding rules are removed successfully as a part of vm id=" + vmId + " expunge"); + } else { + success = false; + logger.warn("Fail to remove port forwarding rules as a part of vm id=" + vmId + " expunge"); + } } // cleanup load balancer rules diff --git a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java index c09775ddaf6..2dea5a4223f 100644 --- a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java +++ b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java @@ -19,9 +19,14 @@ package org.apache.cloudstack.network.router.deployment; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; +import com.cloud.dc.DataCenter; +import com.cloud.dc.Vlan; import com.cloud.network.dao.NetworkDetailVO; import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NsxProviderVO; import com.cloud.network.router.VirtualRouter; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.dao.DiskOfferingDao; @@ -87,6 +92,7 @@ public class RouterDeploymentDefinition { protected NetworkDao networkDao; protected DomainRouterDao routerDao; + protected NsxProviderDao nsxProviderDao; protected PhysicalNetworkServiceProviderDao physicalProviderDao; protected NetworkModel networkModel; protected VirtualRouterProviderDao vrProviderDao; @@ -384,8 +390,19 @@ public class RouterDeploymentDefinition { protected void findSourceNatIP() throws InsufficientAddressCapacityException, ConcurrentOperationException { sourceNatIp = null; + DataCenter zone = dest.getDataCenter(); + Long zoneId = null; + if (Objects.nonNull(zone)) { + zoneId = zone.getId(); + } + NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId); + if (isPublicNetwork) { - sourceNatIp = ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, guestNetwork); + if (Objects.isNull(nsxProvider)) { + sourceNatIp = ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, guestNetwork); + } else { + sourceNatIp = ipAddrMgr.assignPublicIpAddress(zoneId, getPodId(), owner, Vlan.VlanType.VirtualNetwork, null, null, false, true); + } } } diff --git a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionBuilder.java b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionBuilder.java index aab097115b9..227ae8d641e 100644 --- a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionBuilder.java +++ b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionBuilder.java @@ -23,6 +23,7 @@ import java.util.Map; import javax.inject.Inject; import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.dao.NsxProviderDao; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -63,6 +64,8 @@ public class RouterDeploymentDefinitionBuilder { @Inject private DomainRouterDao routerDao; @Inject + private NsxProviderDao nsxProviderDao; + @Inject private PhysicalNetworkServiceProviderDao physicalProviderDao; @Inject private NetworkModel networkModel; @@ -125,6 +128,7 @@ public class RouterDeploymentDefinitionBuilder { routerDeploymentDefinition.networkDao = networkDao; routerDeploymentDefinition.routerDao = routerDao; + routerDeploymentDefinition.nsxProviderDao = nsxProviderDao; routerDeploymentDefinition.physicalProviderDao = physicalProviderDao; routerDeploymentDefinition.networkModel = networkModel; routerDeploymentDefinition.vrProviderDao = vrProviderDao; diff --git a/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java b/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java index 8b964a3ba80..aa44f29efcd 100644 --- a/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java +++ b/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java @@ -19,7 +19,12 @@ package org.apache.cloudstack.network.router.deployment; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; +import com.cloud.dc.DataCenter; +import com.cloud.dc.Vlan; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.element.NsxProviderVO; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DataCenterDeployment; @@ -118,8 +123,26 @@ public class VpcRouterDeploymentDefinition extends RouterDeploymentDefinition { @Override protected void findSourceNatIP() throws InsufficientAddressCapacityException, ConcurrentOperationException { sourceNatIp = null; + DataCenter zone = dest.getDataCenter(); + Long zoneId = null; + if (Objects.nonNull(zone)) { + zoneId = zone.getId(); + } + NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId); + if (isPublicNetwork) { - sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc); + if (Objects.isNull(nsxProvider)) { + sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc); + } else { + // NSX deploys VRs with Public NIC != to the source NAT, the source NAT IP is on the NSX Public range + sourceNatIp = ipAddrMgr.assignPublicIpAddress(zoneId, getPodId(), owner, Vlan.VlanType.VirtualNetwork, null, null, false, true); + if (vpc != null) { + IPAddressVO routerPublicIp = ipAddressDao.findByIp(sourceNatIp.getAddress().toString()); + routerPublicIp.setVpcId(vpc.getId()); + routerPublicIp.setSourceNat(true); + ipAddressDao.persist(routerPublicIp); + } + } } } diff --git a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index 7227264e229..c80c2947a99 100644 --- a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -106,8 +106,9 @@ - - + + + + diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java index 958a39be410..f7606a9a962 100644 --- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java +++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java @@ -16,12 +16,40 @@ // under the License. package com.cloud.configuration; +import com.cloud.capacity.dao.CapacityDao; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.DataCenterIpAddressDao; +import com.cloud.dc.dao.DedicatedResourceDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.dc.dao.VlanDao; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.dao.HostDao; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.NetworkService; +import com.cloud.network.Networks; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.element.NsxProviderVO; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.storage.StorageManager; +import com.cloud.storage.dao.VMTemplateZoneDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.net.NetUtils; +import com.cloud.vm.dao.VMInstanceDao; +import org.apache.cloudstack.annotation.dao.AnnotationDao; +import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; -import com.cloud.dc.dao.DataCenterDao; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; import com.cloud.offering.DiskOffering; @@ -41,12 +69,28 @@ import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.Collections; import org.mockito.InjectMocks; import org.mockito.Spy; import java.util.ArrayList; import java.util.List; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.nullable; +import static org.mockito.Mockito.anyMap; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.times; @RunWith(MockitoJUnitRunner.class) public class ConfigurationManagerImplTest { @@ -65,8 +109,6 @@ public class ConfigurationManagerImplTest { @Mock Domain domainMock; @Mock - DataCenterDao zoneDaoMock; - @Mock DomainDao domainDaoMock; @Mock EntityManager entityManagerMock; @@ -77,6 +119,48 @@ public class ConfigurationManagerImplTest { @Mock UpdateDiskOfferingCmd updateDiskOfferingCmdMock; + @Mock + NsxProviderDao nsxProviderDao; + @Mock + DataCenterDao zoneDao; + @Mock + HostDao hostDao; + @Mock + HostPodDao podDao; + @Mock + DataCenterIpAddressDao ipAddressDao; + @Mock + IPAddressDao publicIpAddressDao; + @Mock + VMInstanceDao vmInstanceDao; + @Mock + VolumeDao volumeDao; + @Mock + PhysicalNetworkDao physicalNetworkDao; + @Mock + ImageStoreDao imageStoreDao; + @Mock + VlanDao vlanDao; + @Mock + VMTemplateZoneDao vmTemplateZoneDao; + @Mock + CapacityDao capacityDao; + @Mock + DedicatedResourceDao dedicatedResourceDao; + @Mock + AnnotationDao annotationDao; + @Mock + ConfigurationDao configDao; + @Mock + NetworkOfferingDao networkOfferingDao; + @Mock + NetworkService networkService; + @Mock + NetworkModel networkModel; + + DeleteZoneCmd deleteZoneCmd; + CreateNetworkOfferingCmd createNetworkOfferingCmd; + Long validId = 1L; Long invalidId = 100L; List filteredZoneIds = List.of(1L, 2L, 3L); @@ -90,6 +174,28 @@ public class ConfigurationManagerImplTest { @Before public void setUp() throws Exception { configurationManagerImplSpy._configDepot = configDepot; + configurationManagerImplSpy.nsxProviderDao = nsxProviderDao; + configurationManagerImplSpy._zoneDao = zoneDao; + configurationManagerImplSpy._hostDao = hostDao; + configurationManagerImplSpy._podDao = podDao; + configurationManagerImplSpy._privateIpAddressDao = ipAddressDao; + configurationManagerImplSpy._publicIpAddressDao = publicIpAddressDao; + configurationManagerImplSpy._vmInstanceDao = vmInstanceDao; + configurationManagerImplSpy._volumeDao = volumeDao; + configurationManagerImplSpy._physicalNetworkDao = physicalNetworkDao; + configurationManagerImplSpy._imageStoreDao = imageStoreDao; + configurationManagerImplSpy._vlanDao = vlanDao; + configurationManagerImplSpy._capacityDao = capacityDao; + configurationManagerImplSpy._dedicatedDao = dedicatedResourceDao; + configurationManagerImplSpy._configDao = configDao; + configurationManagerImplSpy._networkOfferingDao = networkOfferingDao; + configurationManagerImplSpy._networkSvc = networkService; + configurationManagerImplSpy._networkModel = networkModel; + ReflectionTestUtils.setField(configurationManagerImplSpy, "templateZoneDao", vmTemplateZoneDao); + ReflectionTestUtils.setField(configurationManagerImplSpy, "annotationDao", annotationDao); + + deleteZoneCmd = Mockito.mock(DeleteZoneCmd.class); + createNetworkOfferingCmd = Mockito.mock(CreateNetworkOfferingCmd.class); } @Test @@ -300,6 +406,57 @@ public class ConfigurationManagerImplTest { configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.iprange", "192.168.1.1-192.168.1.100"); } + @Test + public void testDeleteZoneInvokesDeleteNsxProviderWhenNSXIsEnabled() { + NsxProviderVO nsxProviderVO = Mockito.mock(NsxProviderVO.class); + DataCenterVO dataCenterVO = Mockito.mock(DataCenterVO.class); + + when(nsxProviderDao.findByZoneId(anyLong())).thenReturn(nsxProviderVO); + when(zoneDao.findById(anyLong())).thenReturn(dataCenterVO); + lenient().when(hostDao.findByDataCenterId(anyLong())).thenReturn(Collections.emptyList()); + when(podDao.listByDataCenterId(anyLong())).thenReturn(Collections.emptyList()); + when(ipAddressDao.countIPs(anyLong(), anyBoolean())).thenReturn(0); + when(publicIpAddressDao.countIPs(anyLong(), anyBoolean())).thenReturn(0); + when(vmInstanceDao.listByZoneId(anyLong())).thenReturn(Collections.emptyList()); + when(volumeDao.findByDc(anyLong())).thenReturn(Collections.emptyList()); + when(physicalNetworkDao.listByZone(anyLong())).thenReturn(Collections.emptyList()); + when(imageStoreDao.findByZone(any(ZoneScope.class), nullable(Boolean.class))).thenReturn(Collections.emptyList()); + when(vlanDao.listByZone(anyLong())).thenReturn(List.of(Mockito.mock(VlanVO.class))); + when(nsxProviderVO.getId()).thenReturn(1L); + when(zoneDao.remove(anyLong())).thenReturn(true); + when(capacityDao.removeBy(nullable(Short.class), anyLong(), nullable(Long.class), nullable(Long.class), nullable(Long.class))).thenReturn(true); + when(dedicatedResourceDao.findByZoneId(anyLong())).thenReturn(null); + lenient().when(annotationDao.removeByEntityType(anyString(), anyString())).thenReturn(true); + + configurationManagerImplSpy.deleteZone(deleteZoneCmd); + + verify(nsxProviderDao, times(1)).remove(anyLong()); + } + + @Test + public void testCreateNetworkOfferingForNsx() { + NetworkOfferingVO offeringVO = Mockito.mock(NetworkOfferingVO.class); + + when(createNetworkOfferingCmd.isForNsx()).thenReturn(true); + when(createNetworkOfferingCmd.getNsxMode()).thenReturn(NetworkOffering.NsxMode.NATTED.name()); + when(createNetworkOfferingCmd.getTraffictype()).thenReturn(Networks.TrafficType.Guest.name()); + when(createNetworkOfferingCmd.getGuestIpType()).thenReturn(Network.GuestType.Isolated.name()); + when(createNetworkOfferingCmd.getAvailability()).thenReturn(NetworkOffering.Availability.Optional.name()); + lenient().when(configurationManagerImplSpy.createNetworkOffering(anyString(), anyString(), any(Networks.TrafficType.class), anyString(), + anyBoolean(), any(NetworkOffering.Availability.class), anyInt(), anyMap(), anyBoolean(), any(Network.GuestType.class), + anyBoolean(), anyLong(), anyBoolean(), anyMap(), anyBoolean(), anyBoolean(), anyMap(), anyBoolean(), anyInt(), + anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyString(), anyList(), anyList(), anyBoolean(), any(NetUtils.InternetProtocol.class))) + .thenReturn(offeringVO); + when(configDao.getValue(anyString())).thenReturn("1000"); + lenient().when(networkOfferingDao.persist(any(NetworkOfferingVO.class), anyMap())).thenReturn(offeringVO); + doNothing().when(networkService).validateIfServiceOfferingIsActiveAndSystemVmTypeIsDomainRouter(anyLong()); + doNothing().when(networkModel).canProviderSupportServices(anyMap()); + + NetworkOffering offering = configurationManagerImplSpy.createNetworkOffering(createNetworkOfferingCmd); + + Assert.assertNotNull(offering); + } + @Test public void validateDomainTestInvalidIdThrowException() { Mockito.doReturn(null).when(domainDaoMock).findById(invalidId); @@ -308,7 +465,7 @@ public class ConfigurationManagerImplTest { @Test public void validateZoneTestInvalidIdThrowException() { - Mockito.doReturn(null).when(zoneDaoMock).findById(invalidId); + Mockito.doReturn(null).when(zoneDao).findById(invalidId); Assert.assertThrows(InvalidParameterValueException.class, () -> configurationManagerImplSpy.validateZone(List.of(invalidId))); } diff --git a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java index 0bbead6a468..6eb3e5d186b 100644 --- a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java +++ b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java @@ -17,34 +17,80 @@ package com.cloud.network; import com.cloud.dc.DataCenter; +import com.cloud.dc.VlanVO; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.NetworkServiceMapVO; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.element.NetworkElement; +import com.cloud.network.element.VpcVirtualRouterElement; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; import com.cloud.utils.Pair; +import com.cloud.utils.net.Ip; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mockito; +import org.mockito.ArgumentMatchers; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) public class NetworkModelImplTest { - final String[] ip4Dns1 = {"5.5.5.5", "6.6.6.6"}; - final String[] ip4Dns2 = {"7.7.7.7", "8.8.8.8"}; - final String[] ip6Dns1 = {"2001:4860:4860::5555", "2001:4860:4860::6666"}; - final String[] ip6Dns2 = {"2001:4860:4860::7777", "2001:4860:4860::8888"}; + final String[] ip4Dns1 = {"5.5.5.5", "6.6.6.6", "9.9.9.9"}; + final String[] ip4Dns2 = {"7.7.7.7", "8.8.8.8", "10.10.10.10"}; + final String[] ip6Dns1 = {"2001:4860:4860::5555", "2001:4860:4860::6666", "2001:4860:4860::9999"}; + final String[] ip6Dns2 = {"2001:4860:4860::7777", "2001:4860:4860::8888", "2001:4860:4860::AAAA"}; + + @Mock + private VpcDao vpcDao; @InjectMocks private NetworkModelImpl networkModel = new NetworkModelImpl(); - private void prepareMocks(boolean isIp6, Network network, DataCenter zone, - String dns1, String dns2, String dns3, String dns4) { + private NetworkOfferingDao networkOfferingDao; + private NetworkServiceMapDao networkServiceMapDao; + @Before + public void setUp() { + networkOfferingDao = Mockito.mock(NetworkOfferingDao.class); + networkServiceMapDao = Mockito.mock(NetworkServiceMapDao.class); + networkModel._networkOfferingDao = networkOfferingDao; + networkModel._ntwkSrvcDao = networkServiceMapDao; + } + + private void prepareMocks(boolean isIp6, Network network, DataCenter zone, VpcVO vpc, + String networkDns1, String zoneDns1, String networkDns2, String zoneDns2, + String vpcDns1, String vpcDns2) { if (isIp6) { - Mockito.when(network.getIp6Dns1()).thenReturn(dns1); - Mockito.when(zone.getIp6Dns1()).thenReturn(dns2); - Mockito.when(network.getIp6Dns2()).thenReturn(dns3); - Mockito.when(zone.getIp6Dns2()).thenReturn(dns4); + Mockito.when(network.getIp6Dns1()).thenReturn(networkDns1); + Mockito.when(zone.getIp6Dns1()).thenReturn(zoneDns1); + Mockito.when(network.getIp6Dns2()).thenReturn(networkDns2); + Mockito.when(zone.getIp6Dns2()).thenReturn(zoneDns2); + Mockito.when(vpc.getIp6Dns1()).thenReturn(vpcDns1); + Mockito.when(vpc.getIp6Dns2()).thenReturn(vpcDns2); } else { - Mockito.when(network.getDns1()).thenReturn(dns1); - Mockito.when(zone.getDns1()).thenReturn(dns2); - Mockito.when(network.getDns2()).thenReturn(dns3); - Mockito.when(zone.getDns2()).thenReturn(dns4); + Mockito.when(network.getDns1()).thenReturn(networkDns1); + Mockito.when(zone.getDns1()).thenReturn(zoneDns1); + Mockito.when(network.getDns2()).thenReturn(networkDns2); + Mockito.when(zone.getDns2()).thenReturn(zoneDns2); + Mockito.when(vpc.getIp4Dns1()).thenReturn(vpcDns1); + Mockito.when(vpc.getIp4Dns2()).thenReturn(vpcDns2); } } @@ -53,38 +99,53 @@ public class NetworkModelImplTest { String[] dns2 = isIp6 ? ip6Dns2 : ip4Dns2; Network network = Mockito.mock(Network.class); DataCenter zone = Mockito.mock(DataCenter.class); - // Both network and zone have valid dns - prepareMocks(isIp6, network, zone, dns1[0], dns1[1], dns2[0], dns1[1]); + VpcVO vpc = Mockito.mock(VpcVO.class); + Mockito.when(network.getVpcId()).thenReturn(1L); + Mockito.doReturn(vpc).when(vpcDao).findById(ArgumentMatchers.anyLong()); + // network, vpc and zone have valid dns + prepareMocks(isIp6, network, zone, vpc, dns1[0], dns1[1], dns2[0], dns2[1], dns1[2], dns2[2]); Pair result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) : networkModel.getNetworkIp4Dns(network, zone); Assert.assertEquals(dns1[0], result.first()); Assert.assertEquals(dns2[0], result.second()); - // Network has valid dns and zone don't - prepareMocks(isIp6, network, zone, dns1[0], null, dns2[0], null); + // Network has valid dns and vpc/zone don't + prepareMocks(isIp6, network, zone, vpc, dns1[0], null, dns2[0], null, null, null); result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) : networkModel.getNetworkIp4Dns(network, zone); Assert.assertEquals(dns1[0], result.first()); Assert.assertEquals(dns2[0], result.second()); - // Zone has a valid dns and network don't - prepareMocks(isIp6, network, zone, null, dns1[1], null, dns2[1]); + // Vpc has valid dns and network/zone don't + prepareMocks(isIp6, network, zone, vpc, null, null, null, null, dns1[2], dns2[2]); + result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) : + networkModel.getNetworkIp4Dns(network, zone); + Assert.assertEquals(dns1[2], result.first()); + Assert.assertEquals(dns2[2], result.second()); + // Zone has a valid dns and network/vpc don't + prepareMocks(isIp6, network, zone, vpc, null, dns1[1], null, dns2[1], null, null); result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) : networkModel.getNetworkIp4Dns(network, zone); Assert.assertEquals(dns1[1], result.first()); Assert.assertEquals(dns2[1], result.second()); - // Zone has a valid dns and network has only first dns - prepareMocks(isIp6, network, zone, dns1[0], dns1[1], null, dns2[1]); + // Zone/vpc has a valid dns and network has only first dns + prepareMocks(isIp6, network, zone, vpc, dns1[0], dns1[1], null, dns2[1], dns1[2], dns2[2]); result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) : networkModel.getNetworkIp4Dns(network, zone); Assert.assertEquals(dns1[0], result.first()); Assert.assertNull(result.second()); - // Both network and zone only have the first dns - prepareMocks(isIp6, network, zone, dns1[0], dns1[1], null, null); + // network don't have a valid dns, vpc has only first dns, Zone has a valid dns + prepareMocks(isIp6, network, zone, vpc, null, dns1[1], null, dns2[1], dns1[2], null); + result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) : + networkModel.getNetworkIp4Dns(network, zone); + Assert.assertEquals(dns1[2], result.first()); + Assert.assertNull(result.second()); + // network/vpc/zone only have the first dns + prepareMocks(isIp6, network, zone, vpc, dns1[0], dns1[1], null, null, dns1[2], null); result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) : networkModel.getNetworkIp4Dns(network, zone); Assert.assertEquals(dns1[0], result.first()); Assert.assertNull(result.second()); - // Both network and zone dns are null - prepareMocks(isIp6, network, zone, null, null, null, null); + // network/vpc and zone dns are null + prepareMocks(isIp6, network, zone, vpc, null, null, null, null, null, null); result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) : networkModel.getNetworkIp4Dns(network, zone); Assert.assertNull(result.first()); @@ -140,4 +201,35 @@ public class NetworkModelImplTest { public void testVerifyIp6DnsPairValid() { networkModel.verifyIp6DnsPair(ip6Dns1[0], ip6Dns1[1]); } + + @Test + public void testGetProviderToIpList() { + Set services1 = new HashSet<>(List.of(Network.Service.Firewall)); + Set services2 = new HashSet<>(List.of(Network.Service.SourceNat)); + Ip ip1 = new Ip("10.10.10.10"); + Ip ip2 = new Ip("10.10.10.10"); + IPAddressVO ipAddressVO1 = new IPAddressVO(ip1, 1L, 0x0ac00000L, 2L, true); + IPAddressVO ipAddressVO2 = new IPAddressVO(ip2, 1L, 0x0ac00000L, 2L, true); + VlanVO vlanVO = new VlanVO(); + vlanVO.setNetworkId(15L); + PublicIpAddress publicIpAddress1 = new PublicIp(ipAddressVO1, vlanVO, 0x0ac00000L); + PublicIpAddress publicIpAddress2 = new PublicIp(ipAddressVO2, vlanVO, 0x0ac00000L); + NetworkOfferingVO networkOfferingVO = new NetworkOfferingVO(); + networkOfferingVO.setForVpc(true); + networkOfferingVO.setForNsx(false); + Network network = new NetworkVO(); + List networkServiceMapVOs = new ArrayList<>(); + networkServiceMapVOs.add(new NetworkServiceMapVO(15L, Network.Service.Firewall, Network.Provider.VPCVirtualRouter)); + networkServiceMapVOs.add(new NetworkServiceMapVO(15L, Network.Service.SourceNat, Network.Provider.VPCVirtualRouter)); + NetworkElement element = new VpcVirtualRouterElement(); + + ReflectionTestUtils.setField(networkModel, "networkElements", List.of(element)); + Mockito.when(networkOfferingDao.findById(ArgumentMatchers.anyLong())).thenReturn(networkOfferingVO); + Mockito.when(networkServiceMapDao.getServicesInNetwork(ArgumentMatchers.anyLong())).thenReturn(networkServiceMapVOs); + Map> ipToServices = new HashMap<>(); + ipToServices.put(publicIpAddress1, services1); + ipToServices.put(publicIpAddress2, services2); + Map> result = networkModel.getProviderToIpList(network, ipToServices); + Assert.assertNotNull(result); + } } diff --git a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java index c993f7b7095..f2ab2a08ae7 100644 --- a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java +++ b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java @@ -40,6 +40,7 @@ import java.util.UUID; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; +import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.dao.PublicIpQuarantineDao; import com.cloud.network.vo.PublicIpQuarantineVO; import com.cloud.user.dao.AccountDao; @@ -212,6 +213,8 @@ public class NetworkServiceImplTest { @Mock private Ip ipMock; + @Mock + private NsxProviderDao nsxProviderDao; private static Date beforeDate; @@ -295,6 +298,7 @@ public class NetworkServiceImplTest { service.commandSetupHelper = commandSetupHelper; service.networkHelper = networkHelper; service._ipAddrMgr = ipAddressManagerMock; + service.nsxProviderDao = nsxProviderDao; callContextMocked = Mockito.mockStatic(CallContext.class); CallContext callContextMock = Mockito.mock(CallContext.class); callContextMocked.when(CallContext::current).thenReturn(callContextMock); diff --git a/server/src/test/java/com/cloud/network/guru/DirectNetworkGuruTest.java b/server/src/test/java/com/cloud/network/guru/DirectNetworkGuruTest.java index 9818b43e650..50d8af5e520 100644 --- a/server/src/test/java/com/cloud/network/guru/DirectNetworkGuruTest.java +++ b/server/src/test/java/com/cloud/network/guru/DirectNetworkGuruTest.java @@ -142,7 +142,7 @@ public class DirectNetworkGuruTest { when(networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Network.Service.SecurityGroup)).thenReturn(true); - assertNotNull(guru.design(offering, plan, network, owner)); + assertNotNull(guru.design(offering, plan, network, "", 1L, owner)); } @Test @@ -159,7 +159,7 @@ public class DirectNetworkGuruTest { when(networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Network.Service.SecurityGroup)).thenReturn(false); - Network config = guru.design(offering, plan, network, owner); + Network config = guru.design(offering, plan, network, "", 1L, owner); assertNotNull(config); assertEquals(ip4Dns[0], config.getDns1()); assertEquals(ip4Dns[1], config.getDns2()); diff --git a/server/src/test/java/com/cloud/network/guru/ExternalGuestNetworkGuruTest.java b/server/src/test/java/com/cloud/network/guru/ExternalGuestNetworkGuruTest.java index 3286ee54b3b..bcb39b6b3b5 100644 --- a/server/src/test/java/com/cloud/network/guru/ExternalGuestNetworkGuruTest.java +++ b/server/src/test/java/com/cloud/network/guru/ExternalGuestNetworkGuruTest.java @@ -75,7 +75,7 @@ public class ExternalGuestNetworkGuruTest { Mockito.when(network.getIp6Dns1()).thenReturn(ip6Dns[0]); Mockito.when(network.getIp6Dns2()).thenReturn(ip6Dns[1]); Account owner = Mockito.mock(Account.class); - Network config = guru.design(networkOffering, plan, network, owner); + Network config = guru.design(networkOffering, plan, network, "", 1L, owner); assertNotNull(config); assertEquals(ip4Dns[0], config.getDns1()); assertEquals(ip4Dns[1], config.getDns2()); diff --git a/server/src/test/java/com/cloud/network/router/CommandSetupHelperTest.java b/server/src/test/java/com/cloud/network/router/CommandSetupHelperTest.java index f03ae9d62b2..37fa13baf98 100644 --- a/server/src/test/java/com/cloud/network/router/CommandSetupHelperTest.java +++ b/server/src/test/java/com/cloud/network/router/CommandSetupHelperTest.java @@ -16,21 +16,93 @@ // under the License. package com.cloud.network.router; +import com.cloud.agent.api.Command; import com.cloud.agent.api.routing.VmDataCommand; +import com.cloud.agent.manager.Commands; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.network.NetworkModel; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingDetailsDao; +import com.cloud.utils.net.Ip; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.dao.NicDao; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @RunWith(MockitoJUnitRunner.class) public class CommandSetupHelperTest { @InjectMocks protected CommandSetupHelper commandSetupHelper = new CommandSetupHelper(); + @Mock + NicDao nicDao; + @Mock + NetworkDao networkDao; + @Mock + IPAddressDao ipAddressDao; + @Mock + VlanDao vlanDao; + @Mock + NetworkModel networkModel; + @Mock + NetworkOfferingDao networkOfferingDao; + @Mock + ConfigurationManager configurationManager; + @Mock + NetworkOfferingDetailsDao networkOfferingDetailsDao; + @Mock + NetworkDetailsDao networkDetailsDao; + @Mock + VpcDao vpcDao; + @Mock + RouterControlHelper routerControlHelper; + @Mock + DataCenterDao dcDao; + + @Before + public void setUp() { + ReflectionTestUtils.setField(commandSetupHelper, "_nicDao", nicDao); + ReflectionTestUtils.setField(commandSetupHelper, "_networkDao", networkDao); + ReflectionTestUtils.setField(commandSetupHelper, "_ipAddressDao", ipAddressDao); + ReflectionTestUtils.setField(commandSetupHelper, "_vlanDao", vlanDao); + ReflectionTestUtils.setField(commandSetupHelper, "_networkModel", networkModel); + ReflectionTestUtils.setField(commandSetupHelper, "_networkOfferingDao", networkOfferingDao); + ReflectionTestUtils.setField(commandSetupHelper, "networkOfferingDetailsDao", networkOfferingDetailsDao); + ReflectionTestUtils.setField(commandSetupHelper, "networkDetailsDao", networkDetailsDao); + ReflectionTestUtils.setField(commandSetupHelper, "_vpcDao", vpcDao); + ReflectionTestUtils.setField(commandSetupHelper, "_routerControlHelper", routerControlHelper); + ReflectionTestUtils.setField(commandSetupHelper, "_dcDao", dcDao); + } @Test public void testUserDataDetails() { @@ -79,4 +151,46 @@ public class CommandSetupHelperTest { Assert.assertEquals("value1", metadataFile1[2]); Assert.assertEquals("value2", metadataFile2[2]); } + + @Test + public void testCreateVpcAssociatePublicIP() { + VirtualRouter router = Mockito.mock(VirtualRouter.class); + Ip ip = new Ip("10.10.10.10"); + IPAddressVO ipAddressVO = new IPAddressVO(ip, 1L, 0x0ac00000L, 2L, true); + VlanVO vlanVO = new VlanVO(); + vlanVO.setNetworkId(15L); + PublicIpAddress publicIpAddress = new PublicIp(ipAddressVO, vlanVO, 0x0ac00000L); + List pubIpList = new ArrayList<>(1); + pubIpList.add(publicIpAddress); + Commands commands = new Commands(Command.OnError.Stop); + Map vlanMacAddress = new HashMap<>(); + NicVO nicVO = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User); + NetworkVO networkVO = new NetworkVO(); + networkVO.setNetworkOfferingId(12L); + List userIps = List.of(ipAddressVO); + NetworkOfferingVO networkOfferingVO = new NetworkOfferingVO(); + Map details = new HashMap<>(); + VpcVO vpc = new VpcVO(); + DataCenterVO dc = new DataCenterVO(1L, null, null, null, null, null, null, null, null, null, DataCenter.NetworkType.Advanced, null, null); + + Mockito.when(router.getId()).thenReturn(14L); + Mockito.when(router.getDataCenterId()).thenReturn(4L); + Mockito.when(nicDao.listByVmId(ArgumentMatchers.anyLong())).thenReturn(List.of(nicVO)); + Mockito.when(networkDao.findById(ArgumentMatchers.anyLong())).thenReturn(networkVO); + Mockito.when(ipAddressDao.listByAssociatedVpc(ArgumentMatchers.anyLong(), ArgumentMatchers.nullable(Boolean.class))).thenReturn(userIps); + Mockito.when(vlanDao.findById(ArgumentMatchers.anyLong())).thenReturn(vlanVO); + Mockito.when(networkModel.getNetworkRate(ArgumentMatchers.anyLong(), ArgumentMatchers.anyLong())).thenReturn(1200); + Mockito.when(networkModel.getNetwork(ArgumentMatchers.anyLong())).thenReturn(networkVO); + Mockito.when(networkOfferingDao.findById(ArgumentMatchers.anyLong())).thenReturn(networkOfferingVO); + Mockito.when(configurationManager.getNetworkOfferingNetworkRate(ArgumentMatchers.anyLong(), ArgumentMatchers.anyLong())).thenReturn(1200); + Mockito.when(networkModel.isSecurityGroupSupportedInNetwork(networkVO)).thenReturn(false); + Mockito.when(networkOfferingDetailsDao.getNtwkOffDetails(ArgumentMatchers.anyLong())).thenReturn(details); + Mockito.when(networkDetailsDao.findDetail(ArgumentMatchers.anyLong(), ArgumentMatchers.anyString())).thenReturn(null); + Mockito.when(vpcDao.findById(ArgumentMatchers.anyLong())).thenReturn(vpc); + Mockito.when(routerControlHelper.getRouterControlIp(ArgumentMatchers.anyLong())).thenReturn("10.1.11.101"); + Mockito.when(dcDao.findById(ArgumentMatchers.anyLong())).thenReturn(dc); + + commandSetupHelper.createVpcAssociatePublicIPCommands(router, pubIpList, commands, vlanMacAddress); + Assert.assertEquals(2, commands.size()); + } } diff --git a/server/src/test/java/com/cloud/network/router/NetworkHelperImplTest.java b/server/src/test/java/com/cloud/network/router/NetworkHelperImplTest.java index 8e1408d4998..a729af07106 100644 --- a/server/src/test/java/com/cloud/network/router/NetworkHelperImplTest.java +++ b/server/src/test/java/com/cloud/network/router/NetworkHelperImplTest.java @@ -23,6 +23,11 @@ import com.cloud.agent.manager.Commands; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.NetworkDao; +import com.cloud.vm.dao.NicDao; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -51,6 +56,20 @@ public class NetworkHelperImplTest { @InjectMocks protected NetworkHelperImpl nwHelper = new NetworkHelperImpl(); + @Mock + NetworkOrchestrationService networkOrchestrationService; + @Mock + NetworkDao networkDao; + @Mock + NetworkModel networkModel; + @Mock + NicDao nicDao; + + @Before + public void setUp() { + nwHelper._networkDao = networkDao; + nwHelper._networkModel = networkModel; + } @Test(expected=ResourceUnavailableException.class) public void testSendCommandsToRouterWrongRouterVersion() @@ -168,5 +187,4 @@ public class NetworkHelperImplTest { verify(answer1, times(0)).getResult(); assertFalse(result); } - } diff --git a/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java b/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java index bce081d4319..b24136972ad 100644 --- a/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java +++ b/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java @@ -17,10 +17,12 @@ package com.cloud.network.vpc; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.ArgumentMatchers.eq; + import static org.mockito.Mockito.times; import java.util.ArrayList; @@ -29,7 +31,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.cloud.dc.DataCenter; import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.utils.net.NetUtils; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -104,6 +108,8 @@ public class NetworkACLServiceImplTest { private NetworkACLVO networkACLVOMock; @Mock private UpdateNetworkACLListCmd updateNetworkACLListCmdMock; + @Mock + private NsxProviderDao nsxProviderDao; private Long networkAclMockId = 5L; private Long networkOfferingMockId = 2L; @@ -130,6 +136,8 @@ public class NetworkACLServiceImplTest { @Mock private VpcVO vpcVOMock; + @Mock + DataCenter dataCenterVO; @Mock private Account accountMock; @@ -174,7 +182,9 @@ public class NetworkACLServiceImplTest { private void createNetworkACLItemTestForNumberAndExecuteTest(Integer number) { Mockito.when(createNetworkAclCmdMock.getNumber()).thenReturn(number); - + Mockito.when(vpcDaoMock.findById(anyLong())).thenReturn(vpcVOMock); + Mockito.when(entityManagerMock.findById(any(), anyLong())).thenReturn(dataCenterVO); + Mockito.when(nsxProviderDao.findByZoneId(anyLong())).thenReturn(null); Mockito.doReturn(networkAclMockId).when(networkAclServiceImpl).createAclListIfNeeded(createNetworkAclCmdMock); Mockito.when(networkAclManagerMock.getNetworkACL(networkAclMockId)).thenReturn(networkAclMock); @@ -711,6 +721,9 @@ public class NetworkACLServiceImplTest { @Test public void updateNetworkACLItemTest() throws ResourceUnavailableException { Mockito.when(networkAclItemVoMock.getAclId()).thenReturn(networkAclMockId); + Mockito.when(vpcDaoMock.findById(anyLong())).thenReturn(vpcVOMock); + Mockito.when(entityManagerMock.findById(any(), anyLong())).thenReturn(dataCenterVO); + Mockito.when(nsxProviderDao.findByZoneId(anyLong())).thenReturn(null); Mockito.doReturn(networkAclItemVoMock).when(networkAclServiceImpl).validateNetworkAclRuleIdAndRetrieveIt(updateNetworkACLItemCmdMock); Mockito.doReturn(networkAclMock).when(networkAclManagerMock).getNetworkACL(networkAclMockId); Mockito.doNothing().when(networkAclServiceImpl).validateNetworkAcl(Mockito.eq(networkAclMock)); diff --git a/server/src/test/java/com/cloud/server/ManagementServerImplTest.java b/server/src/test/java/com/cloud/server/ManagementServerImplTest.java index ba9fff5ad40..4cb2b61f94d 100644 --- a/server/src/test/java/com/cloud/server/ManagementServerImplTest.java +++ b/server/src/test/java/com/cloud/server/ManagementServerImplTest.java @@ -252,7 +252,7 @@ public class ManagementServerImplTest { Mockito.verify(sc, Mockito.times(1)).setParameters("display", false); Mockito.verify(sc, Mockito.times(1)).setParameters("sourceNetworkId", 10L); Mockito.verify(sc, Mockito.times(1)).setParameters("state", "Free"); - Mockito.verify(sc, Mockito.never()).setParameters("forsystemvms", false); + Mockito.verify(sc, Mockito.times(1)).setParameters("forsystemvms", false); } @Test @@ -274,7 +274,7 @@ public class ManagementServerImplTest { Mockito.verify(sc, Mockito.times(1)).setJoinParameters("vlanSearch", "vlanType", VlanType.VirtualNetwork); Mockito.verify(sc, Mockito.times(1)).setParameters("display", false); Mockito.verify(sc, Mockito.times(1)).setParameters("sourceNetworkId", 10L); - Mockito.verify(sc, Mockito.never()).setParameters("forsystemvms", false); + Mockito.verify(sc, Mockito.times(1)).setParameters("forsystemvms", false); } @Test @@ -296,7 +296,7 @@ public class ManagementServerImplTest { Mockito.verify(sc, Mockito.times(1)).setJoinParameters("vlanSearch", "vlanType", VlanType.VirtualNetwork); Mockito.verify(sc, Mockito.times(1)).setParameters("display", false); Mockito.verify(sc, Mockito.times(1)).setParameters("sourceNetworkId", 10L); - Mockito.verify(sc, Mockito.never()).setParameters("forsystemvms", false); + Mockito.verify(sc, Mockito.times(1)).setParameters("forsystemvms", false); } @Test diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index 1d9b65afd1b..f9f66550657 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, 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; } @@ -556,7 +556,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu */ @Override public 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 vlanGatewayv6, String vlanCidrv6) + String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6, boolean forNsx) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException { // TODO Auto-generated method stub return null; diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java index 434c644f596..106fc7fa543 100644 --- a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java @@ -26,6 +26,7 @@ import javax.naming.ConfigurationException; import com.cloud.dc.DataCenter; import com.cloud.network.PublicIpQuarantine; +import com.cloud.network.VirtualRouterProvider; import com.cloud.utils.fsm.NoTransitionException; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.command.admin.address.ReleasePodIpCmdByAdmin; @@ -46,6 +47,7 @@ import org.apache.cloudstack.api.command.user.network.UpdateNetworkCmd; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import org.apache.cloudstack.api.response.AcquirePodIpCmdResponse; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; import org.springframework.stereotype.Component; import com.cloud.deploy.DataCenterDeployment; @@ -181,6 +183,11 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches return null; } + @Override + public IpAddress reserveIpAddressWithVlanDetail(Account account, DataCenter zone, Boolean displayIp, String vlanDetailKey) throws ResourceAllocationException { + return null; + } + @Override public boolean releaseReservedIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { return false; @@ -1081,4 +1088,24 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches public void removePublicIpAddressFromQuarantine(RemoveQuarantinedIpCmd cmd) { } + + @Override + public InternalLoadBalancerElementService getInternalLoadBalancerElementByType(VirtualRouterProvider.Type type) { + return null; + } + + @Override + public InternalLoadBalancerElementService getInternalLoadBalancerElementByNetworkServiceProviderId(long networkProviderId) { + return null; + } + + @Override + public InternalLoadBalancerElementService getInternalLoadBalancerElementById(long providerId) { + return null; + } + + @Override + public List getInternalLoadBalancerElements() { + return null; + } } diff --git a/server/src/test/java/com/cloud/vpc/NetworkACLServiceTest.java b/server/src/test/java/com/cloud/vpc/NetworkACLServiceTest.java index d2f00c409ae..6579a892ec6 100644 --- a/server/src/test/java/com/cloud/vpc/NetworkACLServiceTest.java +++ b/server/src/test/java/com/cloud/vpc/NetworkACLServiceTest.java @@ -18,6 +18,7 @@ package com.cloud.vpc; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.NetworkModel; import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.vpc.NetworkACLItemDao; import com.cloud.network.vpc.NetworkACLItemVO; import com.cloud.network.vpc.NetworkACLManager; @@ -78,6 +79,8 @@ public class NetworkACLServiceTest extends TestCase { private NetworkACLItemDao _networkACLItemDao; @Inject private EntityManager _entityMgr; + @Inject + private NsxProviderDao nsxProviderDao; private NetworkACLVO acl; private NetworkACLItemVO aclItem; @@ -184,6 +187,9 @@ public class NetworkACLServiceTest extends TestCase { return Mockito.mock(VpcService.class); } + @Bean + public NsxProviderDao nsxProviderDao() { return Mockito.mock(NsxProviderDao.class); } + public static class Library implements TypeFilter { @Override public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { diff --git a/server/src/test/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionTest.java b/server/src/test/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionTest.java index f9d6d0dfcba..679324fed2f 100644 --- a/server/src/test/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionTest.java +++ b/server/src/test/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionTest.java @@ -31,6 +31,7 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.network.VirtualRouterProvider.Type; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.element.VirtualRouterProviderVO; import com.cloud.network.router.VirtualRouter.Role; @@ -73,6 +74,8 @@ public class RouterDeploymentDefinitionTest extends RouterDeploymentDefinitionTe @Mock protected NetworkVO mockNw; + @Mock + protected NsxProviderDao nsxProviderDao; protected RouterDeploymentDefinition deployment; diff --git a/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java b/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java index 969fb1f209c..a355ad21f2b 100644 --- a/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java +++ b/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java @@ -24,6 +24,7 @@ import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.router.NicProfileHelper; @@ -62,6 +63,8 @@ public class VpcRouterDeploymentDefinitionTest extends RouterDeploymentDefinitio @Mock protected VpcDao mockVpcDao; @Mock + protected NsxProviderDao nsxProviderDao; + @Mock protected PhysicalNetworkDao mockPhNwDao; protected PhysicalNetworkServiceProviderDao mockPhProviderDao; 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 d0b7ace4711..838bb3dadcb 100644 --- a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -43,6 +43,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.dao.VlanDetailsDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.event.dao.UsageEventDetailsDao; import com.cloud.exception.InvalidParameterValueException; @@ -103,6 +104,8 @@ public class CreateNetworkOfferingTest extends TestCase { @Inject AnnotationDao annotationDao; + @Inject + VlanDetailsDao vlanDetailsDao; @Inject PublicIpQuarantineDao publicIpQuarantineDao; @@ -135,7 +138,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, 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); } @@ -143,7 +146,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, 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); } @@ -151,7 +154,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, 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); } @@ -160,7 +163,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, 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); } @@ -173,7 +176,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, 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); } @@ -186,7 +189,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, 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); } @@ -199,7 +202,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, 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); } @@ -210,7 +213,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, 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); } @@ -228,7 +231,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, 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); } @@ -248,7 +251,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, 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/server/src/test/resources/createNetworkOffering.xml b/server/src/test/resources/createNetworkOffering.xml index 28e602720e8..787de99a754 100644 --- a/server/src/test/resources/createNetworkOffering.xml +++ b/server/src/test/resources/createNetworkOffering.xml @@ -72,5 +72,7 @@ + + diff --git a/systemvm/debian/opt/cloud/bin/cs/CsGuestNetwork.py b/systemvm/debian/opt/cloud/bin/cs/CsGuestNetwork.py index a934862c224..41b8b644186 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsGuestNetwork.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsGuestNetwork.py @@ -40,7 +40,7 @@ class CsGuestNetwork: return self.config.get_dns() dns = [] - if 'router_guest_gateway' in self.data and not self.config.use_extdns(): + if 'router_guest_gateway' in self.data and not self.config.use_extdns() and 'is_vr_guest_gateway' not in self.data: dns.append(self.data['router_guest_gateway']) if 'dns' in self.data: diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index b971d244941..9df6bf9efc5 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -134,6 +134,9 @@ known_categories = { 'removeTungstenFabricNetworkGatewayFromLogicalRouter': 'Tungsten', 'updateTungstenFabricLBHealthMonitor': 'Tungsten', 'listTungstenFabricLBHealthMonitor': 'Tungsten', + 'listNsxControllers': 'NSX', + 'addNsxController': 'NSX', + 'deleteNsxController': 'NSX', 'Vpn': 'VPN', 'Limit': 'Limit', 'ResourceCount': 'Limit', diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 1fa2318c37c..08d7d82b1a1 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -15,8 +15,8 @@ "error.release.dedicate.zone": "Failed to release dedicated zone.", "error.unable.to.proceed": "Unable to proceed. Please contact your administrator.", "firewall.close": "Firewall", -"icmp.code.desc": "Please specify -1 if you want to allow all ICMP codes.", -"icmp.type.desc": "Please specify -1 if you want to allow all ICMP types.", +"icmp.code.desc": "Please specify -1 if you want to allow all ICMP codes (except NSX zones).", +"icmp.type.desc": "Please specify -1 if you want to allow all ICMP types (except NSX zones).", "inline": "Inline", "label.about": "About", "label.about.app": "About CloudStack", @@ -913,6 +913,8 @@ "label.forceencap": "Force UDP encapsulation of ESP packets", "label.forgedtransmits": "Forged transmits", "label.format": "Format", +"label.fornsx": "NSX", +"label.forvpc": "VPC", "label.free": "Free", "label.french.azerty.keyboard": "French AZERTY keyboard", "label.friday": "Friday", @@ -1051,7 +1053,7 @@ "label.internaldns2": "Internal DNS 2", "label.internallb.description": "Brief description of the internal LB.", "label.internallb.name.description": "Unique name for internal LB.", -"label.internallb.sourceip.description": "Brief description of the internal LB.", +"label.internallb.sourceip.description": "Source IP address the network traffic will be load balanced from", "label.internallbvm": "InternalLbVm", "label.internetprotocol": "Internet protocol", "label.interval": "Polling interval (in sec)", @@ -1340,6 +1342,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", @@ -1434,6 +1437,19 @@ "label.not.found": "Not found", "label.not.suitable": "Not suitable", "label.notifications": "Notifications", +"label.nsx": "NSX", +"label.nsxmode": "NSX Mode", +"label.nsx.provider": "NSX Provider", +"label.nsx.provider.name": "NSX provider name", +"label.nsx.provider.hostname": "NSX provider hostname", +"label.nsx.provider.port": "NSX provider port", +"label.nsx.provider.username": "NSX provider username", +"label.nsx.provider.password": "NSX provider password", +"label.nsx.provider.edgecluster": "NSX provider edge cluster", +"label.nsx.provider.tier0gateway": "NSX provider tier-0 gateway", +"label.nsx.provider.transportzone": "NSX provider transport zone", +"label.nsx.supports.internal.lb": "Enable NSX internal LB service", +"label.nsx.supports.lb": "Enable NSX LB service", "label.num.cpu.cores": "# of CPU cores", "label.number": "#Rule", "label.numretries": "Number of retries", @@ -1621,6 +1637,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", @@ -2045,7 +2062,9 @@ "label.systemvm": "System VM", "label.systemvmtype": "System VM type", "label.tag": "Tag", +"label.tag.nsx": "nsx", "label.tag.key": "Tag key", +"label.tag.systemvm": "systemvm", "label.tag.value": "Tag value", "label.tagged": "Tagged", "label.tagged.limits": "Tagged limits", @@ -2498,11 +2517,12 @@ "message.remove.ip.v6.firewall.rule.failed": "Failed to remove IPv6 firewall rule", "message.remove.ip.v6.firewall.rule.processing": "Removing IPv6 firewall rule...", "message.remove.ip.v6.firewall.rule.success": "Removed IPv6 firewall rule", -"message.add.network": "Add a new Network for zone: ", -"message.add.network.acl.failed": "Adding Network ACL list failed.", -"message.add.network.acl.processing": "Adding Network ACL list...", -"message.add.network.failed": "Adding Network failed.", -"message.add.network.processing": "Adding Network...", +"message.add.nsx.controller": "Add NSX Provider", +"message.add.network": "Add a new network for zone: ", +"message.add.network.acl.failed": "Adding network ACL list failed.", +"message.add.network.acl.processing": "Adding network ACL list...", +"message.add.network.failed": "Adding network failed.", +"message.add.network.processing": "Adding network...", "message.add.new.gateway.to.vpc": "Please specify the information to add a new gateway to this VPC.", "message.add.physical.network.failed": "Adding physical network failed", "message.add.physical.network.processing": "Adding a new physical network...", @@ -2575,6 +2595,7 @@ "message.configuring.guest.traffic": "Configuring guest traffic", "message.configuring.physical.networks": "Configuring physical Networks", "message.configuring.public.traffic": "Configuring public traffic", +"message.configuring.nsx.public.traffic": "Configuring NSX public traffic", "message.configuring.storage.traffic": "Configuring storage traffic", "message.confirm.action.force.reconnect": "Please confirm that you want to force reconnect this host.", "message.confirm.add.router.table.to.instance": "Please confirm that you want to add Route Table to this NIC", @@ -2916,6 +2937,7 @@ "message.import.running.instance.warning": "The selected VM is powered-on on the VMware Datacenter. The recommended state to convert a VMware VM into KVM is powered-off after a graceful shutdown of the guest OS.", "message.info.cloudian.console": "Cloudian Management Console should open in another window.", "message.installwizard.cloudstack.helptext.website": " * Project website:\t ", +"message.infra.setup.nsx.description": "This zone must contain an NSX provider because the isolation method is NSX", "message.infra.setup.tungsten.description": "This zone must contain a Tungsten-Fabric provider because the isolation method is TF", "message.installwizard.cloudstack.helptext.document": " * Documentation:\t ", "message.installwizard.cloudstack.helptext.header": "\nYou can find more information about Apache CloudStackâ„¢ on the pages listed below.\n", @@ -2932,6 +2954,12 @@ "message.installwizard.tooltip.configureguesttraffic.guestgateway": "The gateway that the guests should use.", "message.installwizard.tooltip.configureguesttraffic.guestnetmask": "The netmask in use on the subnet that the guests should use.", "message.installwizard.tooltip.configureguesttraffic.gueststartip": "The range of IP addresses that will be available for allocation to guests in this zone. If one NIC is used, these IPs should be in the same CIDR as the pod CIDR.", +"message.installwizard.tooltip.nsx.provider.hostname": "NSX Provider hostname / IP address not provided", +"message.installwizard.tooltip.nsx.provider.username": "NSX Provider username not provided", +"message.installwizard.tooltip.nsx.provider.password": "NSX Provider password not provided", +"message.installwizard.tooltip.nsx.provider.edgecluster": "NSX Provider edge cluster information not provided", +"message.installwizard.tooltip.nsx.provider.tier0gateway": "NSX Provider tier-0 gateway information not provided", +"message.installwizard.tooltip.nsx.provider.transportZone": "NSX Provider transport zone information not provided", "message.installwizard.tooltip.tungsten.provider.gateway": "Tungsten provider gateway is required", "message.installwizard.tooltip.tungsten.provider.hostname": "Tungsten provider hostname is required", "message.installwizard.tooltip.tungsten.provider.introspectport": "Tungsten provider introspect port is required", @@ -2952,6 +2980,7 @@ "message.kubernetes.cluster.stop": "Please confirm that you want to stop the cluster.", "message.kubernetes.cluster.upgrade": "Please select new Kubernetes version.", "message.kubernetes.version.delete": "Please confirm that you want to delete this Kubernetes version.", +"message.l2.network.unsupported.for.nsx": "L2 networks aren't supported for NSX enabled zones", "message.launch.zone": "Zone is ready to launch; please proceed to the next step.", "message.launch.zone.description": "Zone is ready to launch; please proceed to the next step.", "message.launch.zone.hint": "Configure Network components and traffic including IP addresses.", @@ -3102,6 +3131,7 @@ "message.setup.physical.network.during.zone.creation": "When adding a zone, you need to set up one or more physical networks. Each physical network can carry one or more types of traffic, with certain restrictions on how they may be combined. Add or remove one or more traffic types onto each physical network.", "message.setup.physical.network.during.zone.creation.basic": "When adding a basic zone, you can set up one physical Network, which corresponds to a NIC on the hypervisor. The Network carries several types of traffic.

You may also add other traffic types onto the physical Network.", "message.shared.network.offering.warning": "Domain admins and regular Users can only create shared Networks from Network offering with the setting specifyvlan=false. Please contact an administrator to create a Network offering if this list is empty.", +"message.shared.network.unsupported.for.nsx": "Shared networks aren't supported for NSX enabled zones", "message.shutdown.triggered": "A shutdown has been triggered. CloudStack will not accept new jobs", "message.snapshot.additional.zones": "Snapshots will always be created in its native zone - %x, here you can select additional zone(s) where it will be copied to at creation time", "message.sourcenatip.change.warning": "WARNING: Changing the sourcenat IP address of the network will cause connectivity downtime for the Instances with NICs in the Network.", 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/components/view/ResourceView.vue b/ui/src/components/view/ResourceView.vue index 367c58961bc..2c1764da143 100644 --- a/ui/src/components/view/ResourceView.vue +++ b/ui/src/components/view/ResourceView.vue @@ -114,15 +114,7 @@ export default { handler (newItem, oldItem) { if (newItem.id === oldItem.id) return - if (this.resource.associatednetworkid) { - api('listNetworks', { id: this.resource.associatednetworkid, listall: true }).then(response => { - if (response && response.listnetworksresponse && response.listnetworksresponse.network) { - this.networkService = response.listnetworksresponse.network[0] - } else { - this.networkService = {} - } - }) - } + this.fetchData() } }, '$route.fullPath': function () { @@ -140,8 +132,20 @@ export default { window.addEventListener('popstate', function () { self.setActiveTab() }) + this.fetchData() }, methods: { + fetchData () { + if (this.resource.associatednetworkid) { + api('listNetworks', { id: this.resource.associatednetworkid, listall: true }).then(response => { + if (response && response.listnetworksresponse && response.listnetworksresponse.network) { + this.networkService = response.listnetworksresponse.network[0] + } else { + this.networkService = {} + } + }) + } + }, onTabChange (key) { this.activeTab = key const query = Object.assign({}, this.$route.query) diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js index 65daaf53ae0..75ba6f5361b 100644 --- a/ui/src/config/section/offering.js +++ b/ui/src/config/section/offering.js @@ -269,7 +269,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: [ { @@ -362,7 +362,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/infra/network/ServiceProvidersTab.vue b/ui/src/views/infra/network/ServiceProvidersTab.vue index 4985389ba60..b01f543478b 100644 --- a/ui/src/views/infra/network/ServiceProvidersTab.vue +++ b/ui/src/views/infra/network/ServiceProvidersTab.vue @@ -1056,6 +1056,50 @@ export default { columns: ['name', 'tungstenproviderhostname', 'tungstenproviderport', 'tungstengateway', 'tungstenprovidervrouterport', 'tungstenproviderintrospectport'] } ] + }, + { + title: 'Nsx', + details: ['name', 'state', 'id', 'physicalnetworkid', 'servicelist'], + actions: [ + { + api: 'updateNetworkServiceProvider', + icon: 'stop-outlined', + listView: true, + label: 'label.disable.provider', + confirm: 'message.confirm.disable.provider', + // show: (record) => { return record && record.id && record.state === 'Enabled' }, + mapping: { + state: { + value: (record) => { return 'Disabled' } + } + } + }, + { + api: 'updateNetworkServiceProvider', + icon: 'play-circle-outlined', + listView: true, + label: 'label.enable.provider', + confirm: 'message.confirm.enable.provider', + // show: (record) => { return record && record.id && record.state === 'Disabled' }, + mapping: { + state: { + value: (record) => { return 'Enabled' } + } + } + } + ], + lists: [ + { + title: 'label.nsx.controller', + api: 'listNsxControllers', + mapping: { + zoneid: { + value: (record) => { return record.zoneid } + } + }, + columns: ['name', 'hostname', 'port', 'tier0gateway', 'edgecluster', 'transportzone'] + } + ] } ] } @@ -1096,6 +1140,7 @@ export default { this.fetchLoading = true api('listNetworkServiceProviders', { physicalnetworkid: this.resource.id, name: name }).then(json => { const sps = json.listnetworkserviceprovidersresponse.networkserviceprovider || [] + console.log(sps) if (sps.length > 0) { for (const sp of sps) { this.nsps[sp.name] = sp diff --git a/ui/src/views/infra/zone/IpAddressRangeForm.vue b/ui/src/views/infra/zone/IpAddressRangeForm.vue index 22332952622..c39534d7b93 100644 --- a/ui/src/views/infra/zone/IpAddressRangeForm.vue +++ b/ui/src/views/infra/zone/IpAddressRangeForm.vue @@ -31,9 +31,15 @@ :pagination="false" style="margin-bottom: 24px; width: 100%" >