private final @NonNull ServiceGroupIdentifier serviceGroupIdent;
private final NetconfTopologySingletonImpl topologySingleton;
- private final RemoteDeviceId remoteDeviceId;
private volatile boolean closed;
+ private volatile boolean isMaster;
+
+ private RemoteDeviceId remoteDeviceId;
NetconfTopologyContext(final String topologyId, final NetconfClientDispatcher clientDispatcher,
final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
@VisibleForTesting
protected NetconfTopologySingletonImpl getTopologySingleton() {
+ // FIXME we have to access topology singleton via this method because of mocking in MountPointEndToEndTest
return topologySingleton;
}
LOG.warn("Instance is already closed.");
return;
}
+ isMaster = true;
getTopologySingleton().becomeTopologyLeader();
}
return FluentFutures.immediateNullFluentFuture();
}
+ void refresh(final @NonNull NetconfTopologySetup setup) {
+ final var node = requireNonNull(setup).getNode();
+ remoteDeviceId = NetconfNodeUtils.toRemoteDeviceId(node.getNodeId(), node.augmentation(NetconfNode.class));
+
+ if (isMaster) {
+ getTopologySingleton().disconnectNode(setup.getNode().getNodeId());
+ getTopologySingleton().refreshSetupConnection(setup, remoteDeviceId);
+ } else {
+ getTopologySingleton().refreshDevice(setup, remoteDeviceId);
+ }
+ }
+
@Override
public ServiceGroupIdentifier getIdentifier() {
return serviceGroupIdent;
switch (rootNode.getModificationType()) {
case SUBTREE_MODIFIED:
LOG.debug("Config for node {} updated", nodeId);
- refreshNetconfDeviceContext(dataModifIdent);
+ refreshNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
break;
case WRITE:
if (contexts.containsKey(dataModifIdent)) {
LOG.debug("RemoteDevice{{}} was already configured, reconfiguring node...", nodeId);
- refreshNetconfDeviceContext(dataModifIdent);
+ refreshNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
} else {
LOG.debug("Config for node {} created", nodeId);
startNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
}
}
- private void refreshNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier) {
+ private void refreshNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
final NetconfTopologyContext context = contexts.get(instanceIdentifier);
- context.closeServiceInstance().addListener(context::instantiateServiceInstance, MoreExecutors.directExecutor());
+ context.refresh(createSetup(instanceIdentifier, node));
}
// ClusterSingletonServiceRegistration registerClusterSingletonService method throws a Runtime exception if there
import akka.actor.ActorRef;
import akka.cluster.Cluster;
+import akka.dispatch.OnComplete;
+import akka.pattern.Patterns;
import akka.util.Timeout;
import io.netty.util.concurrent.EventExecutor;
import org.opendaylight.aaa.encrypt.AAAEncryptionService;
import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
final class NetconfTopologySingletonImpl extends AbstractNetconfTopology implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologySingletonImpl.class);
+
private final RemoteDeviceId remoteDeviceId;
private final NetconfTopologySetup setup;
private final Timeout actorResponseWaitTime;
}
void becomeTopologyFollower() {
+ registerNodeManager();
+ // disconnect device from this node and listen for changes from leader
+ disconnectNode(setup.getNode().getNodeId());
if (masterActorRef != null) {
// was leader before
setup.getActorSystem().stop(masterActorRef);
}
- // disconnect device from this node and listen for changes from leader
- disconnectNode(setup.getNode().getNodeId());
- registerNodeManager();
+ }
+
+ void refreshSetupConnection(final NetconfTopologySetup netconfTopologyDeviceSetup, final RemoteDeviceId device) {
+ Patterns.ask(masterActorRef, new RefreshSetupMasterActorData(netconfTopologyDeviceSetup, device),
+ actorResponseWaitTime).onComplete(
+ new OnComplete<>() {
+ @Override
+ public void onComplete(final Throwable failure, final Object success) {
+ if (failure != null) {
+ LOG.error("Failed to refresh master actor data", failure);
+ return;
+ }
+ LOG.debug("Succeed to refresh Master Action data. Creating Connector...");
+ setupConnection(setup.getNode().getNodeId(), setup.getNode());
+ }
+ }, netconfTopologyDeviceSetup.getActorSystem().dispatcher());
+ }
+
+ void refreshDevice(final NetconfTopologySetup netconfTopologyDeviceSetup, final RemoteDeviceId deviceId) {
+ netconfNodeManager.refreshDevice(netconfTopologyDeviceSetup, deviceId);
}
private void registerNodeManager() {
final var context = super.newNetconfTopologyContext(setup, serviceGroupIdent, actorResponseWaitTime,
deviceActionFact);
final var spiedContext = spy(context);
- final var spiedTopology = spy(context.getTopologySingleton());
+ final var spiedSingleton = spy(context.getTopologySingleton());
doAnswer(invocation -> {
final var spiedFacade = (MasterSalFacade) spy(invocation.callRealMethod());
doReturn(deviceDOMDataBroker).when(spiedFacade)
.newDeviceDataBroker(any(MountPointContext.class), any(NetconfSessionPreferences.class));
masterSalFacadeFuture.set(spiedFacade);
return spiedFacade;
- }).when(spiedTopology).createSalFacade(any(RemoteDeviceId.class), any(boolean.class));
- doReturn(spiedTopology).when(spiedContext).getTopologySingleton();
+ }).when(spiedSingleton).createSalFacade(any(RemoteDeviceId.class), any(boolean.class));
+ doReturn(spiedSingleton).when(spiedContext).getTopologySingleton();
return spiedContext;
}
};
@Test
public void test() throws Exception {
- var masterSalFacade = testMaster();
+ testMaster();
testSlave();
- testMasterDisconnected(masterSalFacade);
+ final MasterSalFacade masterSalFacade = testMasterNodeUpdated();
- // FIXME NETCONF-1046
- // masterSalFacade = testMasterNodeUpdated();
+ testMasterDisconnected(masterSalFacade);
testCleanup();
}
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.opendaylight.aaa.encrypt.AAAEncryptionService;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.util.concurrent.FluentFutures;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
import org.opendaylight.yangtools.yang.common.Uint16;
// Notify of Node 1 replaced and Node 2 subtree modified.
mockContextMap.clear();
+ final NetconfNode updatedNetconfNode1 = new NetconfNodeBuilder(netconfNode1)
+ .setPort(new PortNumber(Uint16.valueOf(33333))).build();
+ final Node updatedNode1 = new NodeBuilder().setNodeId(nodeId1).addAugmentation(updatedNetconfNode1).build();
+
doReturn(WRITE).when(dataObjectModification1).getModificationType();
+ doReturn(updatedNode1).when(dataObjectModification1).getDataAfter();
+
doReturn(SUBTREE_MODIFIED).when(dataObjectModification2).getModificationType();
+ doReturn(node2).when(dataObjectModification2).getDataAfter();
- doReturn(FluentFutures.immediateNullFluentFuture()).when(mockContext1).closeServiceInstance();
- doReturn(FluentFutures.immediateNullFluentFuture()).when(mockContext2).closeServiceInstance();
+ doNothing().when(mockContext1).refresh(any());
+ doNothing().when(mockContext2).refresh(any());
netconfTopologyManager.onDataTreeChanged(Arrays.asList(
new CustomTreeModification(DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
new CustomTreeModification(DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
nodeInstanceId2), dataObjectModification2)));
- verify(mockContext1).instantiateServiceInstance();
- verify(mockContext2).instantiateServiceInstance();
+ ArgumentCaptor<NetconfTopologySetup> mockContext1Setup = ArgumentCaptor.forClass(NetconfTopologySetup.class);
+ verify(mockContext1).refresh(mockContext1Setup.capture());
+ assertEquals(updatedNode1, mockContext1Setup.getValue().getNode());
+
+ verify(mockContext2).refresh(any());
+
verifyNoMoreInteractions(clusterSingletonServiceProvider);
// Notify of Node 1 deleted.