NETVIRT-1030 Unbinding elan service during interface state change
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanInstanceManager.java
index 0d7dd96f813d41ea5df9040e757fbdee265c8723..b196d2b573fb17b2b5d1b2bfb100de20c67110c2 100644 (file)
@@ -8,11 +8,13 @@
 
 package org.opendaylight.netvirt.elan.internal;
 
+import static java.util.Collections.emptyList;
+
 import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import javax.annotation.Nonnull;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -23,6 +25,7 @@ import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.netvirt.elan.ElanException;
 import org.opendaylight.netvirt.elan.utils.ElanConstants;
 import org.opendaylight.netvirt.elan.utils.ElanUtils;
@@ -42,8 +45,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Singleton
-public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanInstance, ElanInstanceManager>
-        implements AutoCloseable {
+public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanInstance, ElanInstanceManager> {
 
     private static final Logger LOG = LoggerFactory.getLogger(ElanInstanceManager.class);
 
@@ -51,16 +53,18 @@ public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanIns
     private final IdManagerService idManager;
     private final IInterfaceManager interfaceManager;
     private final ElanInterfaceManager elanInterfaceManager;
+    private final JobCoordinator jobCoordinator;
 
     @Inject
     public ElanInstanceManager(final DataBroker dataBroker, final IdManagerService managerService,
                                final ElanInterfaceManager elanInterfaceManager,
-                               final IInterfaceManager interfaceManager) {
+                               final IInterfaceManager interfaceManager, final JobCoordinator jobCoordinator) {
         super(ElanInstance.class, ElanInstanceManager.class);
         this.broker = dataBroker;
         this.idManager = managerService;
         this.elanInterfaceManager = elanInterfaceManager;
         this.interfaceManager = interfaceManager;
+        this.jobCoordinator = jobCoordinator;
     }
 
     @Override
@@ -72,7 +76,6 @@ public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanIns
     @Override
     protected void remove(InstanceIdentifier<ElanInstance> identifier, ElanInstance deletedElan) {
         LOG.trace("Remove ElanInstance - Key: {}, value: {}", identifier, deletedElan);
-        List<ListenableFuture<Void>> futures = new ArrayList<>();
         String elanName = deletedElan.getElanInstanceName();
         // check the elan Instance present in the Operational DataStore
         Elan existingElan = ElanUtils.getElanByName(broker, elanName);
@@ -85,8 +88,7 @@ public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanIns
                     InstanceIdentifier<ElanInterface> elanInterfaceId = ElanUtils
                             .getElanInterfaceConfigurationDataPathId(elanInterfaceName);
                     InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(elanInterfaceName);
-                    elanInterfaceManager.removeElanInterface(futures, deletedElan, elanInterfaceName,
-                            interfaceInfo, false);
+                    elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName, interfaceInfo);
                     ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
                             elanInterfaceId);
                 }
@@ -103,6 +105,18 @@ public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanIns
             ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL,
                     ElanUtils.getElanInfoEntriesOperationalDataPath(elanTag));
         }
+        ElanUtils.removeAndGetElanInterfaces(elanName).forEach(elanInterfaceName -> {
+            jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(elanInterfaceName), () -> {
+                WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
+                LOG.info("Deleting the elanInterface present under ConfigDS:{}", elanInterfaceName);
+                ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
+                        ElanUtils.getElanInterfaceConfigurationDataPathId(elanInterfaceName));
+                elanInterfaceManager.unbindService(elanInterfaceName, writeConfigTxn);
+                ElanUtils.removeElanInterfaceToElanInstanceCache(elanName, elanInterfaceName);
+                LOG.info("unbind the Interface:{} service bounded to Elan:{}", elanInterfaceName, elanName);
+                return Collections.singletonList(writeConfigTxn.submit());
+            }, ElanConstants.JOB_MAX_RETRIES);
+        });
         // Release tag
         ElanUtils.releaseId(idManager, ElanConstants.ELAN_ID_POOL_NAME, elanName);
         if (deletedElan.getAugmentation(EtreeInstance.class) != null) {
@@ -123,6 +137,7 @@ public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanIns
     @Override
     protected void update(InstanceIdentifier<ElanInstance> identifier, ElanInstance original, ElanInstance update) {
         Long existingElanTag = original.getElanTag();
+        String elanName = update.getElanInstanceName();
         if (existingElanTag != null && existingElanTag.equals(update.getElanTag())) {
             return;
         } else if (update.getElanTag() == null) {
@@ -133,11 +148,16 @@ public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanIns
             ElanUtils.waitForTransactionToComplete(tx);
             return;
         }
-        try {
-            elanInterfaceManager.handleunprocessedElanInterfaces(update);
-        } catch (ElanException e) {
-            LOG.error("update() failed for ElanInstance: " + identifier.toString(), e);
-        }
+
+        jobCoordinator.enqueueJob(elanName, () -> {
+            try {
+                return elanInterfaceManager.handleunprocessedElanInterfaces(update);
+            } catch (ElanException e) {
+                LOG.error("update() failed for ElanInstance: " + identifier.toString(), e);
+                return emptyList();
+            }
+        }, ElanConstants.JOB_MAX_RETRIES);
+
     }
 
     @Override
@@ -157,13 +177,19 @@ public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanIns
         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orNull();
     }
 
+    @Nonnull
     public List<DpnInterfaces> getElanDPNByName(String elanInstanceName) {
+        return getElanDPNByName(broker, elanInstanceName);
+    }
+
+    @Nonnull
+    public static List<DpnInterfaces> getElanDPNByName(DataBroker dataBroker, String elanInstanceName) {
         InstanceIdentifier<ElanDpnInterfacesList> elanIdentifier = getElanDpnOperationDataPath(elanInstanceName);
-        return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).transform(
-                ElanDpnInterfacesList::getDpnInterfaces).or(Collections.emptyList());
+        return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).toJavaUtil().map(
+                ElanDpnInterfacesList::getDpnInterfaces).orElse(Collections.emptyList());
     }
 
-    private InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
+    private static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
     }