Dogface2k commented on code in PR #13766:
URL: https://github.com/apache/cloudstack/pull/13766#discussion_r3702074220


##########
plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java:
##########
@@ -196,6 +282,173 @@ public boolean deleteFirewallRules(Network network, 
List<NsxNetworkRule> netRule
         return result.getResult();
     }
 
+    public NsxVpnGatewayResult createVpnGateway(Vpc vpc, String 
localEndpointIp) {
+        CreateNsxVpnGatewayCommand createNsxVpnGatewayCommand = new 
CreateNsxVpnGatewayCommand(vpc.getDomainId(),
+                vpc.getAccountId(), vpc.getZoneId(), vpc.getId(), 
vpc.getName(), localEndpointIp);
+        NsxAnswer result = 
nsxControllerUtils.sendNsxCommandForResult(createNsxVpnGatewayCommand, 
vpc.getZoneId());
+        return new NsxVpnGatewayResult(result.getResult(), 
result.isEndpointMayBeInUse());
+    }
+
+    public boolean deleteVpnGateway(Vpc vpc) {
+        DeleteNsxVpnGatewayCommand deleteNsxVpnGatewayCommand = new 
DeleteNsxVpnGatewayCommand(vpc.getDomainId(),
+                vpc.getAccountId(), vpc.getZoneId(), vpc.getId(), 
vpc.getName());
+        NsxAnswer result = 
nsxControllerUtils.sendNsxCommand(deleteNsxVpnGatewayCommand, vpc.getZoneId());
+        return result.getResult();
+    }
+
+    public boolean createVpnConnection(Vpc vpc, String connectionUuid, String 
peerAddress, String psk,
+                                       String ikePolicy, String espPolicy, 
Long ikeLifetime, Long espLifetime,
+                                       boolean dpdEnabled, String ikeVersion, 
boolean passive, List<String> peerCidrs,
+                                       String vtiLocalIp, String vtiPeerIp, 
int vtiPrefixLength, String localEndpointIp) {
+        CreateNsxVpnConnectionCommand createNsxVpnConnectionCommand = new 
CreateNsxVpnConnectionCommand(vpc.getDomainId(),
+                vpc.getAccountId(), vpc.getZoneId(), vpc.getId(), 
vpc.getName(), connectionUuid, peerAddress, psk,
+                ikePolicy, espPolicy, ikeLifetime, espLifetime, dpdEnabled, 
ikeVersion, passive, peerCidrs,
+                vtiLocalIp, vtiPeerIp, vtiPrefixLength, vpc.getCidr(), 
localEndpointIp);
+        NsxAnswer result = 
nsxControllerUtils.sendNsxCommand(createNsxVpnConnectionCommand, 
vpc.getZoneId());
+        return result.getResult();
+    }
+
+    public boolean deleteVpnConnection(Vpc vpc, String connectionUuid) {
+        DeleteNsxVpnConnectionCommand deleteNsxVpnConnectionCommand = new 
DeleteNsxVpnConnectionCommand(vpc.getDomainId(),
+                vpc.getAccountId(), vpc.getZoneId(), vpc.getId(), 
vpc.getName(), connectionUuid);
+        NsxAnswer result = 
nsxControllerUtils.sendNsxCommand(deleteNsxVpnConnectionCommand, 
vpc.getZoneId());
+        return result.getResult();
+    }
+
+    public boolean updateVpnConnectionState(Vpc vpc, String connectionUuid, 
boolean enabled) {
+        UpdateNsxVpnConnectionStateCommand command = new 
UpdateNsxVpnConnectionStateCommand(vpc.getDomainId(),
+                vpc.getAccountId(), vpc.getZoneId(), vpc.getId(), 
vpc.getName(), connectionUuid, enabled);
+        NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, 
vpc.getZoneId());
+        return result.getResult();
+    }
+
+    public String getVpnConnectionStatus(Vpc vpc, String connectionUuid) {
+        GetNsxVpnSessionStatusCommand getNsxVpnSessionStatusCommand = new 
GetNsxVpnSessionStatusCommand(vpc.getDomainId(),
+                vpc.getAccountId(), vpc.getZoneId(), vpc.getId(), 
vpc.getName(), connectionUuid);
+        NsxAnswer result = 
nsxControllerUtils.sendNsxCommand(getNsxVpnSessionStatusCommand, 
vpc.getZoneId());
+        return result.getDetails();
+    }
+
+    /**
+     * Every management server runs this poller over VPN connections whose 
gateway has persisted
+     * NSX ownership; duplicate polling in a multi-server setup is tolerated, 
as state transitions
+     * are serialized by the row lock in transitionVpnConnectionState
+     */
+    protected class VpnStatusPollTask extends ManagedContextRunnable {
+        @Override
+        protected void runInContext() {
+            try {
+                Set<Long> polledConnectionIds = new HashSet<>();
+                List<Site2SiteVpnConnectionVO> connections = 
site2SiteVpnConnectionDao.listAll();
+                for (Site2SiteVpnConnectionVO connection : connections) {

Review Comment:
   Addressed in 4cea137c21. The poller now queries 
Site2SiteVpnConnectionDao.listByStates(Pending, Connecting, Connected, 
Disconnected), so terminal rows are filtered by SQL instead of loading the 
complete table. NSX ownership remains checked from the persisted IP detail in 
NsxServiceImpl; keeping that plugin-specific marker out of the shared engine 
DAO avoids coupling the schema layer to the NSX plugin. Added DAO criteria 
coverage and an exact poller-query test. Full affected suites pass: 
engine/schema 385/385 and NSX plugin 202/202, with checkstyle clean.



##########
plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java:
##########
@@ -16,49 +16,135 @@
 // under the License.
 package org.apache.cloudstack.service;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 import javax.inject.Inject;
+import javax.naming.ConfigurationException;
 
 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.CreateNsxVpnConnectionCommand;
+import org.apache.cloudstack.agent.api.CreateNsxVpnGatewayCommand;
 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.DeleteNsxNatRuleCommand;
 import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand;
 import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand;
+import org.apache.cloudstack.agent.api.DeleteNsxVpnConnectionCommand;
+import org.apache.cloudstack.agent.api.DeleteNsxVpnGatewayCommand;
+import org.apache.cloudstack.agent.api.GetNsxVpnSessionStatusCommand;
+import org.apache.cloudstack.agent.api.UpdateNsxVpnConnectionStateCommand;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.resource.NsxNetworkRule;
+import org.apache.cloudstack.resourcedetail.dao.UserIpAddressDetailsDao;
 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 com.cloud.alert.AlertManager;
 import com.cloud.network.IpAddress;
 import com.cloud.network.Network;
 import com.cloud.network.SDNProviderNetworkRule;
+import com.cloud.network.Site2SiteVpnConnection;
 import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.Site2SiteVpnConnectionDao;
+import com.cloud.network.dao.Site2SiteVpnConnectionVO;
+import com.cloud.network.dao.Site2SiteVpnGatewayDao;
+import com.cloud.network.dao.Site2SiteVpnGatewayVO;
 import com.cloud.network.nsx.NsxService;
+import com.cloud.network.nsx.NsxVpnGatewayResult;
 import com.cloud.network.vpc.Vpc;
 import com.cloud.network.vpc.VpcVO;
 import com.cloud.network.vpc.dao.VpcDao;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.concurrency.NamedThreadFactory;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-public class NsxServiceImpl implements NsxService, Configurable {
+public class NsxServiceImpl extends ManagerBase implements NsxService, 
Configurable {
+
+    public static final ConfigKey<Integer> NSX_VPN_STATUS_POLL_INTERVAL = new 
ConfigKey<>("Advanced", Integer.class,
+            "nsx.vpn.status.poll.interval", "60",
+            "Interval (in seconds) between two NSX Site-to-Site VPN connection 
status polls; requires a management server restart",
+            false, ConfigKey.Scope.Global);
+
+    protected static final String VPN_SESSION_STATUS_UP = "UP";
+    protected static final String VPN_SESSION_STATUS_DOWN = "DOWN";
+    protected static final String VPN_SESSION_STATUS_DEGRADED = "DEGRADED";
+    protected static final String VPN_SESSION_STATUS_NOT_FOUND = "NOT_FOUND";
+    protected static final int VPN_STATUS_POLL_FAILURE_THRESHOLD = 3;
+    protected static final int VPN_STATUS_POLL_MIN_INTERVAL = 10;
+    protected static final int VPN_STATUS_POLL_DEFAULT_INTERVAL = 60;
+
+    private static final List<Site2SiteVpnConnection.State> VPN_POLLED_STATES 
= List.of(
+            Site2SiteVpnConnection.State.Pending, 
Site2SiteVpnConnection.State.Connecting, Site2SiteVpnConnection.State.Connected,
+            Site2SiteVpnConnection.State.Disconnected);
+
     @Inject
     NsxControllerUtils nsxControllerUtils;
     @Inject
     VpcDao vpcDao;
+    @Inject
+    Site2SiteVpnConnectionDao site2SiteVpnConnectionDao;
+    @Inject
+    Site2SiteVpnGatewayDao site2SiteVpnGatewayDao;
+    @Inject
+    UserIpAddressDetailsDao userIpAddressDetailsDao;
+    @Inject
+    AlertManager alertManager;
 
     protected Logger logger = LogManager.getLogger(getClass());
 
+    private ScheduledExecutorService vpnStatusPollExecutor;
+    private final Map<Long, Integer> vpnStatusPollFailures = new 
ConcurrentHashMap<>();
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws 
ConfigurationException {
+        super.configure(name, params);
+        vpnStatusPollExecutor = Executors.newSingleThreadScheduledExecutor(new 
NamedThreadFactory("Nsx-Vpn-Status-Poll"));
+        return true;
+    }
+
+    @Override
+    public boolean start() {
+        super.start();
+        if (vpnStatusPollExecutor == null) {
+            throw new IllegalStateException("NSX VPN status poller was not 
configured");
+        }
+        Integer configuredInterval = NSX_VPN_STATUS_POLL_INTERVAL.value();
+        int pollInterval = Objects.isNull(configuredInterval) ? 
VPN_STATUS_POLL_DEFAULT_INTERVAL : configuredInterval;
+        if (pollInterval < VPN_STATUS_POLL_MIN_INTERVAL) {
+            logger.warn("The configured value {} of {} is below the minimum of 
{} seconds, using the default of {} seconds",
+                    configuredInterval, NSX_VPN_STATUS_POLL_INTERVAL.key(), 
VPN_STATUS_POLL_MIN_INTERVAL, VPN_STATUS_POLL_DEFAULT_INTERVAL);
+            pollInterval = VPN_STATUS_POLL_DEFAULT_INTERVAL;
+        }
+        vpnStatusPollExecutor.scheduleWithFixedDelay(new VpnStatusPollTask(), 
pollInterval, pollInterval, TimeUnit.SECONDS);
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        if (Objects.nonNull(vpnStatusPollExecutor)) {
+            vpnStatusPollExecutor.shutdownNow();
+        }
+        return super.stop();
+    }

Review Comment:
   Addressed in 4cea137c21. Executor creation now belongs to synchronized 
start(); stop() atomically clears and shuts down the current executor, and a 
subsequent same-JVM start creates and schedules a fresh one. A scheduling 
failure also shuts down the newly created executor before propagating. Added a 
focused start -> stop -> start test that verifies the first executor is shut 
down and the replacement is scheduled and later shut down. Full affected suites 
pass: engine/schema 385/385 and NSX plugin 202/202, with checkstyle clean.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to