NSX: Add support to create and delete Load balancer 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..861fa34
--- /dev/null
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxLoadBalancerRuleCommand.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 org.apache.cloudstack.resource.NsxLoadBalancerMember;
+
+import java.util.List;
+
+public class CreateNsxLoadBalancerRuleCommand extends NsxNetworkCommand {
+
+ private final String publicPort;
+ 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 algorithm, String protocol) {
+ super(domainId, accountId, zoneId, networkResourceId, networkResourceName, isResourceVpc);
+ this.lbId = lbId;
+ this.memberList = memberList;
+ this.publicPort = publicPort;
+ this.algorithm = algorithm;
+ this.protocol = protocol;
+ }
+
+
+ public long getLbId() {
+ return lbId;
+ }
+
+ public String getPublicPort() {
+ return publicPort;
+ }
+
+ public List<NsxLoadBalancerMember> getMemberList() {
+ return memberList;
+ }
+
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+}
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..21296af
--- /dev/null
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxLoadBalancerRuleCommand.java
@@ -0,0 +1,40 @@
+// 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;
+
+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; }
+}
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
index e5f49af..4cad50d 100644
--- 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
@@ -38,11 +38,16 @@
}
public NsxNetworkCommand(long domainId, long accountId, long zoneId, Long networkResourceId, String networkResourceName,
- boolean isResourceVpc, Long vmId) {
+ 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;
}
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..ec51822
--- /dev/null
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxLoadBalancerMember.java
@@ -0,0 +1,25 @@
+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
index 5b3daa1..f07b81f 100644
--- 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
@@ -16,6 +16,8 @@
// under the License.
package org.apache.cloudstack.resource;
+import java.util.List;
+
public class NsxNetworkRule {
private long domainId;
private long accountId;
@@ -30,6 +32,8 @@
private String publicPort;
private String privatePort;
private String protocol;
+ private String algorithm;
+ private List<NsxLoadBalancerMember> memberList;
public long getDomainId() {
return domainId;
@@ -135,6 +139,22 @@
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 static final class Builder {
private long domainId;
private long accountId;
@@ -150,6 +170,8 @@
private String publicPort;
private String privatePort;
private String protocol;
+ private String algorithm;
+ private List<NsxLoadBalancerMember> memberList;
public Builder() {
}
@@ -220,6 +242,16 @@
return this;
}
+ public Builder setAlgorithm(String algorithm) {
+ this.algorithm = algorithm;
+ return this;
+ }
+
+ public Builder setMemberList(List<NsxLoadBalancerMember> memberList) {
+ this.memberList = memberList;
+ return this;
+ }
+
public NsxNetworkRule build() {
NsxNetworkRule rule = new NsxNetworkRule();
rule.setDomainId(this.domainId);
@@ -235,6 +267,8 @@
rule.setPrivatePort(this.privatePort);
rule.setProtocol(this.protocol);
rule.setRuleId(this.ruleId);
+ rule.setAlgorithm(this.algorithm);
+ rule.setMemberList(this.memberList);
return rule;
}
}
diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java
index 2a375bc..d3cec1f 100644
--- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java
@@ -36,10 +36,12 @@
import org.apache.cloudstack.NsxAnswer;
import org.apache.cloudstack.StartupNsxCommand;
import org.apache.cloudstack.agent.api.CreateNsxDhcpRelayConfigCommand;
+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.DeleteNsxLoadBalancerRuleCommand;
import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand;
import org.apache.cloudstack.agent.api.DeleteNsxNatRuleCommand;
import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand;
@@ -114,6 +116,10 @@
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 {
return Answer.createUnsupportedCommandAnswer(cmd);
}
@@ -401,6 +407,33 @@
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());
+ } 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(), cmd.getVmId());
+ } 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);
+ }
+
@Override
public boolean start() {
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
index 534030a..736eeec 100644
--- 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
@@ -22,6 +22,10 @@
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.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;
@@ -33,6 +37,11 @@
import com.vmware.nsx_policy.model.DhcpRelayConfig;
import com.vmware.nsx_policy.model.EnforcementPointListResult;
import com.vmware.nsx_policy.model.L4PortSetServiceEntry;
+import com.vmware.nsx_policy.model.LBAppProfileListResult;
+import com.vmware.nsx_policy.model.LBPool;
+import com.vmware.nsx_policy.model.LBPoolMember;
+import com.vmware.nsx_policy.model.LBService;
+import com.vmware.nsx_policy.model.LBVirtualServer;
import com.vmware.nsx_policy.model.LocaleServicesListResult;
import com.vmware.nsx_policy.model.PolicyNatRule;
import com.vmware.nsx_policy.model.Segment;
@@ -41,6 +50,7 @@
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;
@@ -51,15 +61,26 @@
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.utils.NsxControllerUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
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;
+
public class NsxApiClient {
private final Function<Class<? extends Service>, Service> nsxService;
@@ -96,6 +117,19 @@
BYPASS
}
+ public enum LBAlgorithm {
+ ROUND_ROBIN,
+ LEAST_CONNECTION,
+ IP_HASH
+ }
+
+ private enum LBSize {
+ SMALL,
+ MEDIUM,
+ LARGE,
+ XLARGE
+ }
+
public enum RouteAdvertisementType { TIER1_STATIC_ROUTES, TIER1_CONNECTED, TIER1_NAT,
TIER1_LB_VIP, TIER1_LB_SNAT, TIER1_DNS_FORWARDER_IP, TIER1_IPSEC_LOCAL_ENDPOINT
}
@@ -380,6 +414,162 @@
}
}
+ public void createNsxLbServerPool(List<NsxLoadBalancerMember> memberList, String tier1GatewayName, String lbServerPoolName, String algorithm) {
+ for (NsxLoadBalancerMember member : memberList) {
+ try {
+ String serverPoolMemberName = getServerPoolMemberName(tier1GatewayName, member.getVmId());
+ LbPools lbPools = (LbPools) nsxService.apply(LbPools.class);
+ LBPoolMember lbPoolMember = new LBPoolMember.Builder()
+ .setDisplayName(serverPoolMemberName)
+ .setIpAddress(member.getVmIp())
+ .setPort(String.valueOf(member.getPort()))
+ .build();
+ LBPool lbPool = new LBPool.Builder()
+ .setId(lbServerPoolName)
+ .setDisplayName(lbServerPoolName)
+ .setAlgorithm(getLoadBalancerAlgorithm(algorithm))
+ .setMembers(List.of(lbPoolMember))
+ .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);
+ }
+ }
+ }
+
+ public void createNsxLoadBalancer(String tier1GatewayName, long lbId) {
+ 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) {
+ try {
+ String lbServerPoolName = getServerPoolName(tier1GatewayName, lbId);
+ createNsxLbServerPool(memberList, tier1GatewayName, lbServerPoolName, algorithm);
+ createNsxLoadBalancer(tier1GatewayName, lbId);
+
+ 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, long vmId) {
+ try {
+ // Delete associated Virtual servers
+ LbVirtualServers lbVirtualServers = (LbVirtualServers) nsxService.apply(LbVirtualServers.class);
+ String lbVirtualServerName = getVirtualServerName(tier1GatewayName, lbId);
+ lbVirtualServers.delete(lbVirtualServerName, true);
+
+ // Delete LB pool
+ LbPools lbPools = (LbPools) nsxService.apply(LbPools.class);
+ String lbServerPoolName = getServerPoolName(tier1GatewayName, vmId);
+ lbPools.delete(lbServerPoolName, true);
+
+ // Delete load balancer
+ String lbName = getLoadBalancerName(tier1GatewayName);
+ LbServices lbServices = (LbServices) nsxService.apply(LbServices.class);
+ lbServices.delete(lbName, true);
+
+ } 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);
+ }
+ }
+
+ 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) {
try {
Services service = (Services) nsxService.apply(Services.class);
@@ -456,12 +646,4 @@
}
return null;
}
-
- private String getServiceName(String ruleName, String port, String protocol) {
- return ruleName + "-SVC-" + port + "-" +protocol;
- }
-
- private String getServiceEntryName(String ruleName, String port, String protocol) {
- return ruleName + "-SE-" + port + "-" + protocol;
- }
}
diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java
index c8ac091..2eb99fe 100644
--- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java
@@ -24,6 +24,7 @@
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;
@@ -45,6 +46,8 @@
import com.cloud.network.PublicIpAddress;
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;
@@ -52,9 +55,11 @@
import com.cloud.network.element.DhcpServiceProvider;
import com.cloud.network.element.DnsServiceProvider;
import com.cloud.network.element.IpDeployer;
+import com.cloud.network.element.LoadBalancingServiceProvider;
import com.cloud.network.element.PortForwardingServiceProvider;
import com.cloud.network.element.StaticNatServiceProvider;
import com.cloud.network.element.VpcProvider;
+import com.cloud.network.lb.LoadBalancingRule;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.PortForwardingRule;
import com.cloud.network.rules.StaticNat;
@@ -83,12 +88,14 @@
import com.cloud.vm.dao.VMInstanceDao;
import net.sf.ehcache.config.InvalidConfigurationException;
import org.apache.cloudstack.StartupNsxCommand;
+import org.apache.cloudstack.resource.NsxLoadBalancerMember;
import org.apache.cloudstack.resource.NsxNetworkRule;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -99,7 +106,8 @@
@Component
public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsServiceProvider, VpcProvider,
- StaticNatServiceProvider, IpDeployer, PortForwardingServiceProvider, ResourceStateAdapter, Listener {
+ StaticNatServiceProvider, IpDeployer, PortForwardingServiceProvider,
+ LoadBalancingServiceProvider, ResourceStateAdapter, Listener {
@Inject
AccountManager accountMgr;
@@ -125,6 +133,8 @@
VMInstanceDao vmInstanceDao;
@Inject
VpcDao vpcDao;
+ @Inject
+ LoadBalancerVMMapDao lbVmMapDao;
private static final Logger LOGGER = Logger.getLogger(NsxElement.class);
@@ -505,7 +515,6 @@
String privatePort = getPrivatePortRange(rule);
- // TODO: add builder to reduce signature params ; should we pass port range?
NsxNetworkRule networkRule = new NsxNetworkRule.Builder()
.setDomainId(domainId)
.setAccountId(accountId)
@@ -522,9 +531,13 @@
.setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT))
.build();
if (rule.getState() == FirewallRule.State.Add) {
- return nsxService.createPortForwardRule(networkRule);
+ if (!nsxService.createPortForwardRule(networkRule)) {
+ return false;
+ }
} else if (rule.getState() == FirewallRule.State.Revoke) {
- return nsxService.deletePortForwardRule(networkRule);
+ if (!nsxService.deletePortForwardRule(networkRule)) {
+ return false;
+ }
}
}
return true;
@@ -558,4 +571,76 @@
String.valueOf(rule.getSourcePortStart()) :
String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd()));
}
+
+ @Override
+ public boolean applyLBRules(Network network, List<LoadBalancingRule> rules) throws ResourceUnavailableException {
+ for (LoadBalancingRule loadBalancingRule : rules) {
+ if (loadBalancingRule.getState() == FirewallRule.State.Active) {
+ continue;
+ }
+ IPAddressVO publicIp = ipAddressDao.findByIpAndDcId(network.getDataCenterId(),
+ loadBalancingRule.getSourceIp().addr());
+
+ Pair<VpcVO, NetworkVO> vpcOrNetwork = getVpcOrNetwork(network.getVpcId(), network.getId());
+ VpcVO vpc = vpcOrNetwork.first();
+ NetworkVO networkVO = vpcOrNetwork.second();
+ Long networkResourceId = Objects.nonNull(vpc) ? vpc.getId() : networkVO.getId();
+ String networkResourceName = Objects.nonNull(vpc) ? vpc.getName() : networkVO.getName();
+ boolean isVpcResource = Objects.nonNull(vpc);
+ long domainId = Objects.nonNull(vpc) ? vpc.getDomainId() : networkVO.getDomainId();
+ long accountId = Objects.nonNull(vpc) ? vpc.getAccountId() : networkVO.getAccountId();
+ long zoneId = Objects.nonNull(vpc) ? vpc.getZoneId() : networkVO.getDataCenterId();
+ List<NsxLoadBalancerMember> lbMembers = getLoadBalancerMembers(loadBalancingRule);
+ NsxNetworkRule networkRule = new NsxNetworkRule.Builder()
+ .setDomainId(domainId)
+ .setAccountId(accountId)
+ .setZoneId(zoneId)
+ .setNetworkResourceId(networkResourceId)
+ .setNetworkResourceName(networkResourceName)
+ .setVpcResource(isVpcResource)
+ .setMemberList(lbMembers)
+ .setPublicIp(publicIp.getAddress().addr())
+ .setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart()))
+ .setRuleId(loadBalancingRule.getId())
+ .setProtocol(loadBalancingRule.getProtocol().toUpperCase(Locale.ROOT))
+ .setAlgorithm(loadBalancingRule.getAlgorithm())
+ .build();
+ if (loadBalancingRule.getState() == FirewallRule.State.Add) {
+ if (!nsxService.createLbRule(networkRule)) {
+ return false;
+ }
+ } else if (loadBalancingRule.getState() == FirewallRule.State.Revoke) {
+ if (!nsxService.deleteLbRule(networkRule)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @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;
+ }
}
diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java
index c2aef14..5e4d446 100644
--- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java
@@ -23,9 +23,11 @@
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.NsxAnswer;
+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.DeleteNsxLoadBalancerRuleCommand;
import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand;
import org.apache.cloudstack.agent.api.DeleteNsxNatRuleCommand;
import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand;
@@ -124,4 +126,23 @@
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.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();
+ }
}
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
index 8c54547..d0416c8 100644
--- 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
@@ -23,6 +23,7 @@
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.log4j.Logger;
import org.springframework.stereotype.Component;
@@ -90,4 +91,43 @@
String suffix = "-PF";
return getTier1GatewayName(domainId, accountId, zoneId, networkResourceId, isVpcResource) + suffix + ruleId;
}
+
+ public static String getServiceName(String ruleName, String port, String protocol) {
+ return ruleName + "-SVC-" + 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 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/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
index 031f622..69574b2 100644
--- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
@@ -1225,6 +1225,7 @@
new NetworkOfferingVO(name, displayText, TrafficType.Guest, false, false, null,
null, true, Availability.Optional, null, GuestType.Isolated, false,
false, false, false, false, forVpc);
+ defaultNatNSXNetworkOffering.setPublicLb(true);
defaultNatNSXNetworkOffering.setForNsx(true);
defaultNatNSXNetworkOffering.setNsxMode(nsxMode.name());
defaultNatNSXNetworkOffering.setState(NetworkOffering.State.Enabled);