Merge "Bug 7910 - Flow with ethernet mask (ff:ff:ff:ff:ff:ff), get stored under alien...
authorAbhijit Kumbhare <abhijit.kumbhare@ericsson.com>
Thu, 9 Mar 2017 18:30:56 +0000 (18:30 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 9 Mar 2017 18:30:56 +0000 (18:30 +0000)
15 files changed:
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OpenFlowPluginProvider.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceContext.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/LifecycleService.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderFactoryImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImplTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImplTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImplTest.java

index bd05be9e448d85ffa8275296aec32b61a672943e..5fcd1b9fa70107539f4b3ddb1cf139c37903854a 100644 (file)
@@ -40,9 +40,8 @@ public interface OFPContext extends AutoCloseable, ClusterLifecycleSupervisor, C
     /**
      * About to stop services in cluster not master anymore or going down
      * @return Future most of services need time to be closed
-     * @param connectionInterrupted true if clustering services stopping by device disconnect
      */
-    default ListenableFuture<Void> stopClusterServices(boolean connectionInterrupted) {
+    default ListenableFuture<Void> stopClusterServices() {
         return Futures.immediateFailedFuture(new RejectedExecutionException("Cannot stop abstract services, check implementation of cluster services"));
     }
 
index b42c9d1a5dc7c9ab96cda02f4013914e09c5f652..63830b4951031968695145d24251193fad34f135 100644 (file)
@@ -14,6 +14,7 @@ import org.opendaylight.controller.md.sal.binding.api.BindingService;
 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.NotificationService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider;
@@ -41,6 +42,9 @@ public interface OpenFlowPluginProvider extends AutoCloseable, BindingService {
 
     void setNotificationPublishService(NotificationPublishService notificationPublishService);
 
+    void setClusteringSingletonServicesProvider(ClusterSingletonServiceProvider singletonServicesProvider);
+
+    void setEntityOwnershipServiceProvider(EntityOwnershipService entityOwnershipService);
     /**
      * Method initializes all DeviceManager, RpcManager and related contexts.
      */
@@ -76,8 +80,6 @@ public interface OpenFlowPluginProvider extends AutoCloseable, BindingService {
 
     void update(Map<String,Object> props);
 
-    void setClusteringSingletonServicesProvider(ClusterSingletonServiceProvider singletonServicesProvider);
-
     void setSkipTableFeatures(boolean skipTableFeatures);
 
     void setBasicTimerDelay(long basicTimerDelay);
index 202abb6ef6381140be8eb7d6f4d1531c6fb2a797..b5aa65fb614fde450934fa9382f2478eb6253f0f 100644 (file)
@@ -149,5 +149,7 @@ public interface DeviceContext extends
     void sendNodeAddedNotification();
 
     void sendNodeRemovedNotification();
+
+    void cleanupDeviceData();
 }
 
index 9698c2551562d7ac968ebe5a50f82dee9e35286d..d55908b211b78f750c94a31e1d91179cde40a882 100644 (file)
@@ -9,6 +9,8 @@
 package org.opendaylight.openflowplugin.api.openflow.device;
 
 import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.openflowplugin.api.openflow.OFPManager;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler;
@@ -24,7 +26,8 @@ public interface DeviceManager extends
         OFPManager,
         DeviceConnectedHandler,
         DeviceDisconnectedHandler,
-        TranslatorLibrarian {
+        TranslatorLibrarian,
+        EntityOwnershipListener {
 
     /**
      * invoked after all services injected
index 931aaf0cc14fa79fecffb351706dc57ce3bd7b7f..57608463dbb8f0c45550b9904401b9e153a9681d 100644 (file)
@@ -9,6 +9,9 @@
 package org.opendaylight.openflowplugin.api.openflow.lifecycle;
 
 import javax.annotation.CheckForNull;
+
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.openflowplugin.api.openflow.OFPContext;
index bc770118636e9759ac67ec2a909aef052e702b41..74944b00e6bc054264dc8a75ea136bd7561e4d4d 100644 (file)
@@ -48,11 +48,16 @@ public class OpenFlowPluginProviderFactoryImpl implements OpenFlowPluginProvider
                 providerConfig.getThreadPoolMaxThreads().getValue(),
                 providerConfig.getThreadPoolTimeout());
 
+        //Set services
         openflowPluginProvider.setSwitchConnectionProviders(switchConnectionProviders);
         openflowPluginProvider.setDataBroker(dataBroker);
         openflowPluginProvider.setRpcProviderRegistry(rpcRegistry);
         openflowPluginProvider.setNotificationProviderService(notificationService);
         openflowPluginProvider.setNotificationPublishService(notificationPublishService);
+        openflowPluginProvider.setEntityOwnershipServiceProvider(entityOwnershipService);
+        openflowPluginProvider.setClusteringSingletonServicesProvider(singletonServiceProvider);
+
+        //Set config parameters
         openflowPluginProvider.setSwitchFeaturesMandatory(providerConfig.isSwitchFeaturesMandatory());
         openflowPluginProvider.setFlowRemovedNotification(providerConfig.isEnableFlowRemovedNotification());
         openflowPluginProvider.setIsStatisticsRpcEnabled(providerConfig.isIsStatisticsRpcEnabled());
@@ -60,7 +65,6 @@ public class OpenFlowPluginProviderFactoryImpl implements OpenFlowPluginProvider
         openflowPluginProvider.setBarrierInterval(providerConfig.getBarrierIntervalTimeoutLimit().getValue());
         openflowPluginProvider.setEchoReplyTimeout(providerConfig.getEchoReplyTimeout().getValue());
         openflowPluginProvider.setStatisticsPollingOn(providerConfig.isIsStatisticsPollingOn());
-        openflowPluginProvider.setClusteringSingletonServicesProvider(singletonServiceProvider);
         openflowPluginProvider.setSkipTableFeatures(providerConfig.isSkipTableFeatures());
         openflowPluginProvider.setBasicTimerDelay(providerConfig.getBasicTimerDelay().getValue());
         openflowPluginProvider.setMaximumTimerDelay(providerConfig.getMaximumTimerDelay().getValue());
index 08ccb34e2399e42eb3d6044dd6dae7cee41ed52d..b3953549589aa50163d7d62a15e7d03ad6a3da17 100644 (file)
@@ -31,6 +31,7 @@ import javax.management.ObjectName;
 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.NotificationService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider;
@@ -86,6 +87,8 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
     private ConnectionManager connectionManager;
     private NotificationService notificationProviderService;
     private NotificationPublishService notificationPublishService;
+    private EntityOwnershipService entityOwnershipService;
+    private ClusterSingletonServiceProvider singletonServicesProvider;
     private ExtensionConverterManager extensionConverterManager;
     private DataBroker dataBroker;
     private Collection<SwitchConnectionProvider> switchConnectionProviders;
@@ -98,7 +101,6 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
     private long maximumTimerDelay;
 
     private final ThreadPoolExecutor threadPool;
-    private ClusterSingletonServiceProvider singletonServicesProvider;
 
     public OpenFlowPluginProviderImpl(final long rpcRequestsQuota,
                                       final long globalNotificationQuota,
@@ -183,6 +185,11 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
         this.singletonServicesProvider = singletonServicesProvider;
     }
 
+    @Override
+    public void setEntityOwnershipServiceProvider(EntityOwnershipService entityOwnershipService) {
+        this.entityOwnershipService = entityOwnershipService;
+    }
+
     @Override
     public void setSkipTableFeatures(final boolean skipTableFeatures){
             this.skipTableFeatures = skipTableFeatures;
@@ -246,10 +253,11 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
                 getMessageIntelligenceAgency(),
                 isFlowRemovedNotificationOn,
                 singletonServicesProvider,
-                notificationPublishService,
+                entityOwnershipService,
                 hashedWheelTimer,
                 convertorManager,
-                skipTableFeatures);
+                skipTableFeatures,
+                notificationPublishService);
 
         ((ExtensionConverterProviderKeeper) deviceManager).setExtensionConverterProvider(extensionConverterManager);
 
index 19c33d64ac5e0a58ecc0681d93a6b33ab598feeb..f87bbaa8106762139d9e20a6ff4e6c72d32bce2d 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Verify;
 import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.JdkFutureAdapters;
@@ -636,52 +637,25 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
     }
 
     @Override
-    public ListenableFuture<Void> stopClusterServices(boolean connectionInterrupted) {
+    public ListenableFuture<Void> stopClusterServices() {
         final ListenableFuture<Void> deactivateTxManagerFuture = initialized
                 ? transactionChainManager.deactivateTransactionManager()
                 : Futures.immediateFuture(null);
 
+        final boolean connectionInterrupted =
+                this.getPrimaryConnectionContext()
+                        .getConnectionState()
+                        .equals(ConnectionContext.CONNECTION_STATE.RIP);
         if (!connectionInterrupted) {
-            final ListenableFuture<Void> makeSlaveFuture = Futures.transform(makeDeviceSlave(), new Function<RpcResult<SetRoleOutput>, Void>() {
-                @Nullable
-                @Override
-                public Void apply(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
-                    return null;
-                }
-            });
-
-            Futures.addCallback(makeSlaveFuture, new FutureCallback<Void>() {
-                @Override
-                public void onSuccess(@Nullable Void aVoid) {
-                    if (LOG.isDebugEnabled()) {
-                        LOG.debug("Role SLAVE was successfully propagated on device, node {}", deviceInfo.getLOGValue());
-                    }
-                    sendNodeAddedNotification();
-                }
-
-                @Override
-                public void onFailure(final Throwable throwable) {
-                    LOG.warn("Was not able to set role SLAVE to device on node {} ", deviceInfo.getLOGValue());
-                    LOG.trace("Error occurred on device role setting, probably connection loss: ", throwable);
-                }
-            });
-
-            return Futures.transform(deactivateTxManagerFuture, new AsyncFunction<Void, Void>() {
-                @Override
-                public ListenableFuture<Void> apply(Void aVoid) throws Exception {
-                    // Add fallback to remove device from operational DS if setting slave fails
-                    return Futures.withFallback(makeSlaveFuture, t ->
-                            myManager.removeDeviceFromOperationalDS(deviceInfo));
-                }
-            });
-        } else {
-            return Futures.transform(deactivateTxManagerFuture, new AsyncFunction<Void, Void>() {
-                @Override
-                public ListenableFuture<Void> apply(Void aVoid) throws Exception {
-                    return myManager.removeDeviceFromOperationalDS(deviceInfo);
-                }
-            });
+            LOG.info("This controller instance is now acting as a non-owner for node {}", deviceInfo.getLOGValue());
         }
+
+        return deactivateTxManagerFuture;
+    }
+
+    @Override
+    public void cleanupDeviceData() {
+        myManager.removeDeviceFromOperationalDS(deviceInfo);
     }
 
     @Override
index a45511ec387ec051af42ff71c9115c0b27c8808a..3595e6af9446389b62fea74afd381c278c71adb1 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.openflowplugin.impl.device;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Verify;
 import com.google.common.collect.Iterators;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
@@ -31,6 +32,9 @@ 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.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
@@ -54,13 +58,18 @@ import org.opendaylight.openflowplugin.impl.connection.OutboundQueueProviderImpl
 import org.opendaylight.openflowplugin.impl.device.listener.OpenflowProtocolListenerFullImpl;
 import org.opendaylight.openflowplugin.impl.lifecycle.LifecycleServiceImpl;
 import org.opendaylight.openflowplugin.impl.services.SalRoleServiceImpl;
+import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
 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.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -70,9 +79,11 @@ import org.slf4j.LoggerFactory;
 public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProviderKeeper {
 
     private static final Logger LOG = LoggerFactory.getLogger(DeviceManagerImpl.class);
+    private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
 
     private final long globalNotificationQuota;
     private final boolean switchFeaturesMandatory;
+    private final EntityOwnershipListenerRegistration eosListenerRegistration;
     private boolean isFlowRemovedNotificationOn;
     private boolean skipTableFeatures;
     private static final int SPY_RATE = 10;
@@ -84,6 +95,7 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
     private DeviceTerminationPhaseHandler deviceTerminPhaseHandler;
 
     private final ConcurrentMap<DeviceInfo, DeviceContext> deviceContexts = new ConcurrentHashMap<>();
+    private final ConcurrentMap<DeviceInfo, DeviceContext> removeddeviceContexts = new ConcurrentHashMap<>();
     private final ConcurrentMap<DeviceInfo, LifecycleService> lifecycleServices = new ConcurrentHashMap<>();
 
     private long barrierIntervalNanos;
@@ -92,6 +104,7 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
     private ExtensionConverterProvider extensionConverterProvider;
     private ScheduledThreadPoolExecutor spyPool;
     private final ClusterSingletonServiceProvider singletonServiceProvider;
+    private final EntityOwnershipService entityOwnershipService;
     private final NotificationPublishService notificationPublishService;
     private final MessageSpy messageSpy;
     private final HashedWheelTimer hashedWheelTimer;
@@ -104,25 +117,15 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
                              final MessageSpy messageSpy,
                              final boolean isFlowRemovedNotificationOn,
                              final ClusterSingletonServiceProvider singletonServiceProvider,
-                             final NotificationPublishService notificationPublishService,
+                             final EntityOwnershipService entityOwnershipService,
                              final HashedWheelTimer hashedWheelTimer,
                              final ConvertorExecutor convertorExecutor,
-                             final boolean skipTableFeatures) {
+                             final boolean skipTableFeatures,
+                             final NotificationPublishService notificationPublishService) {
 
-        this.dataBroker = dataBroker;
-
-        /* merge empty nodes to oper DS to predict any problems with missing parent for Node */
-        final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-        final NodesBuilder nodesBuilder = new NodesBuilder();
-        nodesBuilder.setNode(Collections.<Node>emptyList());
-        tx.merge(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class), nodesBuilder.build());
-        try {
-            tx.submit().get();
-        } catch (ExecutionException | InterruptedException e) {
-            LOG.error("Creation of node failed.", e);
-            throw new IllegalStateException(e);
-        }
 
+        this.dataBroker = dataBroker;
+        this.entityOwnershipService = entityOwnershipService;
         this.switchFeaturesMandatory = switchFeaturesMandatory;
         this.globalNotificationQuota = globalNotificationQuota;
         this.isFlowRemovedNotificationOn = isFlowRemovedNotificationOn;
@@ -135,6 +138,21 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
         this.singletonServiceProvider = singletonServiceProvider;
         this.notificationPublishService = notificationPublishService;
         this.messageSpy = messageSpy;
+
+        this.eosListenerRegistration = Verify.verifyNotNull(entityOwnershipService.registerListener
+                (SERVICE_ENTITY_TYPE, this));
+
+        /* merge empty nodes to oper DS to predict any problems with missing parent for Node */
+        final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+        final NodesBuilder nodesBuilder = new NodesBuilder();
+        nodesBuilder.setNode(Collections.<Node>emptyList());
+        tx.merge(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class), nodesBuilder.build());
+        try {
+            tx.submit().get();
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("Creation of node failed.", e);
+            throw new IllegalStateException(e);
+        }
     }
 
 
@@ -254,6 +272,15 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
         Optional.ofNullable(spyPool).ifPresent(ScheduledThreadPoolExecutor::shutdownNow);
         spyPool = null;
 
+        if (Objects.nonNull(eosListenerRegistration)) {
+            try {
+                LOG.debug("Closing entity ownership listener");
+                eosListenerRegistration.close();
+            } catch (Exception e) {
+                LOG.debug("Failed to close entity ownership listener registration with exception",e);
+            }
+        }
+
     }
 
     @Override
@@ -368,28 +395,34 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
 
     @Override
     public CheckedFuture<Void, TransactionCommitFailedException> removeDeviceFromOperationalDS(final DeviceInfo deviceInfo) {
+        return removeDeviceFromOperationalDS(deviceInfo.getNodeInstanceIdentifier(), deviceInfo.getLOGValue());
+    }
+
+    private CheckedFuture<Void, TransactionCommitFailedException> removeDeviceFromOperationalDS(
+            final KeyedInstanceIdentifier<Node, NodeKey> nodeIid, final String nodeName) {
+        Preconditions.checkNotNull(nodeIid, "Node IID must not be null");
+
         final WriteTransaction delWtx = dataBroker.newWriteOnlyTransaction();
-        delWtx.delete(LogicalDatastoreType.OPERATIONAL, deviceInfo.getNodeInstanceIdentifier());
+        delWtx.delete(LogicalDatastoreType.OPERATIONAL, nodeIid);
         final CheckedFuture<Void, TransactionCommitFailedException> delFuture = delWtx.submit();
 
         Futures.addCallback(delFuture, new FutureCallback<Void>() {
             @Override
             public void onSuccess(final Void result) {
                 if (LOG.isDebugEnabled()) {
-                    LOG.debug("Delete Node {} was successful", deviceInfo.getLOGValue());
+                    LOG.debug("Delete Node {} was successful", nodeName);
                 }
             }
 
             @Override
             public void onFailure(@Nonnull final Throwable t) {
-                LOG.warn("Delete node {} failed with exception {}", deviceInfo.getLOGValue(), t);
+                LOG.warn("Delete node {} failed with exception {}", nodeName, t);
             }
         });
 
         return delFuture;
     }
 
-
     private void addCallbackToDeviceInitializeToSlave(final DeviceInfo deviceInfo, final DeviceContext deviceContext, final LifecycleService lifecycleService) {
         Futures.addCallback(deviceContext.makeDeviceSlave(), new FutureCallback<RpcResult<SetRoleOutput>>() {
             @Override
@@ -427,10 +460,38 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
     }
 
     public void onDeviceRemoved(DeviceInfo deviceInfo) {
-        deviceContexts.remove(deviceInfo);
+        DeviceContext deviceContext = deviceContexts.remove(deviceInfo);
+        removeddeviceContexts.putIfAbsent(deviceInfo, deviceContext);
         LOG.debug("Device context removed for node {}", deviceInfo.getLOGValue());
 
         lifecycleServices.remove(deviceInfo);
         LOG.debug("Lifecycle service removed for node {}", deviceInfo.getLOGValue());
     }
+
+    @Override
+    public void ownershipChanged(EntityOwnershipChange entityOwnershipChange) {
+        if (!entityOwnershipChange.hasOwner()) {
+            final YangInstanceIdentifier yii = entityOwnershipChange.getEntity().getId();
+            final YangInstanceIdentifier.NodeIdentifierWithPredicates niiwp =
+                    (YangInstanceIdentifier.NodeIdentifierWithPredicates) yii.getLastPathArgument();
+            String entityName =  niiwp.getKeyValues().values().iterator().next().toString();
+            LOG.info("Entity ownership changed for device : {} : {}", entityName, entityOwnershipChange);
+
+            if (entityName != null ){
+                if (!removeddeviceContexts.isEmpty()) {
+                    for (DeviceInfo device : removeddeviceContexts.keySet()) {
+                        if (device.getNodeId().getValue().equals(entityName)) {
+                            LOG.info("Cleaning up operational data of the node : {}", entityName);
+                            // No owner present for the entity, clean up the data and remove it from
+                            // removed context.
+                            removeddeviceContexts.remove(device).cleanupDeviceData();
+                            return;
+                        }
+                    }
+                }
+                removeDeviceFromOperationalDS(DeviceStateUtil.createNodeInstanceIdentifier(new NodeId(entityName)),
+                        entityName);
+            }
+        }
+    }
 }
index 7522fe54b08f6c1d8339a449e3d4cb2b3dbe3e95..c4ac4c7d6335e8b4f8d3f01010b5ad18e56fc1aa 100644 (file)
@@ -18,6 +18,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import javax.annotation.Nullable;
+
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
@@ -35,15 +36,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class LifecycleServiceImpl implements LifecycleService {
-
     private static final Logger LOG = LoggerFactory.getLogger(LifecycleServiceImpl.class);
+
+    private final List<DeviceRemovedHandler> deviceRemovedHandlers = new ArrayList<>();
+    private volatile CONTEXT_STATE state = CONTEXT_STATE.INITIALIZATION;
     private DeviceContext deviceContext;
     private RpcContext rpcContext;
     private StatisticsContext statContext;
     private ClusterSingletonServiceRegistration registration;
     private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
-    private final List<DeviceRemovedHandler> deviceRemovedHandlers = new ArrayList<>();
-    private volatile CONTEXT_STATE state = CONTEXT_STATE.INITIALIZATION;
 
 
     @Override
@@ -57,17 +58,12 @@ public class LifecycleServiceImpl implements LifecycleService {
 
     @Override
     public ListenableFuture<Void> closeServiceInstance() {
-        final boolean connectionInterrupted =
-                this.deviceContext
-                        .getPrimaryConnectionContext()
-                        .getConnectionState()
-                        .equals(ConnectionContext.CONNECTION_STATE.RIP);
 
         // Chain all jobs that will stop our services
         final List<ListenableFuture<Void>> futureList = new ArrayList<>();
-        futureList.add(statContext.stopClusterServices(connectionInterrupted));
-        futureList.add(rpcContext.stopClusterServices(connectionInterrupted));
-        futureList.add(deviceContext.stopClusterServices(connectionInterrupted));
+        futureList.add(statContext.stopClusterServices());
+        futureList.add(rpcContext.stopClusterServices());
+        futureList.add(deviceContext.stopClusterServices());
 
         return Futures.transform(Futures.successfulAsList(futureList), new Function<List<Void>, Void>() {
             @Nullable
@@ -114,10 +110,10 @@ public class LifecycleServiceImpl implements LifecycleService {
             // If we are still registered and we are not already closing, then close the registration
             if (Objects.nonNull(registration)) {
                 try {
-                    LOG.debug("Closing clustering MASTER services for node {}", getDeviceInfo().getLOGValue());
+                    LOG.debug("Closing clustering singleton services for node {}", getDeviceInfo().getLOGValue());
                     registration.close();
                 } catch (Exception e) {
-                    LOG.debug("Failed to close clustering MASTER services for node {} with exception: ",
+                    LOG.debug("Failed to close clustering singleton services for node {} with exception: ",
                             getDeviceInfo().getLOGValue(), e);
                 }
             }
@@ -126,7 +122,7 @@ public class LifecycleServiceImpl implements LifecycleService {
 
     @Override
     public void registerService(final ClusterSingletonServiceProvider singletonServiceProvider) {
-        LOG.debug("Registered clustering MASTER services for node {}", getDeviceInfo().getLOGValue());
+        LOG.debug("Registered clustering singleton services for node {}", getDeviceInfo().getLOGValue());
 
         // lifecycle service -> device context -> statistics context -> rpc context -> role context -> lifecycle service
         this.clusterInitializationPhaseHandler = deviceContext;
@@ -139,7 +135,7 @@ public class LifecycleServiceImpl implements LifecycleService {
         // Register cluster singleton service
         try {
             this.registration = Verify.verifyNotNull(singletonServiceProvider.registerClusterSingletonService(this));
-            LOG.info("Registered clustering MASTER services for node {}", getDeviceInfo().getLOGValue());
+            LOG.info("Registered clustering singleton services for node {}", getDeviceInfo().getLOGValue());
         } catch (Exception e) {
             LOG.warn("Failed to register cluster singleton service for node {}, with exception: {}", getDeviceInfo(), e);
             closeConnection();
index 6953784a3f72f6825f29a1d696bc874e480c44d9..f794d850511c98509dc4e8a5f36c8305038b79bb 100644 (file)
@@ -115,7 +115,7 @@ class RpcContextImpl implements RpcContext {
             }
         } else {
             try {
-                stopClusterServices(true).get();
+                stopClusterServices().get();
             } catch (Exception e) {
                 LOG.debug("Failed to close RpcContext for node {} with exception: ", getDeviceInfo().getLOGValue(), e);
             }
@@ -188,7 +188,7 @@ class RpcContextImpl implements RpcContext {
     }
 
     @Override
-    public ListenableFuture<Void> stopClusterServices(boolean connectionInterrupted) {
+    public ListenableFuture<Void> stopClusterServices() {
         if (CONTEXT_STATE.TERMINATION.equals(getState())) {
             return Futures.immediateCancelledFuture();
         }
index 4b5b7be9ca84ba0be030879e7521eb8b4a6821ab..3002b8e632d83e53bb23b5d0f6f6376c92605cf0 100644 (file)
@@ -234,7 +234,7 @@ class StatisticsContextImpl implements StatisticsContext {
             }
         } else {
             try {
-                stopClusterServices(true).get();
+                stopClusterServices().get();
             } catch (Exception e) {
                 LOG.debug("Failed to close StatisticsContext for node {} with exception: ", getDeviceInfo().getLOGValue(), e);
             }
@@ -440,7 +440,7 @@ class StatisticsContextImpl implements StatisticsContext {
     }
 
     @Override
-    public ListenableFuture<Void> stopClusterServices(boolean connectionInterrupted) {
+    public ListenableFuture<Void> stopClusterServices() {
         if (CONTEXT_STATE.TERMINATION.equals(getState())) {
             return Futures.immediateCancelledFuture();
         }
index dc619d61fc0f707f2422d9a200b2b81b9bfc1216..c6fbf45dcca0e02fcf701511a34fb58850f739c9 100644 (file)
@@ -90,6 +90,7 @@ public class OpenFlowPluginProviderImplTest {
         provider.setNotificationProviderService(notificationService);
         provider.setSwitchConnectionProviders(Lists.newArrayList(switchConnectionProvider));
         provider.setClusteringSingletonServicesProvider(clusterSingletonServiceProvider);
+        provider.setEntityOwnershipServiceProvider(entityOwnershipService);
     }
 
     @After
index 33e54b4d7c313e1bab26b678954fc151a8c95a3c..17abab3ea32242b59b98c6f34a0415a90a985a79 100644 (file)
@@ -37,6 +37,8 @@ import org.mockito.stubbing.Answer;
 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
@@ -107,6 +109,10 @@ public class DeviceManagerImplTest {
     @Mock
     private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
     @Mock
+    private EntityOwnershipService entityOwnershipService;
+    @Mock
+    private EntityOwnershipListenerRegistration entityOwnershipListenerRegistration;
+    @Mock
     private ConvertorExecutor convertorExecutor;
     @Mock
     private KeyedInstanceIdentifier<Node, NodeKey> key;
@@ -143,6 +149,7 @@ public class DeviceManagerImplTest {
         when(mockedDataBroker.newWriteOnlyTransaction()).thenReturn(mockedWriteTransaction);
 
         when(mockedWriteTransaction.submit()).thenReturn(mockedFuture);
+        when(entityOwnershipService.registerListener(any(), any())).thenReturn(entityOwnershipListenerRegistration);
 
         final DeviceManagerImpl deviceManager = new DeviceManagerImpl(
                 mockedDataBroker,
@@ -153,10 +160,8 @@ public class DeviceManagerImplTest {
                 messageIntelligenceAgency,
                 true,
                 clusterSingletonServiceProvider,
-                null,
-                new HashedWheelTimer(),
-                convertorExecutor,
-                false);
+                entityOwnershipService, new HashedWheelTimer(), convertorExecutor, false, null
+        );
 
         deviceManager.setDeviceInitializationPhaseHandler(deviceInitPhaseHandler);
         deviceManager.setDeviceTerminationPhaseHandler(deviceTerminationPhaseHandler);
index 7d02cdb2e14fd7bd25e47692ff78fc5573870637..4cf06d4eb4bc544ca08bfb00f29f871596f1290b 100644 (file)
@@ -15,6 +15,8 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
@@ -48,6 +50,8 @@ public class LifecycleServiceImplTest {
     private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
     @Mock
     private ClusterSingletonServiceRegistration clusterSingletonServiceRegistration;
+    @Mock
+    EntityOwnershipListenerRegistration entityOwnershipListenerRegistration;
 
     private LifecycleService lifecycleService;
 
@@ -63,9 +67,9 @@ public class LifecycleServiceImplTest {
         Mockito.when(clusterSingletonServiceProvider.registerClusterSingletonService(Mockito.any()))
                 .thenReturn(clusterSingletonServiceRegistration);
 
-        Mockito.when(deviceContext.stopClusterServices(Mockito.anyBoolean())).thenReturn(Futures.immediateFuture(null));
-        Mockito.when(statContext.stopClusterServices(Mockito.anyBoolean())).thenReturn(Futures.immediateFuture(null));
-        Mockito.when(rpcContext.stopClusterServices(Mockito.anyBoolean())).thenReturn(Futures.immediateFuture(null));
+        Mockito.when(deviceContext.stopClusterServices()).thenReturn(Futures.immediateFuture(null));
+        Mockito.when(statContext.stopClusterServices()).thenReturn(Futures.immediateFuture(null));
+        Mockito.when(rpcContext.stopClusterServices()).thenReturn(Futures.immediateFuture(null));
 
         lifecycleService = new LifecycleServiceImpl();
         lifecycleService.setDeviceContext(deviceContext);
@@ -86,9 +90,9 @@ public class LifecycleServiceImplTest {
     @Test
     public void closeServiceInstance() throws Exception {
         lifecycleService.closeServiceInstance().get();
-        Mockito.verify(statContext).stopClusterServices(false);
-        Mockito.verify(deviceContext).stopClusterServices(false);
-        Mockito.verify(rpcContext).stopClusterServices(false);
+        Mockito.verify(statContext).stopClusterServices();
+        Mockito.verify(deviceContext).stopClusterServices();
+        Mockito.verify(rpcContext).stopClusterServices();
     }
 
     @Test