return;
}
+ if (this.session != null || this.nodeState != null) {
+ this.onSessionDown(session, new IllegalStateException("Session is already up with " + session.getRemoteAddress()));
+ return;
+ }
+
this.session = session;
this.nodeState = state;
}
writeNode(pccBuilder, state, topologyAugment);
this.listenerState.init(session);
- this.serverSessionManager.registerRuntimeRootRegistration(this);
+ this.registration = this.serverSessionManager.registerRuntimeRootRegistration(this);
+ if (this.registration == null) {
+ this.onSessionDown(session, new RuntimeException("PCEP Session with " + session.getRemoteAddress() + " fails to register."));
+ return;
+ }
LOG.info("Session with {} attached to topology node {}", session.getRemoteAddress(), state.getNodeId());
}
return this.triggeredResyncInProcess;
}
+ /**
+ * Tear down the given PCEP session. It's OK to call this method even after the session
+ * is already down. It always clear up the current session status.
+ * @param session
+ */
@GuardedBy("this")
- private void tearDown(final PCEPSession session) {
+ private synchronized void tearDown(final PCEPSession session) {
+ Preconditions.checkNotNull(session);
this.serverSessionManager.releaseNodeState(this.nodeState, session, isLspDbPersisted());
this.nodeState = null;
this.session = null;
switch (r.getState()) {
case DONE:
// Done is done, nothing to do
+ LOG.trace("Request {} was done when session went down.", e.getKey());
break;
case UNACKED:
// Peer has not acked: results in failure
private synchronized void unregister() {
if (this.registration != null) {
this.registration.close();
+ LOG.trace("PCEP session {} unregistered successfully.", this.session);
this.registration = null;
+ } else {
+ LOG.trace("PCEP session {} was not registered.", this.session);
}
}
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.controller.config.yang.pcep.topology.provider.ListenerStateRuntimeMXBean;
+import org.opendaylight.controller.config.yang.pcep.topology.provider.ListenerStateRuntimeRegistration;
import org.opendaylight.controller.config.yang.pcep.topology.provider.PCEPTopologyProviderRuntimeMXBean;
import org.opendaylight.controller.config.yang.pcep.topology.provider.PCEPTopologyProviderRuntimeRegistration;
import org.opendaylight.controller.config.yang.pcep.topology.provider.PCEPTopologyProviderRuntimeRegistrator;
}
synchronized void releaseNodeState(final TopologyNodeState nodeState, final PCEPSession session, final boolean persistNode) {
- LOG.debug("Node {} unbound", nodeState.getNodeId());
this.nodes.remove(createNodeId(session.getRemoteAddress()));
- nodeState.released(persistNode);
+ if (nodeState != null) {
+ LOG.debug("Node {} unbound", nodeState.getNodeId());
+ nodeState.released(persistNode);
+ }
}
synchronized TopologyNodeState takeNodeState(final InetAddress address, final TopologySessionListener sessionListener, final boolean retrieveNode) {
}
}
- public void registerRuntimeRootRegistration(final ListenerStateRuntimeMXBean bean) {
+ public ListenerStateRuntimeRegistration registerRuntimeRootRegistration(final ListenerStateRuntimeMXBean bean) {
final PCEPTopologyProviderRuntimeRegistration runtimeReg = this.runtimeRootRegistration.get();
if (runtimeReg != null) {
- runtimeReg.register(bean);
+ final ListenerStateRuntimeRegistration reg = runtimeReg.register(bean);
LOG.trace("Bean {} is successfully registered.", bean.getPeerId());
+ return reg;
}
+ return null;
}
@Override
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.config.yang.pcep.topology.provider.ListenerStateRuntimeMXBean;
+import org.opendaylight.controller.config.yang.pcep.topology.provider.ListenerStateRuntimeRegistration;
+import org.opendaylight.controller.config.yang.pcep.topology.provider.PCEPTopologyProviderRuntimeMXBean;
+import org.opendaylight.controller.config.yang.pcep.topology.provider.PCEPTopologyProviderRuntimeRegistration;
+import org.opendaylight.controller.config.yang.pcep.topology.provider.PCEPTopologyProviderRuntimeRegistrator;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@Mock
private ChannelFuture channelFuture;
+ @Mock
+ protected ListenerStateRuntimeRegistration listenerReg;
+
private T listenerFactory;
private final Open localPrefs = new OpenBuilder().setDeadTimer((short) 30).setKeepalive((short) 10).setSessionId((short) 0).build();
doReturn(mock(ChannelFuture.class)).when(this.clientListener).close();
- this.listenerFactory = (T) ((Class)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
+ doNothing().when(this.listenerReg).close();
+ final PCEPTopologyProviderRuntimeRegistration topologyReg = mock(PCEPTopologyProviderRuntimeRegistration.class);
+ doReturn(this.listenerReg).when(topologyReg).register(any(ListenerStateRuntimeMXBean.class));
+ doNothing().when(topologyReg).close();
+ final PCEPTopologyProviderRuntimeRegistrator registrator = mock(PCEPTopologyProviderRuntimeRegistrator.class);
+ doReturn(topologyReg).when(registrator).register(any(PCEPTopologyProviderRuntimeMXBean.class));
+
+ this.listenerFactory = (T) ((Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
this.manager = new ServerSessionManager(getDataBroker(), TOPO_IID, this.listenerFactory, RPC_TIMEOUT);
+ this.manager.setRuntimeRootRegistartion(registrator);
this.neg = new DefaultPCEPSessionNegotiator(mock(Promise.class), this.clientListener, this.manager.getSessionListener(), (short) 1, 5, this.localPrefs);
this.topologyRpcs = new TopologyRPCs(this.manager);
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createLspTlvs;
-
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import java.net.UnknownHostException;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.yang.pcep.topology.provider.SessionState;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.protocol.pcep.PCEPCloseTermination;
import org.opendaylight.protocol.pcep.PCEPSession;
import org.opendaylight.protocol.pcep.TerminationReason;
@Test
public void testOnSessionDown() throws InterruptedException, ExecutionException {
this.listener.onSessionUp(this.session);
+ verify(this.listenerReg, times(0)).close();
// send request
final Future<RpcResult<AddLspOutput>> futureOutput = this.topologyRpcs.addLsp(createAddLspInput());
this.listener.onSessionDown(this.session, new IllegalArgumentException());
+ verify(this.listenerReg, times(1)).close();
+ final AddLspOutput output = futureOutput.get().getResult();
+ // deal with unsent request after session down
+ assertEquals(FailureType.Unsent, output.getFailure());
+ }
+
+ /**
+ * All the pcep session registration should be closed when the session manager is closed
+ * @throws InterruptedException
+ * @throws ExecutionException
+ * @throws TransactionCommitFailedException
+ */
+ @Test
+ public void testOnServerSessionManagerDown() throws InterruptedException, ExecutionException, TransactionCommitFailedException {
+ this.listener.onSessionUp(this.session);
+ verify(this.listenerReg, times(0)).close();
+ // send request
+ final Future<RpcResult<AddLspOutput>> futureOutput = this.topologyRpcs.addLsp(createAddLspInput());
+ this.manager.close();
+ verify(this.listenerReg, times(1)).close();
+ final AddLspOutput output = futureOutput.get().getResult();
+ // deal with unsent request after session down
+ assertEquals(FailureType.Unsent, output.getFailure());
+ }
+
+ /**
+ * Verify the PCEP session should not be up when server session manager is down,
+ * otherwise it would be a problem when the session is up while it's not registered with session manager
+ * @throws InterruptedException
+ * @throws ExecutionException
+ * @throws TransactionCommitFailedException
+ */
+ @Test
+ public void testOnServerSessionManagerUnstarted() throws InterruptedException, ExecutionException, TransactionCommitFailedException {
+ this.manager.close();
+ // the registration should not be closed since it's never initialized
+ verify(this.listenerReg, times(0)).close();
+ this.listener.onSessionUp(this.session);
+ // verify the session was NOT added to topology
+ assertFalse(getTopology().isPresent());
+ // still, the session should not be registered and thus close() is never called
+ verify(this.listenerReg, times(0)).close();
+ // send request
+ final Future<RpcResult<AddLspOutput>> futureOutput = this.topologyRpcs.addLsp(createAddLspInput());
final AddLspOutput output = futureOutput.get().getResult();
// deal with unsent request after session down
assertEquals(FailureType.Unsent, output.getFailure());
@Test
public void testOnSessionTermination() throws UnknownHostException, InterruptedException, ExecutionException {
this.listener.onSessionUp(this.session);
+ verify(this.listenerReg, times(0)).close();
// create node
this.topologyRpcs.addLsp(createAddLspInput());
// node should be removed after termination
this.listener.onSessionTerminated(this.session, new PCEPCloseTermination(TerminationReason.UNKNOWN));
+ verify(this.listenerReg, times(1)).close();
assertEquals(0, getTopology().get().getNode().size());
}