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 8742d68ca4cb72125e9262b1a4cc3951a6a315b2..b196d2b573fb17b2b5d1b2bfb100de20c67110c2 100644 (file)
@@ -8,10 +8,16 @@
 
 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;
 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.data.LogicalDatastoreType;
@@ -19,6 +25,8 @@ 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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
@@ -36,8 +44,8 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanInstance, ElanInstanceManager>
-        implements AutoCloseable {
+@Singleton
+public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanInstance, ElanInstanceManager> {
 
     private static final Logger LOG = LoggerFactory.getLogger(ElanInstanceManager.class);
 
@@ -45,17 +53,22 @@ 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
+    @PostConstruct
     public void init() {
         registerListener(LogicalDatastoreType.CONFIGURATION, broker);
     }
@@ -63,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);
@@ -76,19 +88,35 @@ 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);
                 }
             }
             ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL,
                     ElanUtils.getElanInstanceOperationalDataPath(elanName));
-            ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL,
+            Optional<ElanDpnInterfacesList> elanDpnInterfaceList = MDSALUtil.read(broker,
+                    LogicalDatastoreType.OPERATIONAL,
+                    ElanUtils.getElanDpnOperationDataPath(elanName));
+            if (elanDpnInterfaceList.isPresent()) {
+                ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL,
                     getElanDpnOperationDataPath(elanName));
+            }
             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) {
@@ -109,52 +137,59 @@ public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanIns
     @Override
     protected void update(InstanceIdentifier<ElanInstance> identifier, ElanInstance original, ElanInstance update) {
         Long existingElanTag = original.getElanTag();
-        if (existingElanTag != null && existingElanTag == update.getElanTag()) {
+        String elanName = update.getElanInstanceName();
+        if (existingElanTag != null && existingElanTag.equals(update.getElanTag())) {
             return;
         } else if (update.getElanTag() == null) {
             // update the elan-Instance with new properties
             WriteTransaction tx = broker.newWriteOnlyTransaction();
             ElanUtils.updateOperationalDataStore(broker, idManager,
-                    update, new ArrayList<String>(), tx);
+                    update, new ArrayList<>(), tx);
             ElanUtils.waitForTransactionToComplete(tx);
             return;
         }
-        elanInterfaceManager.handleunprocessedElanInterfaces(update);
+
+        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
     protected void add(InstanceIdentifier<ElanInstance> identifier, ElanInstance elanInstanceAdded) {
-        Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceAdded.getElanInstanceName());
+        String elanInstanceName  = elanInstanceAdded.getElanInstanceName();
+        Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
         if (elanInfo == null) {
             WriteTransaction tx = broker.newWriteOnlyTransaction();
             ElanUtils.updateOperationalDataStore(broker, idManager,
-                    elanInstanceAdded, new ArrayList<String>(), tx);
+                elanInstanceAdded, new ArrayList<>(), tx);
             ElanUtils.waitForTransactionToComplete(tx);
         }
     }
 
     public ElanInstance getElanInstanceByName(String elanInstanceName) {
         InstanceIdentifier<ElanInstance> elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName);
-        Optional<ElanInstance> elanInstance = MDSALUtil.read(broker,
-                LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
-        if (elanInstance.isPresent()) {
-            return elanInstance.get();
-        }
-        return null;
+        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);
-        Optional<ElanDpnInterfacesList> elanInstance = MDSALUtil.read(broker,
-                LogicalDatastoreType.OPERATIONAL, elanIdentifier);
-        if (elanInstance.isPresent()) {
-            ElanDpnInterfacesList elanDPNs = elanInstance.get();
-            return elanDPNs.getDpnInterfaces();
-        }
-        return null;
+        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();
     }