X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fsal-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fconnect%2Fnetconf%2Fsal%2FKeepaliveSalFacade.java;fp=opendaylight%2Fnetconf%2Fsal-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fconnect%2Fnetconf%2Fsal%2FKeepaliveSalFacade.java;h=0000000000000000000000000000000000000000;hb=9ba2b4eca79bcc0e78099b133296801c8d45a6c4;hp=6c29f1d33846df7fb054bdb4eb945881e3d55278;hpb=b2e81149739c87f0ecc2ce7f06448d7a5d3162b8;p=controller.git diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/KeepaliveSalFacade.java b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/KeepaliveSalFacade.java deleted file mode 100644 index 6c29f1d338..0000000000 --- a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/KeepaliveSalFacade.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.connect.netconf.sal; - -import static org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps.getSourceNode; -import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME; -import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME; -import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.controller.md.sal.dom.api.DOMNotification; -import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener; -import org.opendaylight.controller.md.sal.dom.api.DOMRpcException; -import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; -import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; -import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler; -import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator; -import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences; -import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil; -import org.opendaylight.controller.sal.connect.util.RemoteDeviceId; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * SalFacade proxy that invokes keepalive RPCs to prevent session shutdown from remote device - * and to detect incorrect session drops (netconf session is inactive, but TCP/SSH connection is still present). - * The keepalive RPC is a get-config with empty filter. - */ -public final class KeepaliveSalFacade implements RemoteDeviceHandler { - - private static final Logger LOG = LoggerFactory.getLogger(KeepaliveSalFacade.class); - - // 2 minutes keepalive delay by default - private static final long DEFAULT_DELAY = TimeUnit.MINUTES.toSeconds(2); - - private final RemoteDeviceId id; - private final RemoteDeviceHandler salFacade; - private final ScheduledExecutorService executor; - private final long keepaliveDelaySeconds; - private final ResetKeepalive resetKeepaliveTask; - - private volatile NetconfDeviceCommunicator listener; - private volatile ScheduledFuture currentKeepalive; - private volatile DOMRpcService currentDeviceRpc; - - public KeepaliveSalFacade(final RemoteDeviceId id, final RemoteDeviceHandler salFacade, - final ScheduledExecutorService executor, final long keepaliveDelaySeconds) { - this.id = id; - this.salFacade = salFacade; - this.executor = executor; - this.keepaliveDelaySeconds = keepaliveDelaySeconds; - this.resetKeepaliveTask = new ResetKeepalive(); - } - - public KeepaliveSalFacade(final RemoteDeviceId id, final RemoteDeviceHandler salFacade, - final ScheduledExecutorService executor) { - this(id, salFacade, executor, DEFAULT_DELAY); - } - - /** - * Set the netconf session listener whenever ready - * - * @param listener netconf session listener - */ - public void setListener(final NetconfDeviceCommunicator listener) { - this.listener = listener; - } - - /** - * Just cancel current keepalive task. - * If its already started, let it finish ... not such a big deal. - * - * Then schedule next keepalive. - */ - private void resetKeepalive() { - LOG.trace("{}: Resetting netconf keepalive timer", id); - if(currentKeepalive != null) { - currentKeepalive.cancel(false); - } - scheduleKeepalive(); - } - - /** - * Cancel current keepalive and also reset current deviceRpc - */ - private void stopKeepalives() { - if(currentKeepalive != null) { - currentKeepalive.cancel(false); - } - currentDeviceRpc = null; - } - - private void reconnect() { - Preconditions.checkState(listener != null, "%s: Unable to reconnect, session listener is missing", id); - stopKeepalives(); - LOG.info("{}: Reconnecting inactive netconf session", id); - listener.disconnect(); - } - - @Override - public void onDeviceConnected(final SchemaContext remoteSchemaContext, final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) { - this.currentDeviceRpc = deviceRpc; - final DOMRpcService deviceRpc1 = new KeepaliveDOMRpcService(deviceRpc, resetKeepaliveTask); - salFacade.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc1); - - LOG.debug("{}: Netconf session initiated, starting keepalives", id); - scheduleKeepalive(); - } - - private void scheduleKeepalive() { - Preconditions.checkState(currentDeviceRpc != null); - LOG.trace("{}: Scheduling next keepalive in {} {}", id, keepaliveDelaySeconds, TimeUnit.SECONDS); - currentKeepalive = executor.schedule(new Keepalive(), keepaliveDelaySeconds, TimeUnit.SECONDS); - } - - @Override - public void onDeviceDisconnected() { - stopKeepalives(); - salFacade.onDeviceDisconnected(); - } - - @Override - public void onDeviceFailed(final Throwable throwable) { - stopKeepalives(); - salFacade.onDeviceFailed(throwable); - } - - @Override - public void onNotification(final DOMNotification domNotification) { - resetKeepalive(); - salFacade.onNotification(domNotification); - } - - @Override - public void close() { - stopKeepalives(); - salFacade.close(); - } - - // Keepalive RPC static resources - private static final SchemaPath PATH = toPath(NETCONF_GET_CONFIG_QNAME); - private static final ContainerNode KEEPALIVE_PAYLOAD = - NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, getSourceNode(NETCONF_RUNNING_QNAME), NetconfMessageTransformUtil.EMPTY_FILTER); - - /** - * Invoke keepalive RPC and check the response. In case of any received response the keepalive - * is considered successful and schedules next keepalive with a fixed delay. If the response is unsuccessful (no - * response received, or the rcp could not even be sent) immediate reconnect is triggered as netconf session - * is considered inactive/failed. - */ - private class Keepalive implements Runnable, FutureCallback { - - @Override - public void run() { - LOG.trace("{}: Invoking keepalive RPC", id); - - try { - Futures.addCallback(currentDeviceRpc.invokeRpc(PATH, KEEPALIVE_PAYLOAD), this); - } catch (NullPointerException e) { - LOG.debug("{}: Skipping keepalive while reconnecting", id); - // Empty catch block intentional - // Do nothing. The currentDeviceRpc was null and it means we hit the reconnect window and - // attempted to send keepalive while we were reconnecting. Next keepalive will be scheduled - // after reconnect so no action necessary here. - } - } - - @Override - public void onSuccess(final DOMRpcResult result) { - LOG.debug("{}: Keepalive RPC successful with response: {}", id, result.getResult()); - scheduleKeepalive(); - } - - @Override - public void onFailure(@Nonnull final Throwable t) { - LOG.warn("{}: Keepalive RPC failed. Reconnecting netconf session.", id, t); - reconnect(); - } - } - - /** - * Reset keepalive after each RPC response received - */ - private class ResetKeepalive implements com.google.common.util.concurrent.FutureCallback { - @Override - public void onSuccess(@Nullable final DOMRpcResult result) { - // No matter what response we got, rpc-reply or rpc-error, we got it from device so the netconf session is OK - resetKeepalive(); - } - - @Override - public void onFailure(@Nonnull final Throwable t) { - // User/Application RPC failed (The RPC did not reach the remote device or .. TODO what other reasons could cause this ?) - // There is no point in keeping this session. Reconnect. - LOG.warn("{}: Rpc failure detected. Reconnecting netconf session", id, t); - reconnect(); - } - } - - /** - * DOMRpcService proxy that attaches reset-keepalive-task to each RPC invocation. - */ - private static final class KeepaliveDOMRpcService implements DOMRpcService { - - private final DOMRpcService deviceRpc; - private ResetKeepalive resetKeepaliveTask; - - public KeepaliveDOMRpcService(final DOMRpcService deviceRpc, final ResetKeepalive resetKeepaliveTask) { - this.deviceRpc = deviceRpc; - this.resetKeepaliveTask = resetKeepaliveTask; - } - - @Nonnull - @Override - public CheckedFuture invokeRpc(@Nonnull final SchemaPath type, final NormalizedNode input) { - final CheckedFuture domRpcResultDOMRpcExceptionCheckedFuture = deviceRpc.invokeRpc(type, input); - Futures.addCallback(domRpcResultDOMRpcExceptionCheckedFuture, resetKeepaliveTask); - return domRpcResultDOMRpcExceptionCheckedFuture; - } - - @Override - public ListenerRegistration registerRpcListener(@Nonnull final T listener) { - // There is no real communication with the device (yet), no reset here - return deviceRpc.registerRpcListener(listener); - } - } -}