private static final Logger LOG = LoggerFactory.getLogger(DeviceMastership.class);
private final NodeId nodeId;
private final ServiceGroupIdentifier identifier;
- private final ClusterSingletonServiceRegistration clusterSingletonServiceRegistration;
+ private final ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+ private ClusterSingletonServiceRegistration clusterSingletonServiceRegistration;
private boolean deviceMastered;
public DeviceMastership(final NodeId nodeId, final ClusterSingletonServiceProvider clusterSingletonService) {
this.nodeId = nodeId;
this.identifier = ServiceGroupIdentifier.create(nodeId.getValue());
this.deviceMastered = false;
- clusterSingletonServiceRegistration = clusterSingletonService.registerClusterSingletonService(this);
+ this.clusterSingletonServiceProvider = clusterSingletonService;
}
@Override
public void instantiateServiceInstance() {
- LOG.debug("FRM started for: {}", nodeId.getValue());
+ LOG.info("FRM started for: {}", nodeId.getValue());
deviceMastered = true;
}
@Override
public ListenableFuture<Void> closeServiceInstance() {
- LOG.debug("FRM stopped for: {}", nodeId.getValue());
+ LOG.info("FRM stopped for: {}", nodeId.getValue());
deviceMastered = false;
return Futures.immediateFuture(null);
}
return deviceMastered;
}
+ public void registerClusterSingletonService() {
+ LOG.info("Registering FRM as a cluster singleton service listner for service id : {}",getIdentifier());
+ clusterSingletonServiceRegistration = clusterSingletonServiceProvider.registerClusterSingletonService(this);
+ }
}
import com.google.common.annotations.VisibleForTesting;
import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manager for clustering service registrations of {@link DeviceMastership}.
*/
-public class DeviceMastershipManager {
+public class DeviceMastershipManager implements OpendaylightInventoryListener, AutoCloseable{
private static final Logger LOG = LoggerFactory.getLogger(DeviceMastershipManager.class);
private final ClusterSingletonServiceProvider clusterSingletonService;
+ private final ListenerRegistration<?> notifListenerRegistration;
private final ConcurrentHashMap<NodeId, DeviceMastership> deviceMasterships = new ConcurrentHashMap();
- public DeviceMastershipManager(final ClusterSingletonServiceProvider clusterSingletonService) {
+ public DeviceMastershipManager(final ClusterSingletonServiceProvider clusterSingletonService,
+ final NotificationProviderService notificationService) {
this.clusterSingletonService = clusterSingletonService;
+ this.notifListenerRegistration = notificationService.registerNotificationListener(this);
}
public void onDeviceConnected(final NodeId nodeId) {
- LOG.debug("FRM service registered for: {}", nodeId.getValue());
- final DeviceMastership mastership = new DeviceMastership(nodeId, clusterSingletonService);
- deviceMasterships.put(nodeId, mastership);
+ //No-op
}
public void onDeviceDisconnected(final NodeId nodeId) {
- final DeviceMastership mastership = deviceMasterships.remove(nodeId);
- if (mastership != null) {
- mastership.close();
- }
- LOG.debug("FRM service unregistered for: {}", nodeId.getValue());
+ //No-op
}
public boolean isDeviceMastered(final NodeId nodeId) {
ConcurrentHashMap<NodeId, DeviceMastership> getDeviceMasterships() {
return deviceMasterships;
}
+
+ @Override
+ public void onNodeUpdated(NodeUpdated notification) {
+ LOG.debug("NodeUpdate notification received : {}", notification);
+ DeviceMastership membership = deviceMasterships.computeIfAbsent(notification.getId(), device ->
+ new DeviceMastership(notification.getId(), clusterSingletonService));
+ membership.registerClusterSingletonService();
+ }
+
+ @Override
+ public void onNodeConnectorUpdated(NodeConnectorUpdated notification) {
+ //Not published by plugin
+ }
+
+ @Override
+ public void onNodeRemoved(NodeRemoved notification) {
+ LOG.debug("NodeRemoved notification received : {}", notification);
+ NodeId nodeId = notification.getNodeRef().getValue().firstKeyOf(Node.class).getId();
+ final DeviceMastership mastership = deviceMasterships.remove(nodeId);
+ if (mastership != null) {
+ mastership.close();
+ LOG.info("Unregistered FRM cluster singleton service for service id : {}", nodeId.getValue());
+ }
+ }
+
+ @Override
+ public void onNodeConnectorRemoved(NodeConnectorRemoved notification) {
+ //Not published by plugin
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (notifListenerRegistration != null) {
+ notifListenerRegistration.close();
+ }
+ }
}
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
import org.opendaylight.openflowplugin.applications.frm.FlowNodeReconciliation;
private final ForwardingRulesManagerConfig forwardingRulesManagerConfig;
private FlowNodeConnectorInventoryTranslatorImpl flowNodeConnectorInventoryTranslatorImpl;
private final ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+ private final NotificationProviderService notificationService;
private DeviceMastershipManager deviceMastershipManager;
public ForwardingRulesManagerImpl(final DataBroker dataBroker,
final RpcConsumerRegistry rpcRegistry,
final ForwardingRulesManagerConfig config,
- final ClusterSingletonServiceProvider clusterSingletonService) {
+ final ClusterSingletonServiceProvider clusterSingletonService,
+ final NotificationProviderService notificationService) {
this.dataService = Preconditions.checkNotNull(dataBroker, "DataBroker can not be null!");
this.forwardingRulesManagerConfig = Preconditions.checkNotNull(config, "Configuration for FRM cannot be null");
this.clusterSingletonServiceProvider = Preconditions.checkNotNull(clusterSingletonService,
"ClusterSingletonService provider can not be null");
+ this.notificationService = Preconditions.checkNotNull(notificationService, "Notification publisher service is" +
+ " not available");
Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !");
@Override
public void start() {
- this.deviceMastershipManager = new DeviceMastershipManager(clusterSingletonServiceProvider);
+ this.deviceMastershipManager = new DeviceMastershipManager(clusterSingletonServiceProvider,
+ notificationService);
this.flowListener = new FlowForwarder(this, dataService);
this.groupListener = new GroupForwarder(this, dataService);
this.meterListener = new MeterForwarder(this, dataService);
this.nodeListener.close();
this.nodeListener = null;
}
+ if (deviceMastershipManager != null) {
+ deviceMastershipManager.close();
+ }
}
@Override
<reference id="dataBroker" interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"/>
<reference id="rpcRegistry" interface="org.opendaylight.controller.sal.binding.api.RpcProviderRegistry"/>
+ <reference id="notificationService" interface="org.opendaylight.controller.sal.binding.api.NotificationProviderService"/>
<reference id="clusterSingletonService" interface="org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider"/>
<odl:clustered-app-config id="frmConfig"
<argument ref="rpcRegistry"/>
<argument ref="frmConfig"/>
<argument ref="clusterSingletonService"/>
+ <argument ref="notificationService"/>
</bean>
</blueprint>
\ No newline at end of file
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
/**
* Test for {@link DeviceMastershipManager}.
private ClusterSingletonServiceRegistration registration;
@Mock
private ClusterSingletonServiceProvider clusterSingletonService;
+ @Mock
+ private NotificationProviderService notificationService;
@Before
public void setUp() throws Exception {
- deviceMastershipManager = new DeviceMastershipManager(clusterSingletonService);
+ deviceMastershipManager = new DeviceMastershipManager(clusterSingletonService,
+ notificationService);
Mockito.when(clusterSingletonService.registerClusterSingletonService(Matchers.<ClusterSingletonService>any()))
.thenReturn(registration);
}
public void testOnDeviceConnectedAndDisconnected() throws Exception {
// no context
Assert.assertNull(deviceMastershipManager.getDeviceMasterships().get(NODE_ID));
- // create context - register
- deviceMastershipManager.onDeviceConnected(NODE_ID);
+ NodeUpdatedBuilder nodeUpdatedBuilder = new NodeUpdatedBuilder();
+ nodeUpdatedBuilder.setId(NODE_ID);
+ deviceMastershipManager.onNodeUpdated(nodeUpdatedBuilder.build());
DeviceMastership serviceInstance = deviceMastershipManager.getDeviceMasterships().get(NODE_ID);
Assert.assertNotNull(serviceInstance);
- Mockito.verify(clusterSingletonService).registerClusterSingletonService(serviceInstance);
// destroy context - unregister
deviceMastershipManager.onDeviceDisconnected(NODE_ID);
+ Assert.assertNotNull(deviceMastershipManager.getDeviceMasterships().get(NODE_ID));
+ NodeRemovedBuilder nodeRemovedBuilder = new NodeRemovedBuilder();
+ InstanceIdentifier<Node> nodeIId = InstanceIdentifier.create(Nodes.class).
+ child(Node.class, new NodeKey(NODE_ID));
+ nodeRemovedBuilder.setNodeRef(new NodeRef(nodeIId));
+ deviceMastershipManager.onNodeRemoved(nodeRemovedBuilder.build());
Assert.assertNull(deviceMastershipManager.getDeviceMasterships().get(NODE_ID));
- Mockito.verify(registration).close();
}
@Test
public void testIsDeviceMasteredOrSlaved() {
// no context
Assert.assertFalse(deviceMastershipManager.isDeviceMastered(NODE_ID));
- deviceMastershipManager.onDeviceConnected(NODE_ID);
+ NodeUpdatedBuilder nodeUpdatedBuilder = new NodeUpdatedBuilder();
+ nodeUpdatedBuilder.setId(NODE_ID);
+ deviceMastershipManager.onNodeUpdated(nodeUpdatedBuilder.build());
// is master
deviceMastershipManager.getDeviceMasterships().get(NODE_ID).instantiateServiceInstance();
Assert.assertTrue(deviceMastershipManager.isDeviceMastered(NODE_ID));
import org.mockito.runners.MockitoJUnitRunner;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
import org.opendaylight.openflowplugin.applications.frm.impl.DeviceMastershipManager;
ClusterSingletonServiceProvider clusterSingletonService;
@Mock
DeviceMastershipManager deviceMastershipManager;
+ @Mock
+ private NotificationProviderService notificationService;
@Before
public void setUp() {
getDataBroker(),
rpcProviderRegistryMock,
getConfig(),
- clusterSingletonService);
+ clusterSingletonService,
+ notificationService);
forwardingRulesManager.start();
// TODO consider tests rewrite (added because of complicated access)
forwardingRulesManager.setDeviceMastershipManager(deviceMastershipManager);
import org.mockito.runners.MockitoJUnitRunner;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
import org.opendaylight.openflowplugin.applications.frm.impl.DeviceMastershipManager;
ClusterSingletonServiceProvider clusterSingletonService;
@Mock
DeviceMastershipManager deviceMastershipManager;
+ @Mock
+ private NotificationProviderService notificationService;
@Before
public void setUp() {
getDataBroker(),
rpcProviderRegistryMock,
getConfig(),
- clusterSingletonService);
+ clusterSingletonService,
+ notificationService);
forwardingRulesManager.start();
// TODO consider tests rewrite (added because of complicated access)
forwardingRulesManager.setDeviceMastershipManager(deviceMastershipManager);
import org.mockito.runners.MockitoJUnitRunner;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
import org.opendaylight.openflowplugin.applications.frm.impl.DeviceMastershipManager;
ClusterSingletonServiceProvider clusterSingletonService;
@Mock
DeviceMastershipManager deviceMastershipManager;
+ @Mock
+ private NotificationProviderService notificationService;
@Before
public void setUp() {
getDataBroker(),
rpcProviderRegistryMock,
getConfig(),
- clusterSingletonService);
+ clusterSingletonService,
+ notificationService);
forwardingRulesManager.start();
// TODO consider tests rewrite (added because of complicated access)
forwardingRulesManager.setDeviceMastershipManager(deviceMastershipManager);
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
import org.opendaylight.openflowplugin.applications.frm.impl.ForwardingRulesManagerImpl;
RpcProviderRegistry rpcProviderRegistryMock = new RpcProviderRegistryMock();
@Mock
ClusterSingletonServiceProvider clusterSingletonService;
+ @Mock
+ private NotificationProviderService notificationService;
@Before
public void setUp() {
getDataBroker(),
rpcProviderRegistryMock,
getConfig(),
- clusterSingletonService);
+ clusterSingletonService,
+ notificationService);
forwardingRulesManager.start();
}
import org.mockito.runners.MockitoJUnitRunner;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
import org.opendaylight.openflowplugin.applications.frm.impl.DeviceMastershipManager;
ClusterSingletonServiceProvider clusterSingletonService;
@Mock
DeviceMastershipManager deviceMastershipManager;
+ @Mock
+ private NotificationProviderService notificationService;
@Before
public void setUp() {
getDataBroker(),
rpcProviderRegistryMock,
getConfig(),
- clusterSingletonService);
+ clusterSingletonService,
+ notificationService);
forwardingRulesManager.start();
// TODO consider tests rewrite (added because of complicated access)
forwardingRulesManager.setDeviceMastershipManager(deviceMastershipManager);
ListenableFuture<RpcResult<SetRoleOutput>> makeDeviceSlave();
boolean canUseSingleLayerSerialization();
+
+ void sendNodeAddedNotification();
+
+ void sendNodeRemovedNotification();
}
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
-import java.math.BigInteger;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
public class DeviceContextImpl implements DeviceContext, ExtensionConverterProviderKeeper {
private static final Logger LOG = LoggerFactory.getLogger(DeviceContextImpl.class);
private final DeviceManager myManager;
private final DeviceInitializerProvider deviceInitializerProvider;
private final boolean useSingleLayerSerialization;
+ private Boolean isAddNotificationSent = false;
DeviceContextImpl(
@Nonnull final ConnectionContext primaryConnectionContext,
}
}
+ @Override
+ public void sendNodeAddedNotification() {
+ if (!isAddNotificationSent) {
+ isAddNotificationSent = true;
+ NodeUpdatedBuilder builder = new NodeUpdatedBuilder();
+ builder.setId(getDeviceInfo().getNodeId());
+ builder.setNodeRef(new NodeRef(getDeviceInfo().getNodeInstanceIdentifier()));
+ LOG.debug("Publishing node added notification for {}", builder.build());
+ notificationPublishService.offerNotification(builder.build());
+ }
+ }
+
+ @Override
+ public void sendNodeRemovedNotification() {
+ NodeRemovedBuilder builder = new NodeRemovedBuilder();
+ builder.setNodeRef(new NodeRef(getDeviceInfo().getNodeInstanceIdentifier()));
+ LOG.debug("Publishing node removed notification for {}", builder.build());
+ notificationPublishService.offerNotification(builder.build());
+ }
+
@Override
public void processPortStatusMessage(final PortStatusMessage portStatus) {
messageSpy.spyMessage(portStatus.getImplementedInterface(), MessageSpy.STATISTIC_GROUP.FROM_SWITCH_PUBLISHED_SUCCESS);
if (LOG.isDebugEnabled()) {
LOG.debug("Role SLAVE was successfully propagated on device, node {}", deviceInfo.getLOGValue());
}
+ sendNodeAddedNotification();
}
@Override
} else {
this.state = CONTEXT_STATE.TERMINATION;
}
+ sendNodeRemovedNotification();
}
@Override
if (LOG.isDebugEnabled()) {
LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue());
}
+ sendNodeAddedNotification();
}
@Override
if (LOG.isDebugEnabled()) {
LOG.debug("Role SLAVE was successfully propagated on device, node {}", deviceInfo.getLOGValue());
}
+ deviceContext.sendNodeAddedNotification();
}
@Override