Merge branch 'main' into nsx-integration
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 3a61617..573363c 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 @@
Map<NetworkOffering.Detail, String> details;
boolean dpdkEnabled;
Integer mtu;
+ Long networkId;
+
+ String networkSegmentName;
public NicTO() {
super();
@@ -127,4 +130,20 @@
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 db6cba7..b4f4619 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 @@
Map<String, String> guestOsDetails = new HashMap<String, String>();
Map<String, String> extraConfig = new HashMap<>();
+ Map<Long, String> 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 @@
return extraConfig;
}
+ public Map<Long, String> getNetworkIdToNetworkNameMap() {
+ return networkIdToNetworkNameMap;
+ }
+
+ public void setNetworkIdToNetworkNameMap(Map<Long, String> 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 e445e50..e160227 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 @@
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 cf2e2f8..ae1af45 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 @@
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 458169c..3b13ef7 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 @@
//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 @@
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 82d229d..51799e2 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 @@
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.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 @@
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 @@
PublicIpQuarantine updatePublicIpAddressInQuarantine(UpdateQuarantinedIpCmd cmd);
void removePublicIpAddressFromQuarantine(RemoveQuarantinedIpCmd cmd);
+
+ InternalLoadBalancerElementService getInternalLoadBalancerElementByType(VirtualRouterProvider.Type type);
+ InternalLoadBalancerElementService getInternalLoadBalancerElementByNetworkServiceProviderId(long networkProviderId);
+ InternalLoadBalancerElementService getInternalLoadBalancerElementById(long providerId);
+ List<InternalLoadBalancerElementService> getInternalLoadBalancerElements();
}
diff --git a/api/src/main/java/com/cloud/network/Networks.java b/api/src/main/java/com/cloud/network/Networks.java
index aeed5d4..dfa0ddb 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 @@
},
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 aca526b..98410ca 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 @@
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 8c3243c..852a650 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 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 @@
*/
boolean applyNetworkACLs(Network config, List<? extends NetworkACLItem> rules) throws ResourceUnavailableException;
+ boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> 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 52f6540..cbadbb1 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 @@
* 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.
- *
+ * <p>
* 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 0000000..19cb3b4
--- /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 0000000..79ad954
--- /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 b4df8e3..3aab57d 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 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 @@
*/
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 5cccd6c..1ce3cf8 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 @@
VpcOffering createVpcOffering(String name, String displayText, List<String> supportedServices,
Map<String, List<String>> serviceProviders,
Map serviceCapabilitystList, NetUtils.InternetProtocol internetProtocol,
- Long serviceOfferingId, List<Long> domainIds, List<Long> zoneIds, VpcOffering.State state);
+ Long serviceOfferingId, Boolean forNsx, String mode,
+ List<Long> domainIds, List<Long> zoneIds, VpcOffering.State state);
Pair<List<? extends VpcOffering>,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 207880e..cf01fbf 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 @@
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 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 @@
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 db0c5ce..60309da 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -302,6 +302,8 @@
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";
@@ -696,6 +698,12 @@
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";
@@ -816,6 +824,9 @@
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";
@@ -825,6 +836,11 @@
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";
@@ -949,6 +965,7 @@
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";
@@ -1067,14 +1084,13 @@
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 323fd4e..b206cd0 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.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 @@
@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 18dfc87..c94d326 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 @@
responseHasSensitiveInfo = false)
public class ConfigureInternalLoadBalancerElementCmd extends BaseAsyncCmd {
- @Inject
- private List<InternalLoadBalancerElementService> _service;
-
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@@ -98,7 +90,8 @@
@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 971f097..924287b 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 @@
responseHasSensitiveInfo = false)
public class CreateInternalLoadBalancerElementCmd extends BaseAsyncCreateCmd {
- @Inject
- private List<InternalLoadBalancerElementService> _service;
-
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@@ -83,7 +75,8 @@
@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 @@
@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 6c2fade..b17cc22 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 @@
responseHasSensitiveInfo = false)
public class ListInternalLoadBalancerElementsCmd extends BaseListCmd {
- @Inject
- private InternalLoadBalancerElementService _service;
-
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@@ -86,12 +81,21 @@
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException {
- List<? extends VirtualRouterProvider> providers = _service.searchForInternalLoadBalancerElements(getId(), getNspId(), getEnabled());
+ List<InternalLoadBalancerElementService> 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<InternalLoadBalancerElementResponse> response = new ListResponse<InternalLoadBalancerElementResponse>();
List<InternalLoadBalancerElementResponse> providerResponses = new ArrayList<InternalLoadBalancerElementResponse>();
- for (VirtualRouterProvider provider : providers) {
- InternalLoadBalancerElementResponse providerResponse = _responseGenerator.createInternalLbElementResponse(provider);
- providerResponses.add(providerResponse);
+ for (InternalLoadBalancerElementService service : services) {
+ List<? extends VirtualRouterProvider> 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 f2b1a18..9117bcf 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.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.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 @@
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 List<String> getSupportedServices() {
- return supportedServices == null ? new ArrayList<String>() : supportedServices;
+ if (!isForNsx()) {
+ return supportedServices == null ? new ArrayList<String>() : supportedServices;
+ } else {
+ List<String> 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 @@
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 Map<String, List<String>> getServiceProviders() {
- Map<String, List<String>> serviceProviderMap = null;
- if (serviceProviderList != null && !serviceProviderList.isEmpty()) {
- serviceProviderMap = new HashMap<String, List<String>>();
+ Map<String, List<String>> serviceProviderMap = new HashMap<>();
+ if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isForNsx()) {
Collection servicesCollection = serviceProviderList.values();
Iterator iter = servicesCollection.iterator();
while (iter.hasNext()) {
@@ -278,11 +351,37 @@
providerList.add(provider);
serviceProviderMap.put(service, providerList);
}
+ } else if (Boolean.TRUE.equals(forNsx)) {
+ getServiceProviderMapForNsx(serviceProviderMap);
}
-
return serviceProviderMap;
}
+ private void getServiceProviderMapForNsx(Map<String, List<String>> serviceProviderMap) {
+ String routerProvider = Boolean.TRUE.equals(getForVpc()) ? VirtualRouterProvider.Type.VPCVirtualRouter.name() :
+ VirtualRouterProvider.Type.VirtualRouter.name();
+ List<String> unsupportedServices = new ArrayList<>(List.of("Vpn", "SecurityGroup", "Connectivity",
+ "Gateway", "BaremetalPxeService"));
+ List<String> routerSupported = List.of("Dhcp", "Dns", "UserData");
+ List<String> 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<Capability, String> getServiceCapabilities(Service service) {
Map<Capability, String> 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 cceadea..c0ba99a 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.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 @@
@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 @@
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 382c081..dd5c815 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.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.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 @@
@Parameter(name = ApiConstants.SUPPORTED_SERVICES,
type = CommandType.LIST,
- required = true,
collectionType = CommandType.STRING,
description = "services supported by the vpc offering")
private List<String> supportedServices;
@@ -99,6 +112,24 @@
since = "4.13")
private List<Long> 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 List<String> 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<String, List<String>> getServiceProviders() {
- Map<String, List<String>> serviceProviderMap = null;
- if (serviceProviderList != null && !serviceProviderList.isEmpty()) {
- serviceProviderMap = new HashMap<String, List<String>>();
+ Map<String, List<String>> serviceProviderMap = new HashMap<>();
+ if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isForNsx()) {
Collection<? extends Map<String, String>> servicesCollection = serviceProviderList.values();
Iterator<? extends Map<String, String>> iter = servicesCollection.iterator();
while (iter.hasNext()) {
@@ -132,7 +191,7 @@
if (logger.isTraceEnabled()) {
logger.trace("service provider entry specified: " + obj);
}
- HashMap<String, String> services = (HashMap<String, String>)obj;
+ HashMap<String, String> services = (HashMap<String, String>) obj;
String service = services.get("service");
String provider = services.get("provider");
List<String> providerList = null;
@@ -144,11 +203,31 @@
providerList.add(provider);
serviceProviderMap.put(service, providerList);
}
+ } else if (Boolean.TRUE.equals(forNsx)) {
+ getServiceProviderMapForNsx(serviceProviderMap);
}
return serviceProviderMap;
}
+ private void getServiceProviderMapForNsx(Map<String, List<String>> serviceProviderMap) {
+ List<String> unsupportedServices = List.of("Vpn", "BaremetalPxeService", "SecurityGroup", "Connectivity",
+ "Gateway", "Firewall");
+ List<String> routerSupported = List.of("Dhcp", "Dns", "UserData");
+ List<String> 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<String, List<String>> 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 5c1c611..5760ca3 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 @@
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 @@
@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 @@
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 e2bf6ef..8a9bf77 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 @@
@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 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 b92725d..b73163a 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 @@
@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 @@
@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 @@
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 @@
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 a22e2eb..aac6dd3c 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 @@
@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 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 6881969..ce00827 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 @@
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 @@
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 4e8e665..a898cd9 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 @@
@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<ResourceTagResponse>();
}
@@ -368,4 +372,8 @@
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 76706a4..1fff54f 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 @@
* @return
*/
List<? extends VirtualRouterProvider> 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 8b95456..ef10ebf 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.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 16b716d..290a285 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 @@
IllegalAccessException {
CreateVPCOfferingCmd cmd = new CreateVPCOfferingCmd();
ApiCmdTestUtil.set(cmd, ApiConstants.SERVICE_PROVIDER_LIST, new HashMap<String, Map<String, String>>());
- 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 9139909..9ff3f2a 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -298,6 +298,11 @@
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-plugin-network-nsx</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-network-elb</artifactId>
<version>${project.version}</version>
</dependency>
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 a36d124..49775fe 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 @@
<bean id="clusterDrsAlgorithmRegistry"
class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry">
</bean>
+
+ <bean id="internalLoadBalancerElementServiceRegistry" class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry">
+ <property name="preRegistered">
+ <list>
+ <ref bean="InternalLbVm" />
+ </list>
+ </property>
+ </bean>
</beans>
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 8dbaf61..2240d1f 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 @@
<property name="typeClass"
value="org.apache.cloudstack.region.gslb.GslbServiceProvider" />
</bean>
+
+ <bean class="org.apache.cloudstack.spring.lifecycle.registry.RegistryLifecycle">
+ <property name="registry" ref="internalLoadBalancerElementServiceRegistry" />
+ <property name="typeClass" value="org.apache.cloudstack.network.element.InternalLoadBalancerElementService" />
+ </bean>
</beans>
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 2005b70..1105921 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 @@
static final ConfigKey<Boolean> 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<Boolean> NSX_ENABLED = new ConfigKey<>(Boolean.class, "nsx.plugin.enable", "Advanced", "false",
+ "Indicates whether to enable the NSX plugin", false, ConfigKey.Scope.Zone, null);
+
List<? extends Network> 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 5343fb6..bbddd8f 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 @@
static final String VM_USERDATA_MAX_LENGTH_STRING = "vm.userdata.max.length";
static final ConfigKey<Integer> 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<Boolean> 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 @@
// * @param volatileVm
// * @param hostTag
// * @param networkRate
-// * TODO
// * @param id
// * @param useVirtualNetwork
// * @param deploymentPlanner
@@ -167,11 +169,9 @@
* @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 @@
*
* @param userId
* @param vlanDbId
- * @param caller TODO
+ * @param caller
* @return success/failure
*/
boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId, Account caller);
@@ -197,30 +197,25 @@
/**
* 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 @@
Integer networkRate, Map<Service, Set<Provider>> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId,
boolean conserveMode, Map<Service, Map<Capability, String>> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent,
Map<NetworkOffering.Detail, String> details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc,
- Boolean forTungsten, List<Long> domainIds, List<Long> zoneIds, boolean enableOffering, final NetUtils.InternetProtocol internetProtocol);
+ Boolean forTungsten, boolean forNsx, String mode, List<Long> domainIds, List<Long> 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 d1153a2..d69a72a 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 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 4200ea8..de69b89 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 @@
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 @@
boolean revokeACLItemsForPrivateGw(PrivateGateway gateway) throws ResourceUnavailableException;
boolean applyACLToPrivateGw(PrivateGateway gateway) throws ResourceUnavailableException;
+
+ boolean reorderAclRules(VpcVO vpc, List<? extends Network> networks, List<? extends NetworkACLItem> 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 5e7be6d..5a2a899 100755
--- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -35,6 +35,7 @@
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;
@@ -47,6 +48,11 @@
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;
@@ -383,6 +389,12 @@
private DomainRouterJoinDao domainRouterJoinDao;
@Inject
private AnnotationDao annotationDao;
+ @Inject
+ private AccountDao accountDao;
+ @Inject
+ private VpcDao vpcDao;
+ @Inject
+ private DomainDao domainDao;
VmWorkJobHandlerProxy _jobHandlerProxy = new VmWorkJobHandlerProxy(this);
@@ -597,11 +609,18 @@
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;
}
@@ -672,28 +691,31 @@
// send hypervisor-dependent commands before removing
final List<Command> 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<Command> finalizeExpungeCommands, List<Command> 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 @@
checkAndSetEnterSetupMode(vmTO, params);
handlePath(vmTO.getDisks(), vm.getHypervisorType());
+ setVmNetworkDetails(vm, vmTO);
+
Commands cmds = new Commands(Command.OnError.Stop);
final Map<String, String> sshAccessDetails = _networkMgr.getSystemVMAccessDetails(vm);
@@ -1460,6 +1484,55 @@
}
}
+ public void setVmNetworkDetails(VMInstanceVO vm, VirtualMachineTO vmTO) {
+ Map<Long, String> networkToNetworkNameMap = new HashMap<>();
+ if (VirtualMachine.Type.User.equals(vm.getType())) {
+ List<UserVmJoinVO> 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<DomainRouterJoinVO> 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<Long, String> 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).
@@ -2731,6 +2804,7 @@
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 6d858a5..50b4f60 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 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.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.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.googlecode.ipv6.IPv6Address;
+import org.jetbrains.annotations.NotNull;
/**
* NetworkManagerImpl implements NetworkManager.
@@ -337,8 +342,12 @@
Ipv6Service ipv6Service;
@Inject
RouterNetworkDao routerNetworkDao;
+ @Inject
+ private VlanDetailsDao vlanDetailsDao;
List<NetworkGuru> networkGurus;
+ @Inject
+ private NsxProviderDao nsxProviderDao;
@Override
public List<NetworkGuru> getNetworkGurus() {
@@ -500,6 +509,7 @@
defaultTungstenSharedSGEnabledNetworkOfferingProviders.put(Service.UserData, tungstenProvider);
defaultTungstenSharedSGEnabledNetworkOfferingProviders.put(Service.SecurityGroup, tungstenProvider);
+
final Map<Network.Service, Set<Network.Provider>> defaultIsolatedSourceNatEnabledNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
defaultProviders.clear();
defaultProviders.add(Network.Provider.VirtualRouter);
@@ -536,27 +546,27 @@
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<Network.Service, Set<Network.Provider>>(), 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 @@
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 @@
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 @@
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 @@
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 @@
.getBroadcastDomainType() == BroadcastDomainType.Vlan || predefined.getBroadcastDomainType() == BroadcastDomainType.Lswitch || predefined
.getBroadcastDomainType() == BroadcastDomainType.Vxlan)) {
final List<NetworkVO> 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 @@
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 @@
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 @@
}
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 @@
}
}
+ @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<? extends Network> existingConfiguration(final NetworkOffering offering, List<NetworkVO> 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<? extends Network, List<? extends NicProfile>> networks, final Map<String, Map<Integer, String>> extraDhcpOptions) throws InsufficientCapacityException,
@@ -1025,6 +1052,12 @@
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 @@
return new Pair<NicProfile, Integer>(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<IPAddressVO> 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<NetworkVO, VpcVO> networks, Network network, NicVO vo) {
if (TrafficType.Public == network.getTrafficType()) {
if (networks == null) {
@@ -2811,10 +2874,9 @@
}
// 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;
@@ -3841,7 +3903,8 @@
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 {
@@ -4721,6 +4784,6 @@
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 97bd1f5..e6587a0 100644
--- a/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java
+++ b/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java
@@ -38,6 +38,18 @@
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 com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterDetailsVO;
import com.cloud.dc.Pod;
@@ -178,6 +190,16 @@
@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;
@@ -933,6 +955,48 @@
}
@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<UserVmJoinVO> 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();
ReflectionTestUtils.setField(vmInstance, "id", 1L);
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 fde9323..581f789 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 @@
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 0000000..0fc7753
--- /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, Long> {
+ NsxProviderVO findByZoneId(long zoneId);
+
+ NsxProviderVO findByUuid(String uuid);
+
+ List<NsxProviderVO> 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 0000000..cf7b5d4
--- /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<NsxProviderVO, Long>
+ implements NsxProviderDao {
+
+ final SearchBuilder<NsxProviderVO> 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<NsxProviderVO> sc = allFieldsSearch.create();
+ sc.setParameters("zone_id", zoneId);
+ return findOneBy(sc);
+ }
+
+ @Override
+ public List<NsxProviderVO> 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 0000000..f08e08b
--- /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 aa26f16..350dda3 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 @@
@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 @@
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 ae5e6fb..b2fabf2 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 @@
@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;
@@ -196,6 +202,24 @@
}
@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 68f5732..23c26ea 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 @@
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 59d2417..3eee1d4 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 @@
return findOneIncludingRemovedBy(sc);
}
- @Override
- public NicVO findByNetworkIdAndType(long networkId, VirtualMachine.Type vmType) {
+ private NicVO findByNetworkIdAndTypeInternal(long networkId, VirtualMachine.Type vmType, boolean includingRemoved) {
SearchCriteria<NicVO> 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 5d95838..9fa01c2 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 @@
<bean id="nicIpAliasDaoImpl" class="com.cloud.vm.dao.NicIpAliasDaoImpl" />
<bean id="objectInDataStoreDaoImpl" class="org.apache.cloudstack.storage.db.ObjectInDataStoreDaoImpl" />
<bean id="ovsProviderDaoImpl" class="com.cloud.network.dao.OvsProviderDaoImpl" />
+ <bean id="nsxControllerDaoImpl" class="com.cloud.network.dao.NsxProviderDaoImpl" />
<bean id="tungstenControllerDaoImpl" class="com.cloud.network.dao.TungstenProviderDaoImpl"/>
<bean id="physicalNetworkDaoImpl" class="com.cloud.network.dao.PhysicalNetworkDaoImpl" />
<bean id="physicalNetworkIsolationMethodDaoImpl" class="com.cloud.network.dao.PhysicalNetworkIsolationMethodDaoImpl" />
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql b/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql
index a6f45c2..26a7d54 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql
@@ -103,6 +103,43 @@
ALTER TABLE `cloud`.`kubernetes_cluster` ADD COLUMN `cluster_type` varchar(64) DEFAULT 'CloudManaged' COMMENT 'type of cluster';
ALTER TABLE `cloud`.`kubernetes_cluster` MODIFY COLUMN `kubernetes_version_id` bigint unsigned NULL COMMENT 'the ID of the Kubernetes version of this Kubernetes cluster';
+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;
+
+
+-- Idempotent ADD COLUMN
+DROP PROCEDURE IF EXISTS `cloud`.`IDEMPOTENT_ADD_COLUMN`;
+CREATE PROCEDURE `cloud`.`IDEMPOTENT_ADD_COLUMN` (
+ IN in_table_name VARCHAR(200)
+, IN in_column_name VARCHAR(200)
+, IN in_column_definition VARCHAR(1000)
+)
+BEGIN
+ DECLARE CONTINUE HANDLER FOR 1060 BEGIN END; SET @ddl = CONCAT('ALTER TABLE ', in_table_name); SET @ddl = CONCAT(@ddl, ' ', 'ADD COLUMN') ; SET @ddl = CONCAT(@ddl, ' ', in_column_name); SET @ddl = CONCAT(@ddl, ' ', in_column_definition); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END;
+
+-- 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"');
+
-- Add indexes for data store browser
ALTER TABLE `cloud`.`template_spool_ref` ADD INDEX `i_template_spool_ref__install_path`(`install_path`);
ALTER TABLE `cloud`.`volumes` ADD INDEX `i_volumes__path`(`path`);
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 8ba291e..bae73de 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 @@
`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
new file mode 100644
index 0000000..556aeef
--- /dev/null
+++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql
@@ -0,0 +1,61 @@
+-- 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.
+
+-- VIEW `cloud`.`vpc_offering_view`;
+
+DROP VIEW IF EXISTS `cloud`.`vpc_offering_view`;
+
+CREATE VIEW `cloud`.`vpc_offering_view` AS
+SELECT
+ `vpc_offerings`.`id` AS `id`,
+ `vpc_offerings`.`uuid` AS `uuid`,
+ `vpc_offerings`.`name` AS `name`,
+ `vpc_offerings`.`unique_name` AS `unique_name`,
+ `vpc_offerings`.`display_text` AS `display_text`,
+ `vpc_offerings`.`state` AS `state`,
+ `vpc_offerings`.`default` AS `default`,
+ `vpc_offerings`.`for_nsx` AS `for_nsx`,
+ `vpc_offerings`.`nsx_mode` AS `nsx_mode`,
+ `vpc_offerings`.`created` AS `created`,
+ `vpc_offerings`.`removed` AS `removed`,
+ `vpc_offerings`.`service_offering_id` AS `service_offering_id`,
+ `vpc_offerings`.`supports_distributed_router` AS `supports_distributed_router`,
+ `vpc_offerings`.`supports_region_level_vpc` AS `supports_region_level_vpc`,
+ `vpc_offerings`.`redundant_router_service` AS `redundant_router_service`,
+ `vpc_offerings`.`sort_key` AS `sort_key`,
+ GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id,
+ GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid,
+ GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name,
+ GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path,
+ GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id,
+ GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid,
+ GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name,
+ `offering_details`.value AS internet_protocol
+FROM
+ `cloud`.`vpc_offerings`
+ LEFT JOIN
+ `cloud`.`vpc_offering_details` AS `domain_details` ON `domain_details`.`offering_id` = `vpc_offerings`.`id` AND `domain_details`.`name`='domainid'
+ LEFT JOIN
+ `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`)
+ LEFT JOIN
+ `cloud`.`vpc_offering_details` AS `zone_details` ON `zone_details`.`offering_id` = `vpc_offerings`.`id` AND `zone_details`.`name`='zoneid'
+ LEFT JOIN
+ `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`)
+ LEFT JOIN
+ `cloud`.`vpc_offering_details` AS `offering_details` ON `offering_details`.`offering_id` = `vpc_offerings`.`id` AND `offering_details`.`name`='internetprotocol'
+GROUP BY
+ `vpc_offerings`.`id`;
diff --git a/plugins/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 2c570f6..826c613 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 @@
}
}
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 bafe52b..a9ff31d 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 @@
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 @@
deviceNumber++;
VirtualDevice nic;
- Pair<ManagedObjectReference, String> networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false, vmType);
+ Pair<ManagedObjectReference, String> 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 @@
return new ReplugNicAnswer(cmd, false, "Nic to replug not found");
}
- Pair<ManagedObjectReference, String> networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false, cmd.getVMType());
+ Pair<ManagedObjectReference, String> 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 @@
} 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 @@
}
boolean configureVServiceInNexus = (nicTo.getType() == TrafficType.Guest) && (vmSpec.getDetails().containsKey("ConfigureVServiceInNexus"));
VirtualMachine.Type vmType = cmd.getVirtualMachine().getType();
- Pair<ManagedObjectReference, String> networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus, vmType);
+ Pair<ManagedObjectReference, String> 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 @@
return defaultVlan;
}
- private Pair<ManagedObjectReference, String> prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus, VirtualMachine.Type vmType)
+ private Pair<ManagedObjectReference, String> prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus, String networkName, VirtualMachine.Type vmType)
throws Exception {
Ternary<String, String, String> switchDetails = getTargetSwitch(nicTo);
@@ -4011,7 +4012,7 @@
}
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 @@
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<Pair<String, Long>> secStoreUrlAndIdList = mgr.getSecondaryStorageStoresUrlAndIdList(Long.parseLong(_dcId));
@@ -5670,7 +5672,7 @@
}
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) {
@@ -7316,7 +7318,8 @@
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 0ef916a..60bd81c 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,12 +25,15 @@
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) {
@@ -37,6 +41,15 @@
}
@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 fb95a35..834d6d3 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 @@
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<KubernetesCluster.State, KubernetesCluster.Event, KubernetesCluster> _stateMachine = KubernetesCluster.State.getStateMachine();
@@ -1893,26 +1898,54 @@
@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<Network.Service, Network.Provider> defaultKubernetesServiceNetworkOfferingProviders = new HashMap<Service, Network.Provider>();
- 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 @@
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 c7451ad..e8bc8e2 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 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 @@
protected VolumeApiService volumeService;
@Inject
protected VolumeDao volumeDao;
+ @Inject
+ protected NetworkOfferingDao networkOfferingDao;
protected String kubernetesClusterNodeNamePrefix;
@@ -738,12 +742,24 @@
protected void setupKubernetesClusterVpcTierRules(IpAddress publicIp, Network network, List<Long> 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 688a611..45c0b79 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 @@
public interface KubernetesClusterVmMapDao extends GenericDao<KubernetesClusterVmMapVO, Long> {
public List<KubernetesClusterVmMapVO> listByClusterId(long clusterId);
+
+ public KubernetesClusterVmMapVO getClusterMapFromVmId(long vmId);
public List<KubernetesClusterVmMapVO> listByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
int removeByClusterIdAndVmIdsIn(long clusterId, List<Long> 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 b9f2ec9..0d90a4c 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 @@
public class KubernetesClusterVmMapDaoImpl extends GenericDaoBase<KubernetesClusterVmMapVO, Long> implements KubernetesClusterVmMapDao {
private final SearchBuilder<KubernetesClusterVmMapVO> clusterIdSearch;
+ private final SearchBuilder<KubernetesClusterVmMapVO> 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
@@ -48,6 +53,13 @@
}
@Override
+ public KubernetesClusterVmMapVO getClusterMapFromVmId(long vmId) {
+ SearchCriteria<KubernetesClusterVmMapVO> sc = vmIdSearch.create();
+ sc.setParameters("vmId", vmId);
+ return findOneBy(sc);
+ }
+
+ @Override
public List<KubernetesClusterVmMapVO> listByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds) {
SearchCriteria<KubernetesClusterVmMapVO> sc = clusterIdSearch.create();
sc.setParameters("clusterId", clusterId);
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 95513df..5fc9480 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
@@ -699,6 +699,11 @@
}
@Override
+ public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) {
+ return true;
+ }
+
+ @Override
public boolean applyFWRules(Network network,
List<? extends FirewallRule> rules)
throws ResourceUnavailableException {
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 e23395b..f9c11e5 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 @@
}
@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 @@
}
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 1e13aaa..8d2125d 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 @@
}
@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 @@
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 9fbb96f..3f5a047 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 @@
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 @@
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 @@
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 0bbc3e6..0a9b4a7 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.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<Service, Map<Capability, String>> capabilities = setCapabilities();
private static InternalLoadBalancerElement internalLbElement = null;
@@ -112,14 +114,7 @@
@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) {
@@ -518,6 +513,11 @@
}
@Override
+ public Type getProviderType() {
+ return Type.InternalLbVm;
+ }
+
+ @Override
public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Service> services) throws ResourceUnavailableException {
//do nothing here; this element just has to extend the ip deployer
//as the LB service implements IPDeployerRequester
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 6fb4c3e..345cdc1 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 @@
}
@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());
@@ -137,6 +137,11 @@
}
@Override
+ public void setup(Network network, long networkId) {
+ // do nothing
+ }
+
+ @Override
public Network implement(Network network, NetworkOffering offering, DeployDestination destination, ReservationContext context)
throws InsufficientVirtualNetworkCapacityException {
logger.debug("Implement network: " + network.getName() + ", traffic type: " + network.getTrafficType());
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 1261a23..791e245 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 @@
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 @@
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 @@
}
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 b73ed7f..85125bf 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
@@ -183,6 +183,11 @@
}
@Override
+ public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) {
+ return true;
+ }
+
+ @Override
public boolean applyACLItemsToPrivateGw(PrivateGateway privateGateway,
List<? extends NetworkACLItem> rules)
throws ResourceUnavailableException {
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 0959eab..dc453f7 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 @@
}
@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 61dcf91..daf2420 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 @@
}
@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 @@
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 5925fd9..c6ad8a6 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 @@
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 @@
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 @@
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 @@
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 0000000..bed5731
--- /dev/null
+++ b/plugins/network-elements/nsx/pom.xml
@@ -0,0 +1,59 @@
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>cloud-plugin-network-nsx</artifactId>
+ <name>Apache CloudStack Plugin - NSX Network</name>
+
+ <parent>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloudstack-plugins</artifactId>
+ <version>4.20.0.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <dependencies>
+ <dependency>
+ <groupId>com.vmware</groupId>
+ <artifactId>nsx-java-sdk</artifactId>
+ <version>4.1.0.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.vmware</groupId>
+ <artifactId>nsx-gpm-java-sdk</artifactId>
+ <version>4.1.0.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.vmware</groupId>
+ <artifactId>nsx-policy-java-sdk</artifactId>
+ <version>4.1.0.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.vmware.vapi</groupId>
+ <artifactId>vapi-authentication</artifactId>
+ <version>2.40.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.vmware.vapi</groupId>
+ <artifactId>vapi-runtime</artifactId>
+ <version>2.40.0</version>
+ </dependency>
+ </dependencies>
+</project>
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 0000000..0820465
--- /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 0000000..8a5ac35
--- /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 0000000..6ef75b2
--- /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<String> addresses;
+
+ public CreateNsxDhcpRelayConfigCommand(long domainId, long accountId, long zoneId,
+ Long vpcId, String vpcName, long networkId, String networkName,
+ List<String> 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<String> 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 0000000..f598a20
--- /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<NsxNetworkRule> rules;
+
+ public CreateNsxDistributedFirewallRulesCommand(long domainId, long accountId, long zoneId,
+ Long vpcId, long networkId,
+ List<NsxNetworkRule> 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<NsxNetworkRule> 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 0000000..92acc83
--- /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<NsxLoadBalancerMember> memberList;
+
+ private final long lbId;
+ public CreateNsxLoadBalancerRuleCommand(long domainId, long accountId, long zoneId, Long networkResourceId,
+ String networkResourceName, boolean isResourceVpc,
+ List<NsxLoadBalancerMember> 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<NsxLoadBalancerMember> 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 0000000..d722955
--- /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 0000000..b4b86bd
--- /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 0000000..08c1342
--- /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 0000000..90e4b3a
--- /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 0000000..c14be74
--- /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 0000000..ad88f23
--- /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<NsxNetworkRule> 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 0000000..72aa61f
--- /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<NsxLoadBalancerMember> memberList;
+
+ public DeleteNsxLoadBalancerRuleCommand(long domainId, long accountId, long zoneId, Long networkResourceId,
+ String networkResourceName, boolean isResourceVpc,
+ List<NsxLoadBalancerMember> 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<NsxLoadBalancerMember> 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 0000000..c5231b1
--- /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 0000000..882b553
--- /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 0000000..d05acc1
--- /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 0000000..7c5e3a1
--- /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 0000000..4cad50d
--- /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 0000000..22deacc
--- /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 0000000..8e36599
--- /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 0000000..5a3e558
--- /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 0000000..94b5855
--- /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<BaseResponse> baseResponseList = nsxProviderService.listNsxProviders(zoneId);
+ List<BaseResponse> pagingList = StringUtils.applyPagination(baseResponseList, this.getStartIndex(), this.getPageSizeVal());
+ ListResponse<BaseResponse> 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 0000000..910c5e1
--- /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 0000000..00960dd
--- /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 0000000..c11141d
--- /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<NsxLoadBalancerMember> memberList;
+ private NsxRuleAction aclAction;
+ private List<String> sourceCidrList;
+ private List<String> 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<NsxLoadBalancerMember> getMemberList() {
+ return memberList;
+ }
+
+ public void setMemberList(List<NsxLoadBalancerMember> 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<String> getSourceCidrList() {
+ return sourceCidrList;
+ }
+
+ public void setSourceCidrList(List<String> sourceCidrList) {
+ this.sourceCidrList = sourceCidrList;
+ }
+
+ public List<String> getDestinationCidrList() {
+ return destinationCidrList;
+ }
+
+ public void setDestinationCidrList(List<String> 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<NsxLoadBalancerMember> memberList;
+ private NsxRuleAction aclAction;
+ private List<String> sourceCidrList;
+ private List<String> 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<NsxLoadBalancerMember> 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<String> sourceCidrList) {
+ this.sourceCidrList = sourceCidrList;
+ return this;
+ }
+
+ public Builder setDestinationCidrList(List<String> 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 0000000..bb41124
--- /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 0000000..453a260
--- /dev/null
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java
@@ -0,0 +1,483 @@
+// 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<String, Object> params) {
+ // Do nothing
+ }
+
+ @Override
+ public Map<String, Object> 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<String, Object> 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<String> 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<TransportZone> 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);
+
+ 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<NsxNetworkRule> 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<NsxNetworkRule> 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 0000000..fe02948
--- /dev/null
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java
@@ -0,0 +1,1038 @@
+// 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<Class<? extends Service>, 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";
+
+ 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<String> 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<com.vmware.nsx_policy.model.LocaleServices> 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<com.vmware.nsx_policy.model.LocaleServices> 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<String> getRouterAdvertisementTypeList(boolean sourceNatEnabled) {
+ List<String> 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<String> 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);
+ String natId = "USER";
+ PolicyNatRuleListResult result = natRulesService.list(tier1Id, natId, null, false, null, null, null, null);
+ List<PolicyNatRule> 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, natId, 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<TransportZone> 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 delete NSX Port-forward rule %s for network: %s, due to %s",
+ ruleName, networkName, ae.getErrorMessage());
+ logger.error(msg);
+ throw new CloudRuntimeException(msg);
+ }
+ }
+
+ List<LBPoolMember> getLbPoolMembers(List<NsxLoadBalancerMember> memberList, String tier1GatewayName) {
+ List<LBPoolMember> 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<NsxLoadBalancerMember> memberList, String tier1GatewayName, String lbServerPoolName,
+ String algorithm, String privatePort, String protocol) {
+ try {
+ String activeMonitorPath = getLbActiveMonitorPath(lbServerPoolName, privatePort, protocol);
+ List<LBPoolMember> 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))
+ .build();
+ lbActiveMonitor.patch(lbMonitorProfileId, lbUdpMonitorProfile);
+ }
+
+ LBMonitorProfileListResult listResult = listLBActiveMonitors(lbActiveMonitor);
+ Optional<Structure> 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<NsxLoadBalancerMember> 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);
+ 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);
+ }
+ }
+
+ 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<String> 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<Structure> 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<com.vmware.nsx_policy.model.Service> services = serviceList.getResults();
+ List<String> 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<Structure> 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<String> 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<NsxNetworkRule> 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<Rule> 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<NsxNetworkRule> 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<Rule> getRulesForDistributedFirewall(String segmentName, List<NsxNetworkRule> nsxRules) {
+ List<Rule> 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<String> getServicesListForDistributedFirewallRule(NsxNetworkRule rule, String segmentName) {
+ List<String> 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<String> getGroupsForTraffic(NsxNetworkRule rule,
+ String segmentName, boolean source) {
+ List<String> segmentGroup = List.of(String.format("%s/%s", GROUPS_PATH_PREFIX, segmentName));
+ List<String> sourceCidrList = rule.getSourceCidrList();
+ List<String> destCidrList = rule.getDestinationCidrList();
+ List<String> ingressSource = (rule.getService() == Network.Service.NetworkACL ? segmentGroup : destCidrList);
+ List<String> 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<Group> 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<Group> groups = listNsxGroups();
+ Optional<Group> 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 0000000..ce27a7d
--- /dev/null
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java
@@ -0,0 +1,906 @@
+// 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<Network.Service, Map<Network.Capability, String>> capabilities = initCapabilities();
+
+
+ private static Map<Network.Service, Map<Network.Capability, String>> initCapabilities() {
+ Map<Network.Service, Map<Network.Capability, String>> capabilities = new HashMap<>();
+
+ Map<Network.Capability, String> dhcpCapabilities = Map.of(Network.Capability.DhcpAccrossMultipleSubnets, "true");
+ capabilities.put(Network.Service.Dhcp, dhcpCapabilities);
+
+ Map<Network.Capability, String> 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<Network.Capability, String> lbCapabilities = new HashMap<Network.Capability, String>();
+ 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<Network.Capability, String> 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<Network.Capability, String> 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<Integer, String> 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<Network.Service, Map<Network.Capability, String>> getCapabilities() {
+ return capabilities;
+ }
+
+ @Override
+ public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Network.Service> 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<Network.Service> services) {
+ return true;
+ }
+
+ @Override
+ public boolean configure(String name, Map<String, Object> 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<String, String> details, List<String> 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<Boolean, Account> 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<Boolean, Account> 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<Boolean, Account> 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<PhysicalNetworkVO> 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<StaticRouteProfile> routes) throws ResourceUnavailableException {
+ return false;
+ }
+
+ @Override
+ public boolean applyACLItemsToPrivateGw(PrivateGateway gateway, List<? extends NetworkACLItem> 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<DataCenterVO> zoneFunction = zoneId -> dataCenterDao.findById(zoneId);
+
+ @Override
+ public IpDeployer getIpDeployer(Network network) {
+ return this;
+ }
+
+ @Override
+ public boolean applyStaticNats(Network config, List<? extends StaticNat> 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<VpcVO, NetworkVO> 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<PortForwardingRule> 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)) ||
+ (vm != null && networkModel.getNicInNetwork(vm.getId(), network.getId()) == null)) {
+ 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 (rule.getState() == FirewallRule.State.Add) {
+ result &= nsxService.createPortForwardRule(networkRule);
+ } else if (rule.getState() == FirewallRule.State.Revoke) {
+ result &= nsxService.deletePortForwardRule(networkRule);
+ }
+ }
+ return result;
+ }
+
+ public Pair<VpcVO, NetworkVO> 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<VpcVO, NetworkVO> 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<LoadBalancingRule> rules) throws ResourceUnavailableException {
+ boolean result = true;
+ for (LoadBalancingRule loadBalancingRule : rules) {
+ if (loadBalancingRule.getState() == FirewallRule.State.Active) {
+ continue;
+ }
+ IPAddressVO publicIp = ipAddressDao.findByIpAndDcId(network.getDataCenterId(),
+ loadBalancingRule.getSourceIp().addr());
+ NsxOpObject nsxObject = getNsxOpObject(network);
+
+ List<NsxLoadBalancerMember> 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.getProtocol().toUpperCase(Locale.ROOT))
+ .setAlgorithm(loadBalancingRule.getAlgorithm())
+ .build();
+ if (loadBalancingRule.getState() == FirewallRule.State.Add) {
+ 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<LoadBalancerTO> updateHealthChecks(Network network, List<LoadBalancingRule> lbrules) {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public boolean handlesOnlyRulesInTransitionState() {
+ return false;
+ }
+
+ private List<NsxLoadBalancerMember> getLoadBalancerMembers(LoadBalancingRule lbRule) {
+ List<LoadBalancerVMMapVO> lbVms = lbVmMapDao.listByLoadBalancerId(lbRule.getId(), false);
+ List<NsxLoadBalancerMember> 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<? extends NetworkACLItem> rules) throws ResourceUnavailableException {
+ if (!canHandle(network, Network.Service.NetworkACL)) {
+ return false;
+ }
+
+ List<NsxNetworkRule> 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<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) {
+ List<NsxNetworkRule> 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<? extends FirewallRule> rules) throws ResourceUnavailableException {
+
+ if (!canHandle(network, Network.Service.Firewall)) {
+ return false;
+ }
+ List<NsxNetworkRule> nsxAddNetworkRules = new ArrayList<>();
+ List<NsxNetworkRule> 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<String> transformCidrListValues(List<String> sourceCidrList) {
+ List<String> 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<? extends VirtualRouterProvider> searchForInternalLoadBalancerElements(Long id, Long ntwkSvsProviderId, Boolean enabled) {
+ QueryBuilder<VirtualRouterProviderVO> 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<Class<?>> getCommands() {
+ List<Class<?>> cmdList = new ArrayList<Class<?>>();
+ 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 0000000..0d556da
--- /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<String> 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 0000000..47dfe04
--- /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<BaseResponse> 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 0000000..c59ebfd
--- /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<String, String> 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<String, Object> 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<NsxProviderVO>) 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<BaseResponse> listNsxProviders(Long zoneId) {
+ List<BaseResponse> nsxControllersResponseList = new ArrayList<>();
+ if (zoneId != null) {
+ NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(zoneId);
+ if (Objects.nonNull(nsxProviderVO)) {
+ nsxControllersResponseList.add(createNsxControllerResponse(nsxProviderVO));
+ }
+ } else {
+ List<NsxProviderVO> 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<PhysicalNetworkVO> physicalNetworks = physicalNetworkDao.listByZone(zoneId);
+ for (PhysicalNetworkVO physicalNetwork : physicalNetworks) {
+ List<NetworkVO> networkList = networkDao.listByPhysicalNetwork(physicalNetwork.getId());
+ if (!CollectionUtils.isNullOrEmpty(networkList)) {
+ validateNetworkState(networkList);
+ }
+ }
+ nsxProviderDao.remove(nsxControllerId);
+ return true;
+ }
+
+ @Override
+ public List<Class<?>> getCommands() {
+ List<Class<?>> 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<NetworkVO> 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 0000000..7463a19
--- /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<IPAddressVO> 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 0000000..f888082
--- /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<NsxNetworkRule> 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<NsxNetworkRule> 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 0000000..e064a6b
--- /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 0000000..b0668a0
--- /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<String> 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 0000000..7010b8c
--- /dev/null
+++ b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/core/spring-nsx-core-managers-context.xml
@@ -0,0 +1,32 @@
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context.xsd">
+
+ <bean id="nsxService" class="org.apache.cloudstack.service.NsxServiceImpl"/>
+ <bean id="nsxControllerUtils" class="org.apache.cloudstack.utils.NsxControllerUtils" />
+
+</beans>
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 0000000..1630826
--- /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 0000000..d5e3e21
--- /dev/null
+++ b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml
@@ -0,0 +1,39 @@
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context.xsd">
+ <bean id="Nsx" class="org.apache.cloudstack.service.NsxElement">
+ <property name="name" value="Nsx"/>
+ </bean>
+ <bean id="nsxGuestNetworkGuru" class="org.apache.cloudstack.service.NsxGuestNetworkGuru">
+ <property name="name" value="NsxGuestNetworkGuru" />
+ </bean>
+ <bean id="NsxPublicNetworkGuru" class="org.apache.cloudstack.service.NsxPublicNetworkGuru">
+ <property name="name" value="NsxPublicNetworkGuru" />
+ </bean>
+ <bean id="nsxProviderService" class="org.apache.cloudstack.service.NsxProviderServiceImpl"/>
+
+</beans>
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 0000000..ee4f4fb
--- /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<String, Object> 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<String, Object> 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<Site> siteList = List.of(site);
+ EnforcementPoint enforcementPoint = mock(EnforcementPoint.class);
+ List<EnforcementPoint> enforcementPointList = List.of(enforcementPoint);
+ List<TransportZone> 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<NsxLoadBalancerMember> 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<NsxNetworkRule> 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<NsxNetworkRule> 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 0000000..a0fde08
--- /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<Class<? extends Service>, 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<Group> ignored = Mockito.mockConstruction(Group.class, (mock, context) -> {
+ groups[0] = mock;
+ }); MockedConstruction<PathExpression> 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<String> sourceGroups = client.getGroupsForTraffic(rule, segmentName, true);
+ List<String> 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<String> sourceGroups = client.getGroupsForTraffic(rule, segmentName, true);
+ List<String> 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 0000000..318542c
--- /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<PhysicalNetworkVO> 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<String> values = nsxElement.transformCidrListValues(null);
+ Assert.assertNotNull(values);
+ Assert.assertTrue(values.isEmpty());
+ }
+
+ @Test
+ public void testTransformCidrListValuesList() {
+ List<String> 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<VpcVO, NetworkVO> 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<VpcVO, NetworkVO> 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"));
+
+ 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"));
+
+ 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 0000000..66b9684
--- /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<String, String> 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<String, String> 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 0000000..cb6f651
--- /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<BaseResponse> baseResponseList = nsxProviderService.listNsxProviders(1L);
+ assertEquals(1, baseResponseList.size());
+ }
+
+ @Test
+ public void testDeleteNsxController() {
+ NsxProviderVO nsxProviderVO = Mockito.mock(NsxProviderVO.class);
+ PhysicalNetworkVO physicalNetworkVO = mock(PhysicalNetworkVO.class);
+ List<PhysicalNetworkVO> physicalNetworkVOList = List.of(physicalNetworkVO);
+ NetworkVO networkVO = mock(NetworkVO.class);
+ List<NetworkVO> 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<NetworkVO> 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 0000000..da21bf1
--- /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<IPAddressVO> 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 0000000..41f47bc
--- /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 0000000..9139fde
--- /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 659caf0..7b4851f 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 @@
}
@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 @@
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 240af3a..97531a9 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 @@
@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 @@
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 818d370..4d22806 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 @@
}
@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 @@
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 6a5a013..f66e026 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 @@
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 1618c97..a1ff8d3 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 @@
}
@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 4d485e2..71f8679 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 @@
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 cbfba8f..1083c36 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -113,6 +113,7 @@
<module>network-elements/brocade-vcs</module>
<module>network-elements/vxlan</module>
<module>network-elements/tungsten</module>
+ <module>network-elements/nsx</module>
<module>outofbandmanagement-drivers/ipmitool</module>
<module>outofbandmanagement-drivers/nested-cloudstack</module>
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index 2d2960a..a7590df 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.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 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 @@
FirewallRulesDao firewallRulesDao;
@Inject
UserDataDao userDataDao;
+ @Inject
+ VlanDetailsDao vlanDetailsDao;
@Inject
ObjectStoreDao _objectStoreDao;
@@ -955,6 +960,8 @@
}
}
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) {
@@ -1108,6 +1115,7 @@
ipResponse.setForDisplay(ipAddr.isDisplay());
ipResponse.setPortable(ipAddr.isPortable());
+ ipResponse.setForSystemVms(ipAddr.isForSystemVms());
//set tag information
List<? extends ResourceTag> tags = ApiDBUtils.listByResourceTypeAndId(ResourceObjectType.PublicIpAddress, ipAddr.getId());
@@ -2349,6 +2357,8 @@
}
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<Detail, String> 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 24b7df5..2bfbb3b 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 AccountManager _accountMgr;
@Inject
private AnnotationDao annotationDao;
+ @Inject
+ private NsxProviderDao nsxProviderDao;
protected DataCenterJoinDaoImpl() {
@@ -117,6 +122,11 @@
}
}
+ NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(dataCenter.getId());
+ if (Objects.nonNull(nsxProviderVO)) {
+ zoneResponse.setNsxEnabled(true);
+ }
+
zoneResponse.setResourceDetails(ApiDBUtils.getResourceDetails(dataCenter.getId(), ResourceObjectType.Zone));
zoneResponse.setHasAnnotation(annotationDao.hasAnnotations(dataCenter.getUuid(), AnnotationService.EntityType.ZONE.name(),
_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())));
diff --git a/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java
index cdf414c..3d50b88 100644
--- a/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java
@@ -106,6 +106,7 @@
networkOfferingResponse.setConcurrentConnections(offering.getConcurrentConnections());
networkOfferingResponse.setSupportsStrechedL2Subnet(offering.isSupportingStrechedL2());
networkOfferingResponse.setSupportsPublicAccess(offering.isSupportingPublicAccess());
+ networkOfferingResponse.setSupportsInternalLb(offering.isInternalLb());
networkOfferingResponse.setCreated(offering.getCreated());
if (offering.getGuestType() != null) {
networkOfferingResponse.setGuestIpType(offering.getGuestType().toString());
diff --git a/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java
index b525b06..1181070 100644
--- a/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java
@@ -70,6 +70,8 @@
offeringResponse.setDomain(offeringJoinVO.getDomainPath());
offeringResponse.setZoneId(offeringJoinVO.getZoneUuid());
offeringResponse.setZone(offeringJoinVO.getZoneName());
+ offeringResponse.setForNsx(offeringJoinVO.isForNsx());
+ offeringResponse.setNsxMode(offeringJoinVO.getNsxMode());
String protocol = offeringJoinVO.getInternetProtocol();
if (StringUtils.isEmpty(protocol)) {
protocol = NetUtils.InternetProtocol.IPv4.toString();
diff --git a/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java
index 2f89b19..edae63f 100644
--- a/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java
+++ b/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java
@@ -157,6 +157,12 @@
@Column(name = "for_tungsten")
boolean forTungsten;
+ @Column(name = "for_nsx")
+ boolean forNsx;
+
+ @Column(name = "nsx_mode")
+ String nsxMode;
+
@Column(name = "service_package_id")
private String servicePackageUuid = null;
@@ -349,6 +355,24 @@
public void setForVpc(boolean forVpc) { this.forVpc = forVpc; }
+ @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;
+ }
+
public String getServicePackage() {
return servicePackageUuid;
}
diff --git a/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java
index 7eaaa02..215c94d 100644
--- a/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java
+++ b/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java
@@ -77,6 +77,12 @@
@Column(name = "sort_key")
int sortKey;
+ @Column(name = "for_nsx")
+ boolean forNsx = false;
+
+ @Column(name = "nsx_mode")
+ String nsxMode;
+
@Column(name = "domain_id")
private String domainId;
@@ -139,6 +145,16 @@
}
@Override
+ public boolean isForNsx() {
+ return forNsx;
+ }
+
+ @Override
+ public String getNsxMode() {
+ return nsxMode;
+ }
+
+ @Override
public Date getRemoved() {
return removed;
}
diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index d5e0d01..80511b2 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -46,7 +46,11 @@
import javax.naming.ConfigurationException;
+import com.cloud.dc.VlanDetailsVO;
+import com.cloud.dc.dao.VlanDetailsDao;
import com.cloud.hypervisor.HypervisorGuru;
+import com.cloud.network.dao.NsxProviderDao;
+import com.cloud.network.element.NsxProviderVO;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.host.HostTagVO;
import com.cloud.storage.StoragePoolTagVO;
@@ -136,6 +140,7 @@
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
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;
@@ -348,6 +353,8 @@
@Inject
VlanDao _vlanDao;
@Inject
+ VlanDetailsDao vlanDetailsDao;
+ @Inject
IPAddressDao _publicIpAddressDao;
@Inject
DataCenterIpAddressDao _privateIpAddressDao;
@@ -455,6 +462,8 @@
Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao;
@Inject
Ipv6Service ipv6Service;
+ @Inject
+ NsxProviderDao nsxProviderDao;
// FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao?
@Inject
@@ -2551,10 +2560,14 @@
}
// we should actually find the mapping and remove if it exists
// but we don't know about vmware/plugin/hypervisors at this point
-
final boolean success = _zoneDao.remove(zoneId);
if (success) {
+ NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId);
+ if (Objects.nonNull(nsxProvider)) {
+ nsxProviderDao.remove(nsxProvider.getId());
+ }
+
// delete template refs for this zone
templateZoneDao.deleteByZoneId(zoneId);
// delete all capacity records for the zone
@@ -2638,7 +2651,7 @@
zoneName = zone.getName();
}
- if (guestCidr != null && !NetUtils.validateGuestCidr(guestCidr)) {
+ if (guestCidr != null && !NetUtils.validateGuestCidr(guestCidr, !AllowNonRFC1918CompliantIPs.value())) {
throw new InvalidParameterValueException("Please enter a valid guest cidr");
}
@@ -2807,7 +2820,7 @@
// checking the following params outside checkzoneparams method as we do
// not use these params for updatezone
// hence the method below is generic to check for common params
- if (guestCidr != null && !NetUtils.validateGuestCidr(guestCidr)) {
+ if (guestCidr != null && !NetUtils.validateGuestCidr(guestCidr, !AllowNonRFC1918CompliantIPs.value())) {
throw new InvalidParameterValueException("Please enter a valid guest cidr");
}
@@ -4461,7 +4474,7 @@
} else {
network = _networkModel.getNetworkWithSecurityGroupEnabled(zoneId);
if (network == null) {
- throw new InvalidParameterValueException("Nework id is required for Direct vlan creation ");
+ throw new InvalidParameterValueException("Network id is required for Direct vlan creation ");
}
networkId = network.getId();
zoneId = network.getDataCenterId();
@@ -4526,12 +4539,12 @@
}
return commitVlan(zoneId, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, forVirtualNetwork, forSystemVms, networkId, physicalNetworkId, startIPv6, endIPv6, ip6Gateway,
- ip6Cidr, domain, vlanOwner, network, sameSubnet);
+ ip6Cidr, domain, vlanOwner, network, sameSubnet, cmd.isForNsx());
}
private Vlan commitVlan(final Long zoneId, final Long podId, final String startIP, final String endIP, final String newVlanGatewayFinal, final String newVlanNetmaskFinal,
final String vlanId, final Boolean forVirtualNetwork, final Boolean forSystemVms, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6,
- final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair<Boolean, Pair<String, String>> sameSubnet) {
+ final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair<Boolean, Pair<String, String>> sameSubnet, boolean forNsx) {
final GlobalLock commitVlanLock = GlobalLock.getInternLock("CommitVlan");
commitVlanLock.lock(5);
logger.debug("Acquiring lock for committing vlan");
@@ -4559,7 +4572,7 @@
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;
@@ -4683,7 +4696,7 @@
@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;
@@ -4765,11 +4778,11 @@
} 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;
}
@@ -4866,7 +4879,7 @@
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());
}
@@ -4882,7 +4895,7 @@
// 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;
}
@@ -4904,9 +4917,11 @@
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];
@@ -4951,13 +4966,14 @@
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<VlanVO>() {
@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
@@ -5936,7 +5952,10 @@
final Map<String, String> 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();
@@ -5970,6 +5989,26 @@
}
}
+ 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)) {
@@ -6234,7 +6273,12 @@
}
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;
@@ -6374,12 +6418,12 @@
@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<Service, Set<Provider>> serviceProviderMap, final boolean isDefault, final GuestType type, final boolean systemOnly,
- final Long serviceOfferingId,
- final boolean conserveMode, final Map<Service, Map<Capability, String>> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent,
- final Map<Detail, String> details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc,
- Boolean forTungsten, final List<Long> domainIds, final List<Long> zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol) {
+ final Availability availability,
+ final Integer networkRate, final Map<Service, Set<Provider>> serviceProviderMap, final boolean isDefault, final GuestType type, final boolean systemOnly,
+ final Long serviceOfferingId,
+ final boolean conserveMode, final Map<Service, Map<Capability, String>> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent,
+ final Map<Detail, String> details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc,
+ Boolean forTungsten, boolean forNsx, String mode, final List<Long> domainIds, final List<Long> zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol) {
String servicePackageUuid;
String spDescription = null;
@@ -6540,6 +6584,10 @@
}
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);
@@ -6604,7 +6652,7 @@
logger.trace("Added service for the network offering: " + offService + " with provider " + provider.getName());
}
- if (vpcOff) {
+ if (vpcOff && !forNsx) {
final List<Service> supportedSvcs = new ArrayList<Service>();
supportedSvcs.addAll(serviceProviderMap.keySet());
_vpcMgr.validateNtwkOffForVpc(offering, supportedSvcs);
@@ -7693,8 +7741,8 @@
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 d0d728d..236a286 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 @@
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 @@
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 @@
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 @@
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 b8c464c..16473e8 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 @@
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 af0d25c..407264e 100644
--- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
@@ -489,7 +489,7 @@
@Override
public Map<Provider, ArrayList<PublicIpAddress>> getProviderToIpList(Network network, Map<PublicIpAddress, Set<Service>> ipToServices) {
NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
- if (!offering.isConserveMode()) {
+ if (!offering.isConserveMode() && !offering.isForNsx()) {
for (PublicIpAddress ip : ipToServices.keySet()) {
Set<Service> services = new HashSet<Service>();
services.addAll(ipToServices.get(ip));
@@ -1615,7 +1615,7 @@
if (!canIpUsedForService(publicIp, service, networkId)) {
return false;
}
- if (!offering.isConserveMode()) {
+ if (!offering.isConserveMode() && !offering.isForNsx()) {
return canIpUsedForNonConserveService(publicIp, service);
}
return true;
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index 9705f23..1184ff1 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.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 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.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 @@
@Inject
VlanDao _vlanDao = null;
@Inject
+ private VlanDetailsDao vlanDetailsDao;
+ @Inject
IPAddressDao _ipAddressDao = null;
@Inject
AccountDao _accountDao = null;
@@ -349,8 +359,6 @@
@Inject
HostDao _hostDao;
@Inject
- InternalLoadBalancerElementService _internalLbElementSvc;
- @Inject
DataCenterVnetDao _dcVnetDao;
@Inject
AccountGuestVlanMapDao _accountGuestVlanMapDao;
@@ -404,6 +412,12 @@
ServiceOfferingDao serviceOfferingDao;
@Inject
PublicIpQuarantineDao publicIpQuarantineDao;
+ @Inject
+ NsxProviderDao nsxProviderDao;
+ @Inject
+ private VirtualRouterProviderDao virtualRouterProviderDao;
+ List<InternalLoadBalancerElementService> internalLoadBalancerElementServices = new ArrayList<>();
+ Map<String, InternalLoadBalancerElementService> internalLoadBalancerElementServiceMap = new HashMap<>();
@Autowired
@Qualifier("networkHelper")
@@ -811,9 +825,19 @@
@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 @@
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<IPAddressVO> 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<VlanVO> 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<AccountVlanMapVO> accountVlanMaps = _accountVlanMapDao.listAccountVlanMapsByVlan(vlanId);
if (CollectionUtils.isNotEmpty(accountVlanMaps)) {
@@ -1414,6 +1490,7 @@
_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 @@
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 @@
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 @@
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 @@
// Add the config drive provider
addConfigDriveToPhysicalNetwork(pNetwork.getId());
+ addNSXProviderToPhysicalNetwork(pNetwork.getId());
CallContext.current().putContextParameter(PhysicalNetwork.class, pNetwork.getUuid());
@@ -5348,7 +5435,8 @@
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 @@
}
+ 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 @@
_networkGurus = networkGurus;
}
+ public void setInternalLoadBalancerElementServices(List<InternalLoadBalancerElementService> 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 @@
_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<InternalLoadBalancerElementService> 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 3d1920b..b896062 100644
--- a/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java
+++ b/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java
@@ -530,6 +530,11 @@
}
@Override
+ public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> 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 5b0d9eb..e9a9352 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.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 @@
NetworkDao _networkDao;
@Inject
VpcManager _vpcMgr;
+ @Inject
+ EntityManager entityManager;
+ @Inject
+ NsxProviderDao nsxProviderDao;
List<FirewallServiceProvider> _firewallElements;
List<PortForwardingServiceProvider> _pfElements;
@@ -687,6 +697,9 @@
}
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 @@
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 0ed71cf..2142796 100644
--- a/server/src/main/java/com/cloud/network/guru/ControlNetworkGuru.java
+++ b/server/src/main/java/com/cloud/network/guru/ControlNetworkGuru.java
@@ -88,7 +88,7 @@
}
@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;
}
@@ -102,6 +102,11 @@
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 c8c3234..a8c98fc 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 @@
}
@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 @@
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 d11483e..bdabc6c 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 @@
}
@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 46a0a0a..ae8ee1e 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 @@
@Inject
ConfigurationServer _configServer;
@Inject
- IpAddressManager _ipAddrMgr;
+ protected IpAddressManager _ipAddrMgr;
@Inject
- NetworkOfferingDao networkOfferingDao;
+ protected NetworkOfferingDao networkOfferingDao;
@Inject
Ipv6AddressManager ipv6AddressManager;
@Inject
@@ -146,6 +146,11 @@
_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 @@
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 3a0ad7e..6624624 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 @@
}
@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 @@
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 9f6551f..bd4f020 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 @@
}
@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;
@@ -136,6 +136,11 @@
}
@Override
+ public void setup(Network network, long networkId) {
+ // do nothing
+ }
+
+ @Override
public void deallocate(Network network, NicProfile nic, VirtualMachineProfile vm) {
if (logger.isDebugEnabled()) {
logger.debug("Deallocate network: networkId: " + nic.getNetworkId() + ", ip: " + nic.getIPv4Address());
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 0061064..1b02e14 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 @@
@Inject
NetworkOrchestrationService _networkMgr;
@Inject
- IPAddressDao _ipAddressDao;
+ protected IPAddressDao _ipAddressDao;
@Inject
IpAddressManager _ipAddrMgr;
@Inject
@@ -98,7 +98,7 @@
}
@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 @@
}
}
+ @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 0f199a7..221661f 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 @@
}
@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 2206173..677707e 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.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 @@
// vlan1, then all ip addresses of vlan2, etc..
final Map<String, ArrayList<PublicIpAddress>> vlanIpMap = new HashMap<String, ArrayList<PublicIpAddress>>();
for (final PublicIpAddress ipAddress : ips) {
- final String vlanTag = ipAddress.getVlanTag();
+ String vlanTag = ipAddress.getVlanTag();
+ if (Objects.isNull(vlanTag)) {
+ vlanTag = "nsx-"+ipAddress.getAddress().addr();
+ }
ArrayList<PublicIpAddress> ipList = vlanIpMap.get(vlanTag);
if (ipList == null) {
ipList = new ArrayList<PublicIpAddress>();
@@ -841,10 +845,18 @@
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 @@
}
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;
@@ -1345,7 +1360,8 @@
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 9c093e3..1f4642b 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 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.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 @@
Ipv6Service ipv6Service;
@Inject
CapacityManager capacityMgr;
+ @Inject
+ VpcDao vpcDao;
protected final Map<HypervisorType, ConfigKey<String>> hypervisorsMap = new HashMap<>();
@@ -709,8 +712,8 @@
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 15c8a2b..399019d 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 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 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 8c7e452..fa2f2ab 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.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 @@
final TreeSet<String> publicVlans = new TreeSet<String>();
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 c09df8d..e30cdd5 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.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 @@
private EntityManager _entityMgr;
@Inject
protected HypervisorGuruManager _hvGuruMgr;
+ @Inject
+ protected NetworkDao networkDao;
+ @Inject
+ protected VpcDao vpcDao;
@Override
public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
@@ -358,7 +365,12 @@
} else if (network.getTrafficType() == TrafficType.Public) {
final Pair<Nic, Network> publicNic = new Pair<Nic, Network>(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 @@
_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 04796146..2f37bdd 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 @@
final List<NetworkACLItemVO> 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 @@
return applyACLToPrivateGw(gateway, rules);
}
+ @Override
+ public boolean reorderAclRules(VpcVO vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) {
+ List<NetworkACLServiceProvider> 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<? extends NetworkACLItem> rules) throws ResourceUnavailableException {
List<VpcProvider> vpcElements = new ArrayList<VpcProvider>();
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 92784e2..4a87f4b 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.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 @@
private VpcDao _vpcDao;
@Inject
private VpcService _vpcSvc;
+ @Inject
+ private NsxProviderDao nsxProviderDao;
private String supportedProtocolsForAclRules = "tcp,udp,icmp,all";
@@ -336,6 +343,7 @@
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 @@
}
}
+ 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 @@
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.");
@@ -956,14 +991,26 @@
NetworkACLVO lockedAcl = _networkACLDao.acquireInLockTable(ruleBeingMoved.getAclId());
List<NetworkACLItemVO> 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<NetworkVO> 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 e313b1b..755cf2b 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.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.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 @@
@Autowired
@Qualifier("networkHelper")
protected NetworkHelper networkHelper;
+ @Inject
+ private NsxService nsxService;
@Inject
private VpcPrivateGatewayTransactionCallable vpcTxCallable;
@@ -270,7 +275,7 @@
private List<VpcProvider> vpcElements = null;
private final List<Service> nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall);
private final List<Provider> 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 @@
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 @@
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 @@
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<Service, Set<Provider>> svcProviderMap = new HashMap<Service, Set<Provider>>();
+ final Set<Provider> defaultProviders = Set.of(Provider.Nsx);
+ for (final Service svc : getSupportedServices()) {
+ if (List.of(Service.UserData, Service.Dhcp, Service.Dns).contains(svc)) {
+ final Set<Provider> 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<Service, Set<Provider>> svcProviderMap = new HashMap<>();
+ final Set<Provider> defaultProviders = Set.of(Provider.Nsx);
+ for (final Service svc : getSupportedServices()) {
+ if (List.of(Service.UserData, Service.Dhcp, Service.Dns).contains(svc)) {
+ final Set<Provider> 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 @@
final Long serviceOfferingId = cmd.getServiceOfferingId();
final List<Long> domainIds = cmd.getDomainIds();
final List<Long> 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 @@
}
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<String> supportedServices, final Map<String, List<String>> serviceProviders,
- final Map serviceCapabilityList, final NetUtils.InternetProtocol internetProtocol, final Long serviceOfferingId, List<Long> domainIds, List<Long> zoneIds, State state) {
+ final Map serviceCapabilityList, final NetUtils.InternetProtocol internetProtocol, final Long serviceOfferingId,
+ final Boolean forNsx, final String mode, List<Long> domainIds, List<Long> 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 @@
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<VpcOfferingDetailsVO> detailsVO = new ArrayList<>();
@@ -565,7 +633,7 @@
@DB
protected VpcOfferingVO createVpcOffering(final String name, final String displayText, final Map<Network.Service, Set<Network.Provider>> 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<VpcOfferingVO>() {
@Override
@@ -576,6 +644,8 @@
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 @@
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 @@
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 @@
}
}
+ 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 @@
}
// 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 @@
}
}
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 @@
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 @@
// 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 @@
// 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 @@
* 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 @@
@Override
public boolean isSrcNatIpRequired(long vpcOfferingId) {
final Map<Network.Service, Set<Network.Provider>> 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 4cb9096..821f93a 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 @@
}
_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<Service, Provider> serviceProviderMap = getServicesAndProvidersForNSXNetwork(nsxMode, forVpc, publicLB);
+ for (Map.Entry<Network.Service, Network.Provider> 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<Service, Provider> getServicesAndProvidersForNSXNetwork(NetworkOffering.NsxMode nsxMode, boolean forVpc, boolean publicLB) {
+ final Map<Network.Service, Network.Provider> 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<DataCenterVO> 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 8e94237..c13f401 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -836,6 +836,7 @@
public class ManagementServerImpl extends ManagerBase implements ManagementServer, Configurable {
protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
+ static final String FOR_SYSTEMVMS = "forsystemvms";
static final ConfigKey<Integer> vmPasswordLength = new ConfigKey<Integer>("Advanced", Integer.class, "vm.password.length", "6", "Specifies the length of a randomly generated password", false);
static final ConfigKey<Integer> sshKeyLength = new ConfigKey<Integer>("Advanced", Integer.class, "ssh.key.length", "2048", "Specifies custom SSH key length (bit)", true, ConfigKey.Scope.Global);
static final ConfigKey<Boolean> humanReadableSizes = new ConfigKey<Boolean>("Advanced", Boolean.class, "display.human.readable.sizes", "true", "Enables outputting human readable byte sizes to logs and usage records.", false, ConfigKey.Scope.Global);
@@ -2561,7 +2562,7 @@
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<LoadBalancerVO> lbSearch = _loadbalancerDao.createSearchBuilder();
@@ -2607,6 +2608,7 @@
final Boolean staticNat = cmd.isStaticNat();
final Boolean forDisplay = cmd.getDisplay();
final String state = cmd.getState();
+ final Boolean forSystemVms = cmd.getForSystemVMs();
final Map<String, String> tags = cmd.getTags();
sc.setJoinParameters("vlanSearch", "vlanType", vlanType);
@@ -2668,7 +2670,9 @@
}
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 063ed09..9fb7ae3 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.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 @@
@Inject
VMScheduleManager vmScheduleManager;
+ @Inject
+ NsxProviderDao nsxProviderDao;
private ScheduledExecutorService _executor = null;
private ScheduledExecutorService _vmIpFetchExecutor = null;
@@ -597,6 +602,7 @@
private boolean _dailyOrHourly = false;
private int capacityReleaseInterval;
private ExecutorService _vmIpFetchThreadExecutor;
+ private List<KubernetesClusterHelper> kubernetesClusterHelpers;
private String _instance;
@@ -610,6 +616,14 @@
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<KubernetesClusterHelper> getKubernetesClusterHelpers() {
+ return kubernetesClusterHelpers;
+ }
+
+ public void setKubernetesClusterHelpers(final List<KubernetesClusterHelper> kubernetesClusterHelpers) {
+ this.kubernetesClusterHelpers = kubernetesClusterHelpers;
+ }
+
@Inject
private OrchestrationService _orchSrvc;
@@ -2528,11 +2542,15 @@
}
// 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 c09775d..2dea5a4 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 @@
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 @@
protected NetworkDao networkDao;
protected DomainRouterDao routerDao;
+ protected NsxProviderDao nsxProviderDao;
protected PhysicalNetworkServiceProviderDao physicalProviderDao;
protected NetworkModel networkModel;
protected VirtualRouterProviderDao vrProviderDao;
@@ -384,8 +390,19 @@
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 aab0971..227ae8d 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 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 @@
@Inject
private DomainRouterDao routerDao;
@Inject
+ private NsxProviderDao nsxProviderDao;
+ @Inject
private PhysicalNetworkServiceProviderDao physicalProviderDao;
@Inject
private NetworkModel networkModel;
@@ -125,6 +128,7 @@
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 8b964a3..aa44f29 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 @@
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 @@
@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 7227264..c80c294 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 @@
<bean id="configurationServerImpl" class="com.cloud.server.ConfigurationServerImpl" />
-
- <bean id="userVmManagerImpl" class="com.cloud.vm.UserVmManagerImpl" />
+ <bean id="userVmManagerImpl" class="com.cloud.vm.UserVmManagerImpl">
+ <property name="kubernetesClusterHelpers" value="#{kubernetesClusterHelperRegistry.registered}" />
+ </bean>
<bean id="consoleProxyManagerImpl" class="com.cloud.consoleproxy.ConsoleProxyManagerImpl">
<property name="consoleProxyAllocators"
@@ -164,6 +165,7 @@
<bean id="networkServiceImpl" class="com.cloud.network.NetworkServiceImpl" >
<property name="networkGurus" value="#{networkGurusRegistry.registered}" />
+ <property name="internalLoadBalancerElementServices" value="#{internalLoadBalancerElementServiceRegistry.registered}" />
</bean>
<bean id="networkUsageManagerImpl" class="com.cloud.network.NetworkUsageManagerImpl" />
diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java
index 3818931..a9f9229 100644
--- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java
+++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java
@@ -16,11 +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 org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -29,19 +58,97 @@
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+import java.util.Collections;
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 {
@Mock
ConfigDepot configDepot;
+ @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;
+
ConfigurationManagerImpl configurationManagerImplSpy = Mockito.spy(new ConfigurationManagerImpl());
+ DeleteZoneCmd deleteZoneCmd;
+ CreateNetworkOfferingCmd createNetworkOfferingCmd;
@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
@@ -250,4 +357,55 @@
Mockito.doReturn(key).when(configurationManagerImplSpy._configDepot).get("config.iprange");
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);
+ }
}
diff --git a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java
index 0bbead6..0f15abc 100644
--- a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java
+++ b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java
@@ -17,12 +17,33 @@
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.utils.Pair;
+import com.cloud.utils.net.Ip;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
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;
public class NetworkModelImplTest {
final String[] ip4Dns1 = {"5.5.5.5", "6.6.6.6"};
@@ -33,6 +54,15 @@
@InjectMocks
private NetworkModelImpl networkModel = new NetworkModelImpl();
+ 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,
String dns1, String dns2, String dns3, String dns4) {
if (isIp6) {
@@ -140,4 +170,35 @@
public void testVerifyIp6DnsPairValid() {
networkModel.verifyIp6DnsPair(ip6Dns1[0], ip6Dns1[1]);
}
+
+ @Test
+ public void testGetProviderToIpList() {
+ Set<Network.Service> services1 = new HashSet<>(List.of(Network.Service.Firewall));
+ Set<Network.Service> 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<NetworkServiceMapVO> 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<PublicIpAddress, Set<Network.Service>> ipToServices = new HashMap<>();
+ ipToServices.put(publicIpAddress1, services1);
+ ipToServices.put(publicIpAddress2, services2);
+ Map<Network.Provider, ArrayList<PublicIpAddress>> 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 c993f7b..f2ab2a0 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 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 @@
@Mock
private Ip ipMock;
+ @Mock
+ private NsxProviderDao nsxProviderDao;
private static Date beforeDate;
@@ -295,6 +298,7 @@
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 9818b43..50d8af5 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 @@
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 @@
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 3286ee5..bcb39b6 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 @@
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 f03ae9d..37fa13b 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 @@
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<PublicIpAddress> pubIpList = new ArrayList<>(1);
+ pubIpList.add(publicIpAddress);
+ Commands commands = new Commands(Command.OnError.Stop);
+ Map<String, String> vlanMacAddress = new HashMap<>();
+ NicVO nicVO = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
+ NetworkVO networkVO = new NetworkVO();
+ networkVO.setNetworkOfferingId(12L);
+ List<IPAddressVO> userIps = List.of(ipAddressVO);
+ NetworkOfferingVO networkOfferingVO = new NetworkOfferingVO();
+ Map<NetworkOffering.Detail, String> 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 8e1408d..a729af0 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.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 @@
@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 @@
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 cd1745c..1f39cf3 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.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 org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.ServerApiException;
@@ -103,6 +107,8 @@
private NetworkACLVO networkACLVOMock;
@Mock
private UpdateNetworkACLListCmd updateNetworkACLListCmdMock;
+ @Mock
+ private NsxProviderDao nsxProviderDao;
private Long networkAclMockId = 5L;
private Long networkOfferingMockId = 2L;
@@ -129,6 +135,8 @@
@Mock
private VpcVO vpcVOMock;
+ @Mock
+ DataCenter dataCenterVO;
@Mock
private Account accountMock;
@@ -173,7 +181,9 @@
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);
@@ -710,6 +720,9 @@
@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 ba9fff5..4cb2b61 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 @@
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 @@
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 @@
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 1d9b65a..f9f6655 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 @@
Integer networkRate, Map<Service, Set<Provider>> serviceProviderMap, boolean isDefault, GuestType type, boolean systemOnly, Long serviceOfferingId,
boolean conserveMode, Map<Service, Map<Capability, String>> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent,
Map<NetworkOffering.Detail, String> details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc,
- Boolean forTungsten, List<Long> domainIds, List<Long> zoneIds, boolean enableOffering, NetUtils.InternetProtocol internetProtocol) {
+ Boolean forTungsten, boolean forNsx, String mode, List<Long> domainIds, List<Long> zoneIds, boolean enableOffering, NetUtils.InternetProtocol internetProtocol) {
// TODO Auto-generated method stub
return null;
}
@@ -556,7 +556,7 @@
*/
@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 434c644..106fc7f 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 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.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;
@@ -182,6 +184,11 @@
}
@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 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<InternalLoadBalancerElementService> 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 d2f00c4..6579a89 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 @@
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 @@
private NetworkACLItemDao _networkACLItemDao;
@Inject
private EntityManager _entityMgr;
+ @Inject
+ private NsxProviderDao nsxProviderDao;
private NetworkACLVO acl;
private NetworkACLItemVO aclItem;
@@ -184,6 +187,9 @@
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 f9d6d0d..679324f 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.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 @@
@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 969fb1f..a355ad2 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.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 @@
@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 d0b7ace..838bb3d 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.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 @@
@Inject
AnnotationDao annotationDao;
+ @Inject
+ VlanDetailsDao vlanDetailsDao;
@Inject
PublicIpQuarantineDao publicIpQuarantineDao;
@@ -135,7 +138,7 @@
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 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 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 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 @@
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 @@
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 @@
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 @@
Set<Network.Provider> vrProvider = new HashSet<Network.Provider>();
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 @@
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 @@
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 28e6027..787de99 100644
--- a/server/src/test/resources/createNetworkOffering.xml
+++ b/server/src/test/resources/createNetworkOffering.xml
@@ -72,5 +72,7 @@
<bean id="PassphraseDaoImpl" class="org.apache.cloudstack.secret.dao.PassphraseDaoImpl" />
<bean id="configurationGroupDaoImpl" class="org.apache.cloudstack.framework.config.dao.ConfigurationGroupDaoImpl" />
<bean id="configurationSubGroupDaoImpl" class="org.apache.cloudstack.framework.config.dao.ConfigurationSubGroupDaoImpl" />
+ <bean id="nsxControllerDaoImpl" class="com.cloud.network.dao.NsxProviderDaoImpl" />
+ <bean id="vlanDetailsDao" class="com.cloud.dc.dao.VlanDetailsDaoImpl" />
<bean id="publicIpQuarantineDaoImpl" class="com.cloud.network.dao.PublicIpQuarantineDaoImpl" />
</beans>
diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py
index b971d24..9df6bf9 100644
--- a/tools/apidoc/gen_toc.py
+++ b/tools/apidoc/gen_toc.py
@@ -134,6 +134,9 @@
'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 5da82a5..198bbcc 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",
@@ -912,6 +912,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",
@@ -1050,7 +1052,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)",
@@ -1338,6 +1340,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",
@@ -1432,6 +1435,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",
@@ -1619,6 +1635,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",
@@ -2043,7 +2060,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.tags": "Tags",
@@ -2494,11 +2513,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: <b><span id=\"zone_name\"></span></b>",
-"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: <b><span id=\"zone_name\"></span></b>",
+"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...",
@@ -2571,6 +2591,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",
@@ -2912,6 +2933,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",
@@ -2928,6 +2950,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",
@@ -2948,6 +2976,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.",
@@ -3098,6 +3127,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.<br/><br/>You may also <strong>add</strong> 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 de6aed4..4fba1da 100644
--- a/ui/src/components/CheckBoxSelectPair.vue
+++ b/ui/src/components/CheckBoxSelectPair.vue
@@ -21,6 +21,7 @@
<a-col :md="24" :lg="layout === 'horizontal' ? 10 : 24">
<a-checkbox
:checked="checked"
+ :disabled="forNsx"
@change="handleCheckChange">
{{ checkBoxLabel }}
</a-checkbox>
@@ -30,7 +31,8 @@
v-if="reversed !== checked"
:label="selectLabel">
<a-select
- v-model:value="selectedOption"
+ v-model:value="selected"
+ :disabled="forNsx"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
@@ -83,6 +85,10 @@
reversed: {
type: Boolean,
default: false
+ },
+ forNsx: {
+ type: Boolean,
+ default: false
}
},
data () {
@@ -112,6 +118,15 @@
}
return option
})
+ },
+ selected () {
+ return this.option || this.selectedOption
+ },
+ option () {
+ if (this.forNsx) {
+ return this.selectOptions[0]?.name || null
+ }
+ return null
}
},
methods: {
diff --git a/ui/src/components/view/DetailsTab.vue b/ui/src/components/view/DetailsTab.vue
index 5f27096..db188e0 100644
--- a/ui/src/components/view/DetailsTab.vue
+++ b/ui/src/components/view/DetailsTab.vue
@@ -43,7 +43,7 @@
<br/>
<div v-if="Array.isArray(dataResource[item]) && item === 'service'">
<div v-for="(service, idx) in dataResource[item]" :key="idx">
- {{ service.name }} : {{ service.provider[0].name }}
+ {{ service.name }} : {{ service.provider?.[0]?.name }}
</div>
</div>
<div v-else-if="$route.meta.name === 'backup' && item === 'volumes'">
diff --git a/ui/src/components/view/ResourceView.vue b/ui/src/components/view/ResourceView.vue
index 367c589..2c1764d 100644
--- a/ui/src/components/view/ResourceView.vue
+++ b/ui/src/components/view/ResourceView.vue
@@ -114,15 +114,7 @@
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 @@
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 65daaf5..75ba6f5 100644
--- a/ui/src/config/section/offering.js
+++ b/ui/src/config/section/offering.js
@@ -269,7 +269,7 @@
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 @@
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 4985389..b01f543 100644
--- a/ui/src/views/infra/network/ServiceProvidersTab.vue
+++ b/ui/src/views/infra/network/ServiceProvidersTab.vue
@@ -1056,6 +1056,50 @@
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 @@
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 2233295..c39534d 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%" >
<template #bodyCell="{ column, record }">
+ <template v-if="column.key === 'gateway'">
+ <div> {{ record.gateway }}</div>
+ <div v-if="record.fornsx"> <a-tag color="processing"> {{ $t('label.tag.nsx') }} </a-tag> </div>
+ <div v-else-if="isNsxZone"> <a-tag color="processing"> {{ $t('label.tag.systemvm') }} </a-tag> </div>
+ </template>
<template v-if="column.key === 'actions'">
<tooltip-button
:tooltip="$t('label.delete')"
+ :disabled="(record.fornsx && !forNsx) || (!record.fornsx && forNsx)"
type="primary"
:danger="true"
icon="delete-outlined"
@@ -70,6 +76,7 @@
<a-form-item name="vlan" ref="vlan">
<a-input
v-model:value="form.vlan"
+ :disabled="forNsx"
:placeholder="$t('label.vlan')"
/>
</a-form-item>
@@ -160,6 +167,14 @@
isFixError: {
type: Boolean,
default: false
+ },
+ forNsx: {
+ type: Boolean,
+ default: false
+ },
+ isNsxZone: {
+ type: Boolean,
+ default: false
}
},
data () {
@@ -170,6 +185,7 @@
ipRanges: [],
columns: [
{
+ key: 'gateway',
title: this.$t('label.gateway'),
dataIndex: 'gateway',
width: 140
@@ -245,13 +261,17 @@
handleAddRange () {
this.formRef.value.validate().then(() => {
const values = toRaw(this.form)
+ const len = this.isValidSetup() ? this.ipRanges.length - 1 : 0
+ const key = this.isValidSetup() ? this.ipRanges[len].key : 0
this.ipRanges.push({
- key: this.ipRanges.length.toString(),
+ key: key + 1,
gateway: values.gateway,
netmask: values.netmask,
vlan: values.vlan,
startIp: values.startIp,
- endIp: values.endIp
+ endIp: values.endIp,
+ fornsx: this.forNsx,
+ forsystemvms: this.isNsxZone && !this.forNsx
})
this.formRef.value.resetFields()
}).catch(error => {
diff --git a/ui/src/views/infra/zone/ZoneWizard.vue b/ui/src/views/infra/zone/ZoneWizard.vue
index bdd12f7..0f4c7f7 100644
--- a/ui/src/views/infra/zone/ZoneWizard.vue
+++ b/ui/src/views/infra/zone/ZoneWizard.vue
@@ -139,7 +139,7 @@
{
name: 'network',
title: 'label.network',
- step: ['physicalNetwork', 'tungsten', 'netscaler', 'pod', 'guestTraffic', 'storageTraffic', 'publicTraffic'],
+ step: ['physicalNetwork', 'nsx', 'tungsten', 'netscaler', 'pod', 'guestTraffic', 'storageTraffic', 'publicTraffic', 'nsxPublicTraffic'],
description: this.$t('message.network.description'),
hint: this.$t('message.network.hint')
},
diff --git a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue
index 929b0bf..5995d23 100644
--- a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue
+++ b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue
@@ -124,6 +124,7 @@
waiting: 'message.launch.zone',
launching: 'message.please.wait.while.zone.is.being.created'
},
+ nsx: false,
isLaunchZone: false,
processStatus: null,
messageError: '',
@@ -200,7 +201,6 @@
this.stepData.tasks = []
this.stepData.stepMove = this.stepData.stepMove.filter(item => item.indexOf('createStorageNetworkIpRange') === -1)
}
- console.log('step-data', this.stepData)
// this.handleSubmit()
}
},
@@ -217,6 +217,7 @@
setStepStatus (status) {
const index = this.steps.findIndex(step => step.index === this.currentStep)
this.steps[index].status = status
+ this.nsx = false
},
handleBack (e) {
this.$emit('backPressed')
@@ -483,6 +484,11 @@
this.stepData.isTungstenZone = true
this.stepData.tungstenPhysicalNetworkId = physicalNetworkReturned.id
}
+ if (physicalNetwork.isolationMethod === 'NSX' &&
+ physicalNetwork.traffics.findIndex(traffic => traffic.type === 'public' || traffic.type === 'guest') > -1) {
+ this.stepData.isNsxZone = true
+ this.stepData.tungstenPhysicalNetworkId = physicalNetworkReturned.id
+ }
} else {
this.stepData.physicalNetworkReturned = this.stepData.physicalNetworkItem['createPhysicalNetwork' + index]
}
@@ -855,7 +861,7 @@
this.stepData.podReturned = await this.createPod(params)
this.stepData.stepMove.push('createPod')
}
- await this.stepConfigurePublicTraffic()
+ await this.stepConfigurePublicTraffic('message.configuring.public.traffic', 'publicTraffic', 0)
} catch (e) {
this.messageError = e
this.processStatus = STATUS_FAILED
@@ -893,19 +899,24 @@
this.setStepStatus(STATUS_FAILED)
}
},
- async stepConfigurePublicTraffic () {
+ async stepConfigurePublicTraffic (message, trafficType, idx) {
if (
(this.isBasicZone &&
(this.havingSG && this.havingEIP && this.havingELB)) ||
(this.isAdvancedZone && !this.sgEnabled && !this.isEdgeZone)) {
this.setStepStatus(STATUS_FINISH)
this.currentStep++
- this.addStep('message.configuring.public.traffic', 'publicTraffic')
+ this.addStep(message, trafficType)
+ if (trafficType === 'nsxPublicTraffic') {
+ this.nsx = false
+ }
let stopNow = false
this.stepData.returnedPublicTraffic = this.stepData?.returnedPublicTraffic || []
- for (let index = 0; index < this.prefillContent['public-ipranges'].length; index++) {
- const publicVlanIpRange = this.prefillContent['public-ipranges'][index]
+ let publicIpRanges = this.prefillContent['public-ipranges']
+ publicIpRanges = publicIpRanges.filter(item => item.fornsx === (idx === 1))
+ for (let index = 0; index < publicIpRanges.length; index++) {
+ const publicVlanIpRange = publicIpRanges[index]
let isExisting = false
this.stepData.returnedPublicTraffic.forEach(publicVlan => {
@@ -926,6 +937,8 @@
params.zoneId = this.stepData.zoneReturned.id
if (publicVlanIpRange.vlan && publicVlanIpRange.vlan.length > 0) {
params.vlan = publicVlanIpRange.vlan
+ } else if (publicVlanIpRange.fornsx) {
+ params.vlan = null
} else {
params.vlan = 'untagged'
}
@@ -933,6 +946,8 @@
params.netmask = publicVlanIpRange.netmask
params.startip = publicVlanIpRange.startIp
params.endip = publicVlanIpRange.endIp
+ params.fornsx = publicVlanIpRange.fornsx
+ params.forsystemvms = publicVlanIpRange.forsystemvms
if (this.isBasicZone) {
params.forVirtualNetwork = true
@@ -945,10 +960,10 @@
}
try {
- if (!this.stepData.stepMove.includes('createPublicVlanIpRange' + index)) {
+ if (!this.stepData.stepMove.includes('createPublicVlanIpRange' + idx + index)) {
const vlanIpRangeItem = await this.createVlanIpRange(params)
this.stepData.returnedPublicTraffic.push(vlanIpRangeItem)
- this.stepData.stepMove.push('createPublicVlanIpRange' + index)
+ this.stepData.stepMove.push('createPublicVlanIpRange' + idx + index)
}
} catch (e) {
this.messageError = e
@@ -956,7 +971,6 @@
this.setStepStatus(STATUS_FAILED)
stopNow = true
}
-
if (stopNow) {
break
}
@@ -966,10 +980,16 @@
return
}
- if (this.stepData.isTungstenZone) {
- await this.stepCreateTungstenFabricPublicNetwork()
+ if (idx === 0) {
+ await this.stepConfigurePublicTraffic('message.configuring.nsx.public.traffic', 'nsxPublicTraffic', 1)
} else {
- await this.stepConfigureStorageTraffic()
+ if (this.stepData.isTungstenZone) {
+ await this.stepCreateTungstenFabricPublicNetwork()
+ } else if (this.stepData.isNsxZone) {
+ await this.stepAddNsxController()
+ } else {
+ await this.stepConfigureStorageTraffic()
+ }
}
} else if (this.isAdvancedZone && this.sgEnabled) {
if (this.stepData.isTungstenZone) {
@@ -1038,6 +1058,38 @@
this.setStepStatus(STATUS_FAILED)
}
},
+ async stepAddNsxController () {
+ this.setStepStatus(STATUS_FINISH)
+ this.currentStep++
+ this.addStep('message.add.nsx.controller', 'nsx')
+ if (this.stepData.stepMove.includes('nsx')) {
+ await this.stepConfigureStorageTraffic()
+ return
+ }
+ try {
+ if (!this.stepData.stepMove.includes('addNsxController')) {
+ const providerParams = {}
+ providerParams.name = this.prefillContent?.nsxName || ''
+ providerParams.nsxproviderhostname = this.prefillContent?.nsxHostname || ''
+ providerParams.nsxproviderport = this.prefillContent?.nsxPort || ''
+ providerParams.username = this.prefillContent?.username || ''
+ providerParams.password = this.prefillContent?.password || ''
+ providerParams.zoneid = this.stepData.zoneReturned.id
+ providerParams.tier0gateway = this.prefillContent?.tier0Gateway || ''
+ providerParams.edgecluster = this.prefillContent?.edgeCluster || ''
+ providerParams.transportzone = this.prefillContent?.transportZone || ''
+
+ await this.addNsxController(providerParams)
+ this.stepData.stepMove.push('addNsxController')
+ }
+ this.stepData.stepMove.push('nsx')
+ await this.stepConfigureStorageTraffic()
+ } catch (e) {
+ this.messageError = e
+ this.processStatus = STATUS_FAILED
+ this.setStepStatus(STATUS_FAILED)
+ }
+ },
async stepConfigureStorageTraffic () {
let targetNetwork = false
this.prefillContent.physicalNetworks.forEach(physicalNetwork => {
@@ -1048,7 +1100,7 @@
}
})
- if (!targetNetwork) {
+ if (!targetNetwork && !this.isNsxZone) {
await this.stepConfigureGuestTraffic()
return
}
@@ -2180,6 +2232,16 @@
})
})
},
+ addNsxController (args) {
+ return new Promise((resolve, reject) => {
+ api('addNsxController', {}, 'POST', args).then(json => {
+ resolve()
+ }).catch(error => {
+ const message = error.response.headers['x-description']
+ reject(message)
+ })
+ })
+ },
configTungstenFabricService (args) {
return new Promise((resolve, reject) => {
api('configTungstenFabricService', {}, 'POST', args).then(json => {
diff --git a/ui/src/views/infra/zone/ZoneWizardNetworkSetupStep.vue b/ui/src/views/infra/zone/ZoneWizardNetworkSetupStep.vue
index 0ea76ee..24efe44 100644
--- a/ui/src/views/infra/zone/ZoneWizardNetworkSetupStep.vue
+++ b/ui/src/views/infra/zone/ZoneWizardNetworkSetupStep.vue
@@ -51,7 +51,7 @@
:isFixError="isFixError"
/>
<ip-address-range-form
- v-if="steps && steps[currentStep].formKey === 'publicTraffic'"
+ v-if="steps && ['publicTraffic', 'nsxPublicTraffic'].includes(steps[currentStep].formKey)"
@nextPressed="nextPressed"
@backPressed="handleBack"
@fieldsChanged="fieldsChanged"
@@ -60,6 +60,8 @@
:description="publicTrafficDescription[zoneType.toLowerCase()]"
:prefillContent="prefillContent"
:isFixError="isFixError"
+ :forNsx="steps[currentStep].formKey === 'nsxPublicTraffic'"
+ :isNsxZone="isNsxZone"
/>
<static-inputs-form
@@ -75,6 +77,18 @@
/>
<static-inputs-form
+ v-if="steps && steps[currentStep].formKey === 'nsx'"
+ @nextPressed="nextPressed"
+ @backPressed="handleBack"
+ @fieldsChanged="fieldsChanged"
+ @submitLaunchZone="submitLaunchZone"
+ :fields="nsxFields"
+ :prefillContent="prefillContent"
+ :description="nsxSetupDescription"
+ :isFixError="isFixError"
+ />
+
+ <static-inputs-form
v-if="steps && steps[currentStep].formKey === 'pod'"
@nextPressed="nextPressed"
@backPressed="handleBack"
@@ -87,6 +101,7 @@
/>
<div v-if="guestTrafficRangeMode">
+ <div>{{ isNsxZone }}</div>
<static-inputs-form
v-if="steps && steps[currentStep].formKey === 'guestTraffic'"
@nextPressed="nextPressed"
@@ -101,7 +116,7 @@
</div>
<div v-else>
<advanced-guest-traffic-form
- v-if="steps && steps[currentStep].formKey === 'guestTraffic'"
+ v-if="steps && steps[currentStep].formKey === 'guestTraffic' && !isNsxZone"
@nextPressed="nextPressed"
@backPressed="handleBack"
@fieldsChanged="fieldsChanged"
@@ -189,7 +204,18 @@
}
return isTungsten
},
+ isNsxZone () {
+ let isNsx = false
+ if (!this.prefillContent.physicalNetworks) {
+ isNsx = false
+ } else {
+ const nsxIdx = this.prefillContent.physicalNetworks.findIndex(network => network.isolationMethod === 'NSX')
+ isNsx = nsxIdx > -1
+ }
+ return isNsx
+ },
allSteps () {
+ console.log(this.isNsxZone)
const steps = []
steps.push({
title: 'label.physical.network',
@@ -201,6 +227,12 @@
formKey: 'tungsten'
})
}
+ if (this.isNsxZone) {
+ steps.push({
+ title: 'label.nsx.provider',
+ formKey: 'nsx'
+ })
+ }
if (this.havingNetscaler) {
steps.push({
title: 'label.netScaler',
@@ -212,11 +244,18 @@
formKey: 'publicTraffic',
trafficType: 'public'
})
+ if (this.isNsxZone) {
+ steps.push({
+ title: 'label.public.traffic.nsx',
+ formKey: 'nsxPublicTraffic',
+ trafficType: 'public'
+ })
+ }
steps.push({
title: 'label.pod',
formKey: 'pod'
})
- if (!this.isTungstenZone) {
+ if (!this.isTungstenZone && !this.isNsxZone) {
steps.push({
title: 'label.guest.traffic',
formKey: 'guestTraffic',
@@ -347,6 +386,60 @@
}
]
},
+ nsxFields () {
+ const fields = [
+ {
+ title: 'label.nsx.provider.name',
+ key: 'nsxName',
+ placeHolder: 'message.installwizard.tooltip.nsx.provider.name',
+ required: true
+ },
+ {
+ title: 'label.nsx.provider.hostname',
+ key: 'nsxHostname',
+ placeHolder: 'message.installwizard.tooltip.nsx.provider.hostname',
+ required: true
+ },
+ {
+ title: 'label.nsx.provider.port',
+ key: 'nsxPort',
+ placeHolder: 'message.installwizard.tooltip.nsx.provider.port',
+ required: false
+ },
+ {
+ title: 'label.nsx.provider.username',
+ key: 'username',
+ placeHolder: 'message.installwizard.tooltip.nsx.provider.username',
+ required: true
+ },
+ {
+ title: 'label.nsx.provider.password',
+ key: 'password',
+ placeHolder: 'message.installwizard.tooltip.nsx.provider.password',
+ required: true,
+ password: true
+ },
+ {
+ title: 'label.nsx.provider.edgecluster',
+ key: 'edgeCluster',
+ placeHolder: 'message.installwizard.tooltip.nsx.provider.edgecluster',
+ required: true
+ },
+ {
+ title: 'label.nsx.provider.tier0gateway',
+ key: 'tier0Gateway',
+ placeHolder: 'message.installwizard.tooltip.nsx.provider.tier0gateway',
+ required: true
+ },
+ {
+ title: 'label.nsx.provider.transportzone',
+ key: 'transportZone',
+ placeHolder: 'message.installwizard.tooltip.nsx.provider.transportZone',
+ required: true
+ }
+ ]
+ return fields
+ },
guestTrafficFields () {
const fields = [
{
@@ -416,6 +509,7 @@
},
podSetupDescription: 'message.add.pod.during.zone.creation',
tungstenSetupDescription: 'message.infra.setup.tungsten.description',
+ nsxSetupDescription: 'message.infra.setup.nsx.description',
netscalerSetupDescription: 'label.please.specify.netscaler.info',
storageTrafficDescription: 'label.zonewizard.traffictype.storage',
podFields: [
@@ -465,7 +559,7 @@
}
this.scrollToStepActive()
if (this.zoneType === 'Basic' ||
- (this.zoneType === 'Advanced' && this.sgEnabled)) {
+ (this.zoneType === 'Advanced' && (this.sgEnabled || this.isNsxZone))) {
this.skipGuestTrafficStep = false
} else {
this.fetchConfiguration()
diff --git a/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue b/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
index 55bf1eb..1117cb6 100644
--- a/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
+++ b/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
@@ -66,6 +66,8 @@
<a-select-option value="VSP"> VSP </a-select-option>
<a-select-option value="VCS"> VCS </a-select-option>
<a-select-option value="TF"> TF </a-select-option>
+ <a-select-option v-if="hypervisor === 'VMware'" value="NSX"> NSX </a-select-option>
+
<template #suffixIcon>
<a-tooltip
v-if="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
diff --git a/ui/src/views/network/CreateIsolatedNetworkForm.vue b/ui/src/views/network/CreateIsolatedNetworkForm.vue
index c7aa3f8..437630e 100644
--- a/ui/src/views/network/CreateIsolatedNetworkForm.vue
+++ b/ui/src/views/network/CreateIsolatedNetworkForm.vue
@@ -573,6 +573,9 @@
this.selectedNetworkOffering = {}
api('listNetworkOfferings', params).then(json => {
this.networkOfferings = json.listnetworkofferingsresponse.networkoffering
+ if (this.selectedZone.isnsxenabled) {
+ this.networkOfferings = this.networkOfferings.filter(offering => offering.fornsx)
+ }
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
@@ -638,6 +641,7 @@
this.formRef.value.validate().then(() => {
const formRaw = toRaw(this.form)
const values = this.handleRemoveFields(formRaw)
+ console.log(values)
this.actionLoading = true
var params = {
zoneId: this.selectedZone.id,
diff --git a/ui/src/views/network/CreateL2NetworkForm.vue b/ui/src/views/network/CreateL2NetworkForm.vue
index 76695eb..6bb87e1 100644
--- a/ui/src/views/network/CreateL2NetworkForm.vue
+++ b/ui/src/views/network/CreateL2NetworkForm.vue
@@ -18,7 +18,14 @@
<template>
<a-spin :spinning="loading">
<div class="form-layout" v-ctrl-enter="handleSubmit">
- <div class="form">
+ <div v-if="isNsxEnabled">
+ <a-alert type="warning">
+ <template #message>
+ <span v-html="$t('message.l2.network.unsupported.for.nsx')" />
+ </template>
+ </a-alert>
+ </div>
+ <div v-else class="form">
<a-form
:ref="formRef"
:model="form"
@@ -248,7 +255,8 @@
networkOfferings: [],
networkOfferingLoading: false,
selectedNetworkOffering: {},
- isolatePvlanType: 'none'
+ isolatePvlanType: 'none',
+ isNsxEnabled: false
}
},
watch: {
@@ -328,6 +336,7 @@
},
handleZoneChange (zone) {
this.selectedZone = zone
+ this.isNsxEnabled = zone?.isnsxenabled || false
this.updateVPCCheckAndFetchNetworkOfferingData()
},
fetchDomainData () {
diff --git a/ui/src/views/network/CreateNetwork.vue b/ui/src/views/network/CreateNetwork.vue
index 44921f4..2e758bd 100644
--- a/ui/src/views/network/CreateNetwork.vue
+++ b/ui/src/views/network/CreateNetwork.vue
@@ -106,7 +106,6 @@
fetchActionZoneData () {
this.loading = true
const params = {}
- console.log(this.resource)
if (this.$route.name === 'deployVirtualMachine' && this.resource.zoneid) {
params.id = this.resource.zoneid
}
diff --git a/ui/src/views/network/CreateSharedNetworkForm.vue b/ui/src/views/network/CreateSharedNetworkForm.vue
index 93bf693..4fd4237 100644
--- a/ui/src/views/network/CreateSharedNetworkForm.vue
+++ b/ui/src/views/network/CreateSharedNetworkForm.vue
@@ -18,7 +18,14 @@
<template>
<a-spin :spinning="loading">
<div class="form-layout" v-ctrl-enter="handleSubmit">
- <div class="form">
+ <div v-if="isNsxEnabled">
+ <a-alert type="warning">
+ <template #message>
+ <span v-html="$t('message.shared.network.unsupported.for.nsx')" />
+ </template>
+ </a-alert>
+ </div>
+ <div v-else class="form">
<a-form
:ref="formRef"
:model="form"
@@ -546,7 +553,8 @@
minMTU: 68,
setMTU: false,
errorPublicMtu: '',
- errorPrivateMtu: ''
+ errorPrivateMtu: '',
+ isNsxEnabled: false
}
},
watch: {
@@ -665,6 +673,7 @@
this.setMTU = zone?.allowuserspecifyvrmtu || false
this.privateMtuMax = zone?.routerprivateinterfacemaxmtu || 1500
this.publicMtuMax = zone?.routerpublicinterfacemaxmtu || 1500
+ this.isNsxEnabled = zone?.isnsxenabled || false
if (isAdmin()) {
this.fetchPhysicalNetworkData()
} else {
diff --git a/ui/src/views/network/CreateVpc.vue b/ui/src/views/network/CreateVpc.vue
index 64e5cdd..199eac2 100644
--- a/ui/src/views/network/CreateVpc.vue
+++ b/ui/src/views/network/CreateVpc.vue
@@ -155,7 +155,7 @@
</a-form-item>
</a-col>
</a-row>
- <a-form-item v-if="selectedNetworkOfferingSupportsSourceNat" name="sourcenatipaddress" ref="sourcenatipaddress">
+ <a-form-item v-if="selectedNetworkOfferingSupportsSourceNat && !isNsxNetwork" name="sourcenatipaddress" ref="sourcenatipaddress">
<template #label>
<tooltip-label :title="$t('label.routerip')" :tooltip="apiParams.sourcenatipaddress?.description"/>
</template>
@@ -201,7 +201,8 @@
publicMtuMax: 1500,
minMTU: 68,
errorPublicMtu: '',
- selectedVpcOffering: {}
+ selectedVpcOffering: {},
+ isNsxNetwork: false
}
},
beforeCreate () {
@@ -278,6 +279,7 @@
if (zone.id === value) {
this.setMTU = zone?.allowuserspecifyvrmtu || false
this.publicMtuMax = zone?.routerpublicinterfacemaxmtu || 1500
+ this.isNsxNetwork = zone?.isnsxenabled || false
}
}
this.fetchOfferings()
diff --git a/ui/src/views/network/PublicIpResource.vue b/ui/src/views/network/PublicIpResource.vue
index fdbd96a..b958ebe 100644
--- a/ui/src/views/network/PublicIpResource.vue
+++ b/ui/src/views/network/PublicIpResource.vue
@@ -70,6 +70,16 @@
defaultTabs: [{
name: 'details',
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
+ },
+ {
+ name: 'events',
+ resourceType: 'IpAddress',
+ component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))),
+ show: () => { return 'listEvents' in this.$store.getters.apis }
+ },
+ {
+ name: 'comments',
+ component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
}],
activeTab: ''
}
@@ -136,17 +146,23 @@
// VPC IPs don't have firewall
let tabs = this.$route.meta.tabs.filter(tab => tab.name !== 'firewall')
+ const network = await this.fetchNetwork()
+ if (network && network.networkofferingconservemode) {
+ this.tabs = tabs
+ return
+ }
+
this.portFWRuleCount = await this.fetchPortFWRule()
this.loadBalancerRuleCount = await this.fetchLoadBalancerRule()
// VPC IPs with PF only have PF
if (this.portFWRuleCount > 0) {
- tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'portforwarding'))
+ tabs = tabs.filter(tab => tab.name !== 'loadbalancing')
}
// VPC IPs with LB rules only have LB
if (this.loadBalancerRuleCount > 0) {
- tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'loadbalancing'))
+ tabs = tabs.filter(tab => tab.name !== 'portforwarding')
}
this.tabs = tabs
return
@@ -171,6 +187,20 @@
fetchAction () {
this.actions = this.$route.meta.actions || []
},
+ fetchNetwork () {
+ return new Promise((resolve, reject) => {
+ api('listNetworks', {
+ listAll: true,
+ projectid: this.resource.projectid,
+ id: this.resource.associatednetworkid
+ }).then(json => {
+ const network = json.listnetworksresponse?.network?.[0] || null
+ resolve(network)
+ }).catch(e => {
+ reject(e)
+ })
+ })
+ },
fetchPortFWRule () {
return new Promise((resolve, reject) => {
api('listPortForwardingRules', {
@@ -202,6 +232,7 @@
})
},
changeResource (resource) {
+ console.log(resource)
this.resource = resource
},
toggleLoading () {
diff --git a/ui/src/views/network/VpcTiersTab.vue b/ui/src/views/network/VpcTiersTab.vue
index 214ea1a..ddfd8fe 100644
--- a/ui/src/views/network/VpcTiersTab.vue
+++ b/ui/src/views/network/VpcTiersTab.vue
@@ -112,7 +112,7 @@
</template>
</a-pagination>
</a-collapse-panel>
- <a-collapse-panel :header="$t('label.internal.lb')" key="ilb" :style="customStyle" :collapsible="!showIlb(network) ? 'disabled' : null" >
+ <a-collapse-panel :header="$t('label.internal.lb')" key="ilb" :style="customStyle" :collapsible="displayCollapsible[network.id] ? null: 'disabled'" >
<a-button
type="dashed"
style="margin-bottom: 15px; width: 100%"
@@ -436,7 +436,10 @@
}
},
publicLBExists: false,
- setMTU: false
+ setMTU: false,
+ isNsxEnabled: false,
+ isOfferingNatMode: false,
+ displayCollapsible: []
}
},
created () {
@@ -459,8 +462,8 @@
this.form = reactive({})
this.rules = reactive({})
},
- showIlb (network) {
- return network.service.filter(s => (s.name === 'Lb') && (s.capability.filter(c => c.name === 'LbSchemes' && c.value === 'Internal').length > 0)).length > 0 || false
+ showIlb (network, networkOffering) {
+ return ((networkOffering.supportsinternallb && network.service.filter(s => (s.name === 'Lb') && (s.capability.filter(c => c.name === 'LbSchemes' && c.value.split(',').includes('Internal')).length > 0)).length > 0)) || false
},
updateMtu () {
if (this.form.privatemtu > this.privateMtuMax) {
@@ -473,12 +476,14 @@
fetchData () {
this.networks = this.resource.network
this.fetchMtuForZone()
+ this.getVpcNetworkOffering()
if (!this.networks || this.networks.length === 0) {
return
}
for (const network of this.networks) {
this.fetchLoadBalancers(network.id)
this.fetchVMs(network.id)
+ this.updateDisplayCollapsible(network.networkofferingid, network)
}
this.publicLBNetworkExists()
},
@@ -488,6 +493,7 @@
}).then(json => {
this.setMTU = json?.listzonesresponse?.zone?.[0]?.allowuserspecifyvrmtu || false
this.privateMtuMax = json?.listzonesresponse?.zone?.[0]?.routerprivateinterfacemaxmtu || 1500
+ this.isNsxEnabled = json?.listzonesresponse?.zone?.[0]?.isnsxenabled || false
})
},
fetchNetworkAclList () {
@@ -515,6 +521,29 @@
})
})
},
+ updateDisplayCollapsible (offeringId, network) {
+ api('listNetworkOfferings', {
+ id: offeringId
+ }).then(json => {
+ var networkOffering = json.listnetworkofferingsresponse.networkoffering[0]
+ this.displayCollapsible[network.id] = this.showIlb(network, networkOffering)
+ }).catch(e => {
+ this.$notifyError(e)
+ })
+ },
+ getVpcNetworkOffering () {
+ return new Promise((resolve, reject) => {
+ api('listVPCOfferings', {
+ id: this.resource.vpcofferingid
+ }).then(json => {
+ const vpcOffering = json?.listvpcofferingsresponse?.vpcoffering[0]
+ resolve(vpcOffering)
+ this.isOfferingNatMode = vpcOffering?.nsxmode === 'NATTED' || false
+ }).catch(e => {
+ reject(e)
+ })
+ })
+ },
publicLBNetworkExists () {
api('listNetworks', {
vpcid: this.resource.id,
@@ -538,12 +567,15 @@
fetchNetworkOfferings () {
this.fetchLoading = true
this.modalLoading = true
- api('listNetworkOfferings', {
+ const params = {
forvpc: true,
guestiptype: 'Isolated',
- supportedServices: 'SourceNat',
state: 'Enabled'
- }).then(json => {
+ }
+ if (!this.isNsxEnabled) {
+ params.supportedServices = 'SourceNat'
+ }
+ api('listNetworkOfferings', params).then(json => {
this.networkOfferings = json.listnetworkofferingsresponse.networkoffering || []
var filteredOfferings = []
if (this.publicLBExists) {
@@ -556,6 +588,9 @@
}
this.networkOfferings = filteredOfferings
}
+ if (this.isNsxEnabled) {
+ this.networkOfferings = this.networkOfferings.filter(offering => offering.nsxmode === (this.isOfferingNatMode ? 'NATTED' : 'ROUTED'))
+ }
this.form.networkOffering = this.networkOfferings[0].id
}).catch(error => {
this.$notifyError(error)
diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue
index 17359e4..500e3dc 100644
--- a/ui/src/views/offering/AddNetworkOffering.vue
+++ b/ui/src/views/offering/AddNetworkOffering.vue
@@ -41,7 +41,7 @@
v-model:value="form.displaytext"
:placeholder="apiParams.displaytext.description"/>
</a-form-item>
- <a-form-item name="networkrate" ref="networkrate">
+ <a-form-item name="networkrate" ref="networkrate" v-if="!forNsx">
<template #label>
<tooltip-label :title="$t('label.networkrate')" :tooltip="apiParams.networkrate.description"/>
</template>
@@ -60,10 +60,10 @@
<a-radio-button value="isolated">
{{ $t('label.isolated') }}
</a-radio-button>
- <a-radio-button value="l2">
+ <a-radio-button value="l2" v-if="!forNsx">
{{ $t('label.l2') }}
</a-radio-button>
- <a-radio-button value="shared">
+ <a-radio-button value="shared" v-if="!forNsx">
{{ $t('label.shared') }}
</a-radio-button>
</a-radio-group>
@@ -93,7 +93,7 @@
</a-radio-button>
</a-radio-group>
</a-form-item>
- <a-row :gutter="12">
+ <a-row :gutter="12" v-if="!forNsx">
<a-col :md="12" :lg="12">
<a-form-item name="specifyvlan" ref="specifyvlan">
<template #label>
@@ -111,18 +111,65 @@
</a-form-item>
</a-col>
</a-row>
- <a-form-item name="forvpc" ref="forvpc" v-if="guestType === 'isolated'">
+ <a-row :gutter="12">
+ <a-col :md="12" :lg="12">
+ <a-form-item name="forvpc" ref="forvpc" v-if="guestType === 'isolated'">
+ <template #label>
+ <tooltip-label :title="$t('label.vpc')" :tooltip="apiParams.forvpc.description"/>
+ </template>
+ <a-switch v-model:checked="form.forvpc" @change="val => { handleForVpcChange(val) }" />
+ </a-form-item>
+ </a-col>
+ <a-col :md="12" :lg="12">
+ <a-form-item name="fornsx" ref="fornsx" v-if="guestType === 'isolated'">
+ <template #label>
+ <tooltip-label :title="$t('label.nsx')" :tooltip="apiParams.fornsx.description"/>
+ </template>
+ <a-switch v-model:checked="form.fornsx" @change="val => { handleForNsxChange(val) }" />
+ </a-form-item>
+ </a-col>
+ </a-row>
+ <a-row :gutter="12" v-if="forNsx">
+ <a-col :md="12" :lg="12">
+ <a-form-item name="nsxsupportlb" ref="nsxsupportlb" v-if="guestType === 'isolated'">
+ <template #label>
+ <tooltip-label :title="$t('label.nsx.supports.lb')" :tooltip="apiParams.nsxsupportlb.description"/>
+ </template>
+ <a-switch v-model:checked="form.nsxsupportlb" @change="val => { handleNsxLbService(val) }" />
+ </a-form-item>
+ </a-col>
+ <a-col :md="12" :lg="12" v-if="form.nsxsupportlb && form.forvpc">
+ <a-form-item name="nsxsupportsinternallb" ref="nsxsupportsinternallb" v-if="guestType === 'isolated'">
+ <template #label>
+ <tooltip-label :title="$t('label.nsx.supports.internal.lb')" :tooltip="apiParams.nsxsupportsinternallb.description"/>
+ </template>
+ <a-switch v-model:checked="form.nsxsupportsinternallb"/>
+ </a-form-item>
+ </a-col>
+ </a-row>
+ <a-form-item name="nsxmode" ref="nsxmode" v-if="forNsx">
<template #label>
- <tooltip-label :title="$t('label.vpc')" :tooltip="apiParams.forvpc.description"/>
+ <tooltip-label :title="$t('label.nsxmode')" :tooltip="apiParams.nsxmode.description"/>
</template>
- <a-switch v-model:checked="form.forvpc" @change="val => { handleForVpcChange(val) }" />
+ <a-select
+ v-if="showMode"
+ optionFilterProp="label"
+ v-model:value="form.nsxmode"
+ :filterOption="(input, option) => {
+ return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }"
+ :placeholder="apiParams.nsxmode.description">
+ <a-select-option v-for="(opt) in modes" :key="opt.name" :label="opt.name">
+ {{ opt.name }}
+ </a-select-option>
+ </a-select>
</a-form-item>
<a-form-item name="userdatal2" ref="userdatal2" :label="$t('label.userdatal2')" v-if="guestType === 'l2'">
<a-switch v-model:checked="form.userdatal2" />
</a-form-item>
<a-row :gutter="12">
<a-col :md="12" :lg="12">
- <a-form-item name="promiscuousmode" ref="promiscuousmode">
+ <a-form-item name="promiscuousmode" ref="promiscuousmode" v-if="!forNsx">
<template #label>
<tooltip-label :title="$t('label.promiscuousmode')" :tooltip="$t('message.network.offering.promiscuous.mode')"/>
</template>
@@ -140,7 +187,7 @@
</a-radio-button>
</a-radio-group>
</a-form-item>
- <a-form-item name="macaddresschanges" ref="macaddresschanges">
+ <a-form-item name="macaddresschanges" ref="macaddresschanges" v-if="!forNsx">
<template #label>
<tooltip-label :title="$t('label.macaddresschanges')" :tooltip="$t('message.network.offering.mac.address.changes')"/>
</template>
@@ -160,7 +207,7 @@
</a-form-item>
</a-col>
<a-col :md="12" :lg="12">
- <a-form-item name="forgedtransmits" ref="forgedtransmits">
+ <a-form-item name="forgedtransmits" ref="forgedtransmits" v-if="!forNsx">
<template #label>
<tooltip-label :title="$t('label.forgedtransmits')" :tooltip="$t('message.network.offering.forged.transmits')"/>
</template>
@@ -178,7 +225,7 @@
</a-radio-button>
</a-radio-group>
</a-form-item>
- <a-form-item name="maclearning" ref="maclearning">
+ <a-form-item name="maclearning" ref="maclearning" v-if="!forNsx">
<template #label>
<tooltip-label :title="$t('label.maclearning')" :tooltip="$t('message.network.offering.mac.learning')"/>
</template>
@@ -217,6 +264,8 @@
<CheckBoxSelectPair
:resourceKey="item.name"
:checkBoxLabel="item.description"
+ :forNsx="forNsx"
+ :defaultCheckBoxValue="forNsx"
:selectOptions="!supportedServiceLoading ? item.provider: []"
@handle-checkselectpair-change="handleSupportedServiceChange"/>
</a-list-item>
@@ -377,7 +426,7 @@
<a-form-item
name="conservemode"
ref="conservemode"
- v-if="(guestType === 'shared' || guestType === 'isolated') && !isVpcVirtualRouterForAtLeastOneService">
+ v-if="(guestType === 'shared' || guestType === 'isolated') && !isVpcVirtualRouterForAtLeastOneService && !forNsx">
<template #label>
<tooltip-label :title="$t('label.conservemode')" :tooltip="apiParams.conservemode.description"/>
</template>
@@ -512,9 +561,12 @@
selectedDomains: [],
selectedZones: [],
forVpc: false,
+ forNsx: false,
+ showMode: false,
lbType: 'publicLb',
macLearningValue: '',
supportedServices: [],
+ supportedSvcs: [],
supportedServiceLoading: false,
isVirtualRouterForAtLeastOneService: false,
isVpcVirtualRouterForAtLeastOneService: false,
@@ -538,7 +590,33 @@
zones: [],
zoneLoading: false,
ipv6NetworkOfferingEnabled: false,
- loading: false
+ loading: false,
+ modes: [
+ {
+ id: 0,
+ name: 'NATTED'
+ },
+ {
+ id: 1,
+ name: 'ROUTED'
+ }
+ ],
+ VPCVR: {
+ name: 'VPCVirtualRouter',
+ description: 'VPCVirtualRouter',
+ enabled: true
+ },
+ VR: {
+ name: 'VirtualRouter',
+ description: 'VirtualRouter',
+ enabled: true
+ },
+ NSX: {
+ name: 'Nsx',
+ description: 'Nsx',
+ enabled: true
+ },
+ nsxSupportedServicesMap: {}
}
},
beforeCreate () {
@@ -573,7 +651,8 @@
conservemode: true,
availability: 'optional',
egressdefaultpolicy: 'deny',
- ispublic: this.isPublic
+ ispublic: this.isPublic,
+ nsxsupportlb: true
})
this.rules = reactive({
name: [{ required: true, message: this.$t('message.error.name') }],
@@ -761,34 +840,89 @@
this.supportedServiceLoading = true
var supportedServices = this.supportedServices
var self = this
- supportedServices.forEach(function (svc, index) {
- if (svc.name !== 'Connectivity') {
- var providers = svc.provider
- providers.forEach(function (provider, providerIndex) {
- if (self.forVpc) { // *** vpc ***
- var enabledProviders = ['VpcVirtualRouter', 'Netscaler', 'BigSwitchBcf', 'ConfigDrive']
- if (self.lbType === 'internalLb') {
- enabledProviders.push('InternalLbVm')
+ if (!this.forNsx) {
+ supportedServices.forEach(function (svc, index) {
+ if (svc.name !== 'Connectivity') {
+ var providers = svc.provider
+ providers.forEach(function (provider, providerIndex) {
+ if (self.forVpc) { // *** vpc ***
+ var enabledProviders = ['VpcVirtualRouter', 'Netscaler', 'BigSwitchBcf', 'ConfigDrive']
+ if (self.lbType === 'internalLb') {
+ enabledProviders.push('InternalLbVm')
+ }
+ provider.enabled = enabledProviders.includes(provider.name)
+ } else { // *** non-vpc ***
+ provider.enabled = !['InternalLbVm', 'VpcVirtualRouter', 'Nsx'].includes(provider.name)
}
- provider.enabled = enabledProviders.includes(provider.name)
- } else { // *** non-vpc ***
- provider.enabled = !['InternalLbVm', 'VpcVirtualRouter'].includes(provider.name)
- }
- providers[providerIndex] = provider
- })
- svc.provider = providers
- supportedServices[index] = svc
- }
- })
- setTimeout(() => {
+ providers[providerIndex] = provider
+ })
+ svc.provider = providers
+ supportedServices[index] = svc
+ }
+ })
+ setTimeout(() => {
+ self.supportedSvcs = self.supportedServices
+ self.supportedServices = supportedServices
+ self.supportedServiceLoading = false
+ }, 50)
+ } else {
+ supportedServices = this.supportedSvcs
+ supportedServices = supportedServices.filter(svc => {
+ return Object.keys(this.nsxSupportedServicesMap).includes(svc.name)
+ })
+ supportedServices = supportedServices.map(svc => {
+ if (!['Dhcp', 'Dns', 'UserData'].includes(svc.name)) {
+ svc.provider = [this.NSX]
+ }
+ return svc
+ })
+ self.supportedSvcs = self.supportedServices
self.supportedServices = supportedServices
self.supportedServiceLoading = false
- }, 50)
+ }
},
handleForVpcChange (forVpc) {
this.forVpc = forVpc
+ if (this.forNsx) {
+ this.nsxSupportedServicesMap = {
+ Dhcp: this.forVpc ? this.VPCVR : this.VR,
+ Dns: this.forVpc ? this.VPCVR : this.VR,
+ UserData: this.forVpc ? this.VPCVR : this.VR,
+ SourceNat: this.NSX,
+ StaticNat: this.NSX,
+ PortForwarding: this.NSX,
+ Lb: this.NSX,
+ ...(forVpc && { NetworkACL: this.NSX }),
+ ...(!forVpc && { Firewall: this.NSX })
+ }
+ }
this.updateSupportedServices()
},
+ handleForNsxChange (forNsx) {
+ this.forNsx = forNsx
+ this.showMode = forNsx
+ this.nsxSupportedServicesMap = {
+ Dhcp: this.forVpc ? this.VPCVR : this.VR,
+ Dns: this.forVpc ? this.VPCVR : this.VR,
+ UserData: this.forVpc ? this.VPCVR : this.VR,
+ SourceNat: this.NSX,
+ StaticNat: this.NSX,
+ PortForwarding: this.NSX,
+ Lb: this.NSX,
+ ...(this.forVpc && { NetworkACL: this.NSX }),
+ ...(!this.forVpc && { Firewall: this.NSX })
+ }
+ this.fetchSupportedServiceData()
+ },
+ handleNsxLbService (supportLb) {
+ if (!supportLb && 'Lb' in this.nsxSupportedServicesMap) {
+ delete this.nsxSupportedServicesMap.Lb
+ }
+ if (supportLb && !('Lb' in this.nsxSupportedServicesMap)) {
+ this.nsxSupportedServicesMap.Lb = this.NSX
+ }
+ this.fetchSupportedServiceData()
+ },
handleLbTypeChange (lbType) {
this.lbType = lbType
this.updateSupportedServices()
@@ -895,6 +1029,12 @@
if (values.forvpc === true) {
params.forvpc = true
}
+ if (values.fornsx === true) {
+ params.fornsx = true
+ params.nsxmode = values.nsxmode
+ params.nsxsupportlb = values.nsxsupportlb
+ params.nsxsupportsinternallb = values.nsxsupportsinternallb
+ }
if (values.guestiptype === 'shared' || values.guestiptype === 'isolated') {
if (values.conservemode !== true) {
params.conservemode = false
diff --git a/ui/src/views/offering/AddVpcOffering.vue b/ui/src/views/offering/AddVpcOffering.vue
index 738a03a..4ff7759 100644
--- a/ui/src/views/offering/AddVpcOffering.vue
+++ b/ui/src/views/offering/AddVpcOffering.vue
@@ -67,6 +67,41 @@
</a-radio-button>
</a-radio-group>
</a-form-item>
+ <a-row :gutter="12">
+ <a-col :md="12" :lg="12">
+ <a-form-item name="fornsx" ref="fornsx">
+ <template #label>
+ <tooltip-label :title="$t('label.nsx')" :tooltip="apiParams.fornsx.description"/>
+ </template>
+ <a-switch v-model:checked="form.fornsx" @change="val => { handleForNsxChange(val) }" />
+ </a-form-item>
+ </a-col>
+ <a-col :md="12" :lg="12" v-if="forNsx">
+ <a-form-item name="nsxsupportlb" ref="nsxsupportlb">
+ <template #label>
+ <tooltip-label :title="$t('label.nsx.supports.lb')" :tooltip="apiParams.nsxsupportlb.description"/>
+ </template>
+ <a-switch v-model:checked="form.nsxsupportlb" @change="val => { handleNsxLbService(val) }" />
+ </a-form-item>
+ </a-col>
+ </a-row>
+ <a-form-item name="nsxmode" ref="nsxmode" v-if="forNsx">
+ <template #label>
+ <tooltip-label :title="$t('label.nsxmode')" :tooltip="apiParams.nsxmode.description"/>
+ </template>
+ <a-select
+ v-if="showMode"
+ optionFilterProp="label"
+ v-model:value="form.nsxmode"
+ :filterOption="(input, option) => {
+ return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }"
+ :placeholder="apiParams.nsxmode.description">
+ <a-select-option v-for="(opt) in modes" :key="opt.name" :label="opt.name">
+ {{ opt.name }}
+ </a-select-option>
+ </a-select>
+ </a-form-item>
<a-form-item>
<template #label>
<tooltip-label :title="$t('label.supportedservices')" :tooltip="apiParams.supportedservices.description"/>
@@ -78,6 +113,8 @@
<CheckBoxSelectPair
:resourceKey="item.name"
:checkBoxLabel="item.description"
+ :forNsx="forNsx"
+ :defaultCheckBoxValue="forNsx"
:selectOptions="item.provider"
@handle-checkselectpair-change="handleSupportedServiceChange"/>
</a-list-item>
@@ -209,6 +246,8 @@
domainLoading: false,
zones: [],
zoneLoading: false,
+ forNsx: false,
+ showMode: false,
loading: false,
supportedServices: [],
supportedServiceLoading: false,
@@ -218,7 +257,28 @@
connectivityServiceChecked: false,
sourceNatServiceChecked: false,
selectedServiceProviderMap: {},
- ipv6NetworkOfferingEnabled: false
+ ipv6NetworkOfferingEnabled: false,
+ modes: [
+ {
+ id: 0,
+ name: 'NATTED'
+ },
+ {
+ id: 1,
+ name: 'ROUTED'
+ }
+ ],
+ VPCVR: {
+ name: 'VPCVirtualRouter',
+ description: 'VPCVirtualRouter',
+ enabled: true
+ },
+ NSX: {
+ name: 'Nsx',
+ description: 'Nsx',
+ enabled: true
+ },
+ nsxSupportedServicesMap: {}
}
},
beforeCreate () {
@@ -241,7 +301,8 @@
regionlevelvpc: true,
distributedrouter: true,
ispublic: true,
- internetprotocol: this.internetProtocolValue
+ internetprotocol: this.internetProtocolValue,
+ nsxsupportlb: true
})
this.rules = reactive({
name: [{ required: true, message: this.$t('message.error.name') }],
@@ -299,84 +360,153 @@
})
},
fetchSupportedServiceData () {
+ var services = []
+ if (this.forNsx) {
+ services.push({
+ name: 'Dhcp',
+ enabled: true,
+ provider: [
+ { name: 'VpcVirtualRouter' }
+ ]
+ })
+ services.push({
+ name: 'Dns',
+ enabled: true,
+ provider: [{ name: 'VpcVirtualRouter' }]
+ })
+ services.push({
+ name: 'Lb',
+ enabled: true,
+ provider: [{ name: 'Nsx' }]
+ })
+ services.push({
+ name: 'StaticNat',
+ enabled: true,
+ provider: [{ name: 'Nsx' }]
+ })
+ services.push({
+ name: 'SourceNat',
+ enabled: true,
+ provider: [{ name: 'Nsx' }]
+ })
+ services.push({
+ name: 'NetworkACL',
+ enabled: true,
+ provider: [{ name: 'Nsx' }]
+ })
+ services.push({
+ name: 'PortForwarding',
+ enabled: true,
+ provider: [{ name: 'Nsx' }]
+ })
+ services.push({
+ name: 'UserData',
+ enabled: true,
+ provider: [{ name: 'VpcVirtualRouter' }]
+ })
+ } else {
+ services.push({
+ name: 'Dhcp',
+ provider: [
+ { name: 'VpcVirtualRouter' }
+ ]
+ })
+ services.push({
+ name: 'Dns',
+ provider: [{ name: 'VpcVirtualRouter' }]
+ })
+ services.push({
+ name: 'Lb',
+ provider: [
+ { name: 'VpcVirtualRouter' },
+ { name: 'InternalLbVm' }
+ ]
+ })
+ services.push({
+ name: 'Gateway',
+ provider: [
+ { name: 'VpcVirtualRouter' },
+ { name: 'BigSwitchBcf' }
+ ]
+ })
+ services.push({
+ name: 'StaticNat',
+ provider: [
+ { name: 'VpcVirtualRouter' },
+ { name: 'BigSwitchBcf' }
+ ]
+ })
+ services.push({
+ name: 'SourceNat',
+ provider: [
+ { name: 'VpcVirtualRouter' },
+ { name: 'BigSwitchBcf' }
+ ]
+ })
+ services.push({
+ name: 'NetworkACL',
+ provider: [
+ { name: 'VpcVirtualRouter' },
+ { name: 'BigSwitchBcf' }
+ ]
+ })
+ services.push({
+ name: 'PortForwarding',
+ provider: [{ name: 'VpcVirtualRouter' }]
+ })
+ services.push({
+ name: 'UserData',
+ provider: [
+ { name: 'VpcVirtualRouter' },
+ { name: 'ConfigDrive' }
+ ]
+ })
+ services.push({
+ name: 'Vpn',
+ provider: [
+ { name: 'VpcVirtualRouter' },
+ { name: 'BigSwitchBcf' }
+ ]
+ })
+ services.push({
+ name: 'Connectivity',
+ provider: [
+ { name: 'BigSwitchBcf' },
+ { name: 'NiciraNvp' },
+ { name: 'Ovs' },
+ { name: 'JuniperContrailVpcRouter' }
+ ]
+ })
+ }
this.supportedServices = []
- this.supportedServices.push({
- name: 'Dhcp',
- provider: [
- { name: 'VpcVirtualRouter' }
- ]
- })
- this.supportedServices.push({
- name: 'Dns',
- provider: [{ name: 'VpcVirtualRouter' }]
- })
- this.supportedServices.push({
- name: 'Lb',
- provider: [
- { name: 'VpcVirtualRouter' },
- { name: 'InternalLbVm' }
- ]
- })
- this.supportedServices.push({
- name: 'Gateway',
- provider: [
- { name: 'VpcVirtualRouter' },
- { name: 'BigSwitchBcf' }
- ]
- })
- this.supportedServices.push({
- name: 'StaticNat',
- provider: [
- { name: 'VpcVirtualRouter' },
- { name: 'BigSwitchBcf' }
- ]
- })
- this.supportedServices.push({
- name: 'SourceNat',
- provider: [
- { name: 'VpcVirtualRouter' },
- { name: 'BigSwitchBcf' }
- ]
- })
- this.supportedServices.push({
- name: 'NetworkACL',
- provider: [
- { name: 'VpcVirtualRouter' },
- { name: 'BigSwitchBcf' }
- ]
- })
- this.supportedServices.push({
- name: 'PortForwarding',
- provider: [{ name: 'VpcVirtualRouter' }]
- })
- this.supportedServices.push({
- name: 'UserData',
- provider: [
- { name: 'VpcVirtualRouter' },
- { name: 'ConfigDrive' }
- ]
- })
- this.supportedServices.push({
- name: 'Vpn',
- provider: [
- { name: 'VpcVirtualRouter' },
- { name: 'BigSwitchBcf' }
- ]
- })
- this.supportedServices.push({
- name: 'Connectivity',
- provider: [
- { name: 'BigSwitchBcf' },
- { name: 'NiciraNvp' },
- { name: 'Ovs' },
- { name: 'JuniperContrailVpcRouter' }
- ]
- })
- for (var i in this.supportedServices) {
- var serviceName = this.supportedServices[i].name
- var serviceDisplayName = serviceName
- // Sanitize names
- this.supportedServices[i].description = serviceDisplayName
+ for (var i in services) {
+ services[i].description = services[i].name
+ }
+ var self = this
+ setTimeout(() => {
+ self.supportedServices = services
+ self.supportedServiceLoading = false
+ }, 50)
+ },
+ async handleForNsxChange (forNsx) {
+ this.forNsx = forNsx
+ this.showMode = forNsx
+ if (forNsx) {
+ this.form.nsxsupportlb = true
+ this.handleNsxLbService(true)
+ }
+ this.fetchSupportedServiceData()
+ },
+ handleNsxLbService (supportLb) {
+ if (!supportLb) {
+ this.supportedServices = this.supportedServices.filter(svc => svc.name !== 'Lb')
+ }
+ if (supportLb) {
+ this.supportedServices.push({
+ name: 'Lb',
+ enabled: true,
+ provider: [{ name: 'Nsx' }]
+ })
}
},
handleSupportedServiceChange (service, checked, provider) {
@@ -453,9 +583,17 @@
if (values.internetprotocol) {
params.internetprotocol = values.internetprotocol
}
+ if (values.fornsx === true) {
+ params.fornsx = true
+ params.nsxmode = values.nsxmode
+ params.nsxsupportlb = values.nsxsupportlb
+ }
if (this.selectedServiceProviderMap != null) {
var supportedServices = Object.keys(this.selectedServiceProviderMap)
- params.supportedservices = supportedServices.join(',')
+ params.supportedservices = []
+ if (!this.forNsx) {
+ params.supportedservices = supportedServices.join(',')
+ }
for (var k in supportedServices) {
params['serviceProviderList[' + k + '].service'] = supportedServices[k]
params['serviceProviderList[' + k + '].provider'] = this.selectedServiceProviderMap[supportedServices[k]]
@@ -485,7 +623,7 @@
params.serviceofferingid = values.serviceofferingid
}
} else {
- params.supportedservices = ''
+ params.supportedservices = []
}
if (values.enable) {
params.enable = values.enable
diff --git a/utils/src/main/java/com/cloud/utils/net/NetUtils.java b/utils/src/main/java/com/cloud/utils/net/NetUtils.java
index 2c410f9..e45c80e 100644
--- a/utils/src/main/java/com/cloud/utils/net/NetUtils.java
+++ b/utils/src/main/java/com/cloud/utils/net/NetUtils.java
@@ -1119,7 +1119,7 @@
return false;
}
- public static boolean validateGuestCidr(final String cidr) {
+ public static boolean validateGuestCidr(final String cidr, boolean checkCompliance) {
// RFC 1918 - The Internet Assigned Numbers Authority (IANA) has reserved the
// following three blocks of the IP address space for private internets:
// 10.0.0.0 - 10.255.255.255 (10/8 prefix)
@@ -1136,6 +1136,9 @@
return false;
}
+ if (!checkCompliance) {
+ return true;
+ }
for (String block: allowedNetBlocks) {
if (isNetworkAWithinNetworkB(cidr, block)) {
return true;
@@ -1238,9 +1241,9 @@
return true;
}
- public static boolean validateGuestCidrList(final String guestCidrList) {
+ public static boolean validateGuestCidrList(final String guestCidrList, boolean checkCompliance) {
for (final String guestCidr : guestCidrList.split(",")) {
- if (!validateGuestCidr(guestCidr)) {
+ if (!validateGuestCidr(guestCidr, checkCompliance)) {
return false;
}
}
diff --git a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
index 1261c60..ecb3b8c 100644
--- a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
+++ b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
@@ -354,10 +354,10 @@
final String[] invalidCidrs = {"172.33.1.0/16", "100.128.1.0/10"};
for (String cidr: validCidrs) {
- assertTrue(NetUtils.validateGuestCidr(cidr));
+ assertTrue(NetUtils.validateGuestCidr(cidr, true));
}
for (String cidr: invalidCidrs) {
- assertFalse(NetUtils.validateGuestCidr(cidr));
+ assertFalse(NetUtils.validateGuestCidr(cidr, true));
}
}
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java
index efec979..0d4fd2f 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java
@@ -29,6 +29,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.UUID;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -550,7 +551,8 @@
public static Pair<ManagedObjectReference, String> prepareNetwork(String physicalNetwork, String namePrefix, HostMO hostMo, String vlanId, String secondaryvlanId,
Integer networkRateMbps, Integer networkRateMulticastMbps, long timeOutMs, VirtualSwitchType vSwitchType, int numPorts, String gateway,
- boolean configureVServiceInNexus, BroadcastDomainType broadcastDomainType, Map<String, String> vsmCredentials, Map<NetworkOffering.Detail, String> details) throws Exception {
+ boolean configureVServiceInNexus, BroadcastDomainType broadcastDomainType, Map<String, String> vsmCredentials,
+ Map<NetworkOffering.Detail, String> details, String netName) throws Exception {
ManagedObjectReference morNetwork = null;
VmwareContext context = hostMo.getContext();
ManagedObjectReference dcMor = hostMo.getHyperHostDatacenter();
@@ -574,7 +576,7 @@
*/
BroadcastDomainType[] supportedBroadcastTypes =
new BroadcastDomainType[] {BroadcastDomainType.Lswitch, BroadcastDomainType.LinkLocal, BroadcastDomainType.Native, BroadcastDomainType.Pvlan,
- BroadcastDomainType.Storage, BroadcastDomainType.UnDecided, BroadcastDomainType.Vlan};
+ BroadcastDomainType.Storage, BroadcastDomainType.UnDecided, BroadcastDomainType.Vlan, BroadcastDomainType.NSX};
if (!Arrays.asList(supportedBroadcastTypes).contains(broadcastDomainType)) {
throw new InvalidParameterException("BroadcastDomainType " + broadcastDomainType + " it not supported on a VMWare hypervisor at this time.");
@@ -637,6 +639,9 @@
throw new InvalidParameterException("NVP integration port-group " + networkName + " does not exist on the DVS " + dvSwitchName);
}
bWaitPortGroupReady = false;
+ } else if (BroadcastDomainType.NSX == broadcastDomainType && Objects.nonNull(netName)){
+ networkName = netName;
+ bWaitPortGroupReady = false;
} else {
boolean dvSwitchSupportNewPolicies = (isFeatureSupportedInVcenterApiVersion(vcApiVersion, MINIMUM_VCENTER_API_VERSION_WITH_DVS_NEW_POLICIES_SUPPORT)
&& isVersionEqualOrHigher(dvSwitchVersion, MINIMUM_DVS_VERSION_WITH_NEW_POLICIES_SUPPORT));
@@ -1282,7 +1287,8 @@
}
public static Pair<ManagedObjectReference, String> prepareNetwork(String vSwitchName, String namePrefix, HostMO hostMo, String vlanId, Integer networkRateMbps,
- Integer networkRateMulticastMbps, long timeOutMs, boolean syncPeerHosts, BroadcastDomainType broadcastDomainType, String nicUuid, Map<NetworkOffering.Detail, String> nicDetails) throws Exception {
+ Integer networkRateMulticastMbps, long timeOutMs, boolean syncPeerHosts, BroadcastDomainType broadcastDomainType,
+ String nicUuid, Map<NetworkOffering.Detail, String> nicDetails) throws Exception {
HostVirtualSwitch vSwitch;
if (vSwitchName == null) {
@@ -1306,7 +1312,7 @@
*/
BroadcastDomainType[] supportedBroadcastTypes =
new BroadcastDomainType[] {BroadcastDomainType.Lswitch, BroadcastDomainType.LinkLocal, BroadcastDomainType.Native, BroadcastDomainType.Pvlan,
- BroadcastDomainType.Storage, BroadcastDomainType.UnDecided, BroadcastDomainType.Vlan};
+ BroadcastDomainType.Storage, BroadcastDomainType.UnDecided, BroadcastDomainType.Vlan, BroadcastDomainType.NSX};
if (!Arrays.asList(supportedBroadcastTypes).contains(broadcastDomainType)) {
throw new InvalidParameterException("BroadcastDomainType " + broadcastDomainType + " it not supported on a VMWare hypervisor at this time.");
diff --git a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java
index 1c888a0..f129ef7 100644
--- a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java
+++ b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java
@@ -21,14 +21,24 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import com.cloud.hypervisor.vmware.util.VmwareClient;
+import com.cloud.network.Networks;
+import com.cloud.utils.Pair;
+import com.vmware.vim25.DynamicProperty;
+import com.vmware.vim25.ManagedObjectReference;
+import com.vmware.vim25.ObjectContent;
+import com.vmware.vim25.VimPortType;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -61,6 +71,10 @@
@Mock
VmwareContext context;
@Mock
+ ManagedObjectReference mor;
+ @Mock
+ VmwareClient vmwareClient;
+ @Mock
DVPortgroupConfigInfo currentDvPortgroupInfo;
@Mock
DVPortgroupConfigSpec dvPortgroupConfigSpec;
@@ -78,6 +92,12 @@
private ClusterConfigInfoEx clusterConfigInfo;
@Mock
private DatacenterConfigInfo datacenterConfigInfo;
+ @Mock
+ HostMO hostMO;
+ @Mock
+ VimPortType vimService;
+ @Mock
+ ObjectContent ocs;
String vSwitchName;
Integer networkRateMbps;
@@ -90,6 +110,10 @@
@Before
public void setup() throws Exception {
closeable = MockitoAnnotations.openMocks(this);
+ ObjectContent oc = new ObjectContent();
+ when(hostMO.getContext()).thenReturn(context);
+ when(context.getService()).thenReturn(vimService);
+ when(context.getVimClient()).thenReturn(vmwareClient);
when(context.getServiceContent()).thenReturn(serviceContent);
when(serviceContent.getAbout()).thenReturn(aboutInfo);
when(clusterMO.getClusterConfigInfo()).thenReturn(clusterConfigInfo);
@@ -947,4 +971,24 @@
HypervisorHostHelper.setVMHardwareVersion(vmSpec, clusterMO, datacenterMO);
verify(vmSpec, never()).setVersion(any());
}
+
+ @Test
+ public void testPrepareNetwork() throws Exception {
+ String networkName = "D1-A2-Z2-V8-S3";
+ DynamicProperty property = new DynamicProperty();
+ property.setVal(networkName);
+
+ when(hostMO.getHyperHostDatacenter()).thenReturn(mor);
+ when(datacenterMO.getDvSwitchMor(any(String.class))).thenReturn(mor);
+ when(vmwareClient.getDecendentMoRef(nullable(ManagedObjectReference.class), any(String.class), any(String.class))).thenReturn(mor);
+ when(vimService.retrieveProperties(any(), anyList())).thenReturn(List.of(ocs));
+ when(ocs.getPropSet()).thenReturn(List.of(property));
+ when(ocs.getObj()).thenReturn(mor);
+
+ Pair<ManagedObjectReference, String> morNet = HypervisorHostHelper.prepareNetwork("NSX-VDS", "cloud.guest", hostMO, null, null,
+ 200, null, 900000, VirtualSwitchType.VMwareDistributedVirtualSwitch, 1, null,
+ false, Networks.BroadcastDomainType.NSX, null,
+ null, networkName);
+ assertEquals(morNet.second(), networkName);
+ }
}