Upgrade support of ovsdb reconciliation 72/82772/7
authorChetan Arakere Gowdru <chetan.arakere@altencalsoftlabs.com>
Fri, 28 Jun 2019 11:08:08 +0000 (16:38 +0530)
committerChetan Arakere Gowdru <chetan.arakere@altencalsoftlabs.com>
Sun, 22 Dec 2019 13:03:26 +0000 (13:03 +0000)
Description:
When Upgrade in process, the config DS may not be fully populated when
reconciliaiton is triggered. This will result in uncessaary deletion on tunnels
(as config and oper DS are compared and delta changes will be pushed to switch).
Changes are done to postpone the reconcilaiton task until upgrade flag is set to false.

Testing Steps.

1) Karaf up and running and tunnels created.
2) Set upgade flag to true.
PUT http://localhost:8181/restconf/config/odl-serviceutils-upgrade:upgrade-config
{
  "upgrade-config": {
    "upgradeInProgress": true
  }
}
3) Close karaf terminal(kill karaf process)
4) Don’t clear data/instance/journal/snapshots
5) del-manager on switches and delete tunnels manually on switches.
6) Start karaf and wait DPN connects.
7) Check the tunnel are not recreated by reconciliation process.
8) Set upgradeInProgress=false and check the tunnels re-created back

Change-Id: Id6cc8e1a3aa5e139597fa3071d536e1f5ac0802f
Signed-off-by: Chetan Arakere Gowdru <chetan.arakere@altencalsoftlabs.com>
Signed-off-by: xcheara <chetan.arakere@altencalsoftlabs.com>
southbound/southbound-impl/pom.xml
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/OvsdbConnectionManager.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/SouthboundProvider.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/reconciliation/OvsdbUpgradeStateListener.java [new file with mode: 0644]
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbDataTreeChangeListenerTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/SouthboundProviderTest.java

index ecc6c87fc2a0777a45b6cc5b554931bb1bbd5752..ad62ea7d0d4dddbbc790fece080971b960fa9c44 100644 (file)
@@ -75,6 +75,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>ready-api</artifactId>
       <version>1.7.0-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.serviceutils</groupId>
+      <artifactId>upgrade</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
     <!-- external dependencies -->
     <dependency>
       <groupId>org.opendaylight.infrautils</groupId>
index 424cc6315e7a8d2016ea3a1700cbdc9e3c4090f2..296216ec9cc3a858303f8843597a6e1b98fd8054 100644 (file)
@@ -55,6 +55,7 @@ import org.opendaylight.ovsdb.southbound.reconciliation.configuration.BridgeConf
 import org.opendaylight.ovsdb.southbound.reconciliation.connection.ConnectionReconciliationTask;
 import org.opendaylight.ovsdb.southbound.transactions.md.OvsdbNodeRemoveCommand;
 import org.opendaylight.ovsdb.southbound.transactions.md.TransactionInvoker;
+import org.opendaylight.serviceutils.upgrade.UpgradeState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
@@ -66,6 +67,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoCloseable {
+
     private final Map<ConnectionInfo, OvsdbConnectionInstance> clients =
             new ConcurrentHashMap<>();
     private static final Logger LOG = LoggerFactory.getLogger(OvsdbConnectionManager.class);
@@ -85,11 +87,13 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
     private final OvsdbConnection ovsdbConnection;
     private final ReconciliationManager reconciliationManager;
     private final InstanceIdentifierCodec instanceIdentifierCodec;
+    private final UpgradeState upgradeState;
 
     public OvsdbConnectionManager(final DataBroker db,final TransactionInvoker txInvoker,
                                   final EntityOwnershipService entityOwnershipService,
                                   final OvsdbConnection ovsdbConnection,
-                                  final InstanceIdentifierCodec instanceIdentifierCodec) {
+                                  final InstanceIdentifierCodec instanceIdentifierCodec,
+                                  final UpgradeState upgradeState) {
         this.db = db;
         this.txInvoker = txInvoker;
         this.entityOwnershipService = entityOwnershipService;
@@ -97,6 +101,7 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
         this.ovsdbConnection = ovsdbConnection;
         this.reconciliationManager = new ReconciliationManager(db, instanceIdentifierCodec);
         this.instanceIdentifierCodec = instanceIdentifierCodec;
+        this.upgradeState = upgradeState;
     }
 
     @Override
@@ -456,8 +461,10 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
             //*this* instance of southbound plugin is owner of the device,
             //so register for monitor callbacks
             ovsdbConnectionInstance.registerCallbacks(instanceIdentifierCodec);
-
-            reconcileBridgeConfigurations(ovsdbConnectionInstance);
+            LOG.trace("isUpgradeInProgress {}", upgradeState.isUpgradeInProgress());
+            if (!upgradeState.isUpgradeInProgress()) {
+                reconcileBridgeConfigurations(ovsdbConnectionInstance);
+            }
         } else {
             //You were owner of the device, but now you are not. With the current ownership
             //grant mechanism, this scenario should not occur. Because this scenario will occur
@@ -642,7 +649,7 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
         }
     }
 
-    private void reconcileBridgeConfigurations(final OvsdbConnectionInstance client) {
+    public void reconcileBridgeConfigurations(final OvsdbConnectionInstance client) {
         final InstanceIdentifier<Node> nodeIid = client.getInstanceIdentifier();
         final ReconciliationTask task = new BridgeConfigReconciliationTask(
                 reconciliationManager, OvsdbConnectionManager.this, nodeIid, client, instanceIdentifierCodec);
@@ -683,4 +690,8 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
         */
         ON_DISCONNECT
     }
+
+    public Map<ConnectionInfo, OvsdbConnectionInstance> getClients() {
+        return clients;
+    }
 }
index 066b1870eaa4b35418f18dfe7372fae57e159122..f197731011a60e192e692b47dd4a8ba8835aee35 100644 (file)
@@ -41,8 +41,10 @@ import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListenerRegistratio
 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
 import org.opendaylight.ovsdb.lib.OvsdbConnection;
+import org.opendaylight.ovsdb.southbound.reconciliation.OvsdbUpgradeStateListener;
 import org.opendaylight.ovsdb.southbound.transactions.md.TransactionInvoker;
 import org.opendaylight.ovsdb.southbound.transactions.md.TransactionInvokerImpl;
+import org.opendaylight.serviceutils.upgrade.UpgradeState;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
@@ -75,12 +77,13 @@ public class SouthboundProvider implements ClusteredDataTreeChangeListener<Topol
     private final OvsdbConnection ovsdbConnection;
     private final InstanceIdentifierCodec instanceIdentifierCodec;
     private final SystemReadyMonitor systemReadyMonitor;
-
+    private final UpgradeState upgradeState;
     private final AtomicBoolean registered = new AtomicBoolean(false);
     private ListenerRegistration<SouthboundProvider> operTopologyRegistration;
     private final OvsdbDiagStatusProvider ovsdbStatusProvider;
     private static List<String> reconcileBridgeInclusionList = new ArrayList<>();
     private static List<String> reconcileBridgeExclusionList = new ArrayList<>();
+    private OvsdbUpgradeStateListener ovsdbUpgradeStateListener;
 
     @Inject
     public SouthboundProvider(@Reference final DataBroker dataBroker,
@@ -89,7 +92,8 @@ public class SouthboundProvider implements ClusteredDataTreeChangeListener<Topol
                               @Reference final DOMSchemaService schemaService,
                               @Reference final BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer,
                               @Reference final SystemReadyMonitor systemReadyMonitor,
-                              @Reference final DiagStatusService diagStatusService) {
+                              @Reference final DiagStatusService diagStatusService,
+                              @Reference final UpgradeState upgradeState) {
         SouthboundProvider.db = dataBroker;
         this.entityOwnershipService = entityOwnershipServiceDependency;
         registration = null;
@@ -98,6 +102,7 @@ public class SouthboundProvider implements ClusteredDataTreeChangeListener<Topol
         this.instanceIdentifierCodec = new InstanceIdentifierCodec(schemaService,
                 bindingNormalizedNodeSerializer);
         this.systemReadyMonitor = systemReadyMonitor;
+        this.upgradeState = upgradeState;
         LOG.info("SouthboundProvider ovsdbConnectionService Initialized");
     }
 
@@ -110,7 +115,7 @@ public class SouthboundProvider implements ClusteredDataTreeChangeListener<Topol
         ovsdbStatusProvider.reportStatus(ServiceState.STARTING, "OVSDB initialization in progress");
         this.txInvoker = new TransactionInvokerImpl(db);
         cm = new OvsdbConnectionManager(db, txInvoker, entityOwnershipService, ovsdbConnection,
-                instanceIdentifierCodec);
+                instanceIdentifierCodec, upgradeState);
         ovsdbDataTreeChangeListener = new OvsdbDataTreeChangeListener(db, cm, instanceIdentifierCodec);
 
         //Register listener for entityOnwership changes
@@ -133,6 +138,7 @@ public class SouthboundProvider implements ClusteredDataTreeChangeListener<Topol
 
         LOG.trace("Registering listener for path {}", treeId);
         operTopologyRegistration = db.registerDataTreeChangeListener(treeId, this);
+        ovsdbUpgradeStateListener = new OvsdbUpgradeStateListener(db, cm);
     }
 
     @Override
@@ -154,6 +160,9 @@ public class SouthboundProvider implements ClusteredDataTreeChangeListener<Topol
             operTopologyRegistration = null;
         }
         ovsdbStatusProvider.reportStatus(ServiceState.UNREGISTERED, "OVSDB Service stopped");
+        if (ovsdbUpgradeStateListener != null) {
+            ovsdbUpgradeStateListener.close();
+        }
     }
 
     private void initializeOvsdbTopology(final LogicalDatastoreType type) {
@@ -256,4 +265,8 @@ public class SouthboundProvider implements ClusteredDataTreeChangeListener<Topol
     boolean isRegistered() {
         return registered.get();
     }
+
+    public UpgradeState getUpgradeState() {
+        return upgradeState;
+    }
 }
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/reconciliation/OvsdbUpgradeStateListener.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/reconciliation/OvsdbUpgradeStateListener.java
new file mode 100644 (file)
index 0000000..9bc8d7b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.southbound.reconciliation;
+
+import java.util.Collection;
+import java.util.Map;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.serviceutils.upgrade.rev180702.UpgradeConfig;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OvsdbUpgradeStateListener implements ClusteredDataTreeChangeListener<UpgradeConfig>, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OvsdbUpgradeStateListener.class);
+
+    private final DataBroker dataBroker;
+
+    /** The connection manager. */
+    private final OvsdbConnectionManager cm;
+
+    /** Our registration. */
+    private final ListenerRegistration<DataTreeChangeListener<UpgradeConfig>> registration;
+
+    public OvsdbUpgradeStateListener(final DataBroker db, OvsdbConnectionManager cm) {
+
+        DataTreeIdentifier<UpgradeConfig> dataTreeIdentifier =
+            new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+                        InstanceIdentifier.create(UpgradeConfig.class));
+        registration = db.registerDataTreeChangeListener(dataTreeIdentifier, this);
+
+        this.dataBroker = db;
+        this.cm = cm;
+        LOG.info("OvsdbUpgradeStateListener (ovsdb) initialized");
+    }
+
+    @Override
+    public void close() {
+        registration.close();
+        LOG.info("OVSDB topology listener has been closed.");
+    }
+
+    @Override
+    public void onDataTreeChanged(@NonNull Collection<DataTreeModification<UpgradeConfig>> changes) {
+        LOG.trace("onDataTreeChanged: {}", changes);
+        for (DataTreeModification<UpgradeConfig> change: changes) {
+
+            if (change.getRootNode().getModificationType() == ModificationType.WRITE) {
+                UpgradeConfig before = change.getRootNode().getDataBefore();
+                UpgradeConfig after = change.getRootNode().getDataAfter();
+                if (before != null && before.isUpgradeInProgress() && after != null && !after.isUpgradeInProgress()) {
+                    LOG.info("Upgrade Flag is set from {} to {}, Trigger Reconciliation",
+                        before.isUpgradeInProgress(), after.isUpgradeInProgress());
+                    //TODO Trigger Reconciliation on all the ovsDbConnectionInstance
+                    for (Map.Entry<ConnectionInfo, OvsdbConnectionInstance> entry : cm.getClients().entrySet()) {
+                        ConnectionInfo connectionInfo = entry.getKey();
+                        OvsdbConnectionInstance connectionInstance = entry.getValue();
+                        LOG.trace("ConnectionInfo : {}", connectionInfo);
+                        LOG.trace("OvsdbConnectionInstance : {}", connectionInstance);
+                        cm.reconcileBridgeConfigurations(connectionInstance);
+                    }
+                }
+            }
+
+        }
+    }
+}
index 25951074cf4c2e4aeae81c2c1cb51b9b571b391d..5e345d562b9db0933a6dbe8c2436fd61b6e7b0c7 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
 import org.opendaylight.ovsdb.lib.OvsdbConnection;
 import org.opendaylight.ovsdb.southbound.transactions.md.TransactionInvokerImpl;
 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+import org.opendaylight.serviceutils.upgrade.UpgradeState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
@@ -48,9 +49,10 @@ public class OvsdbDataTreeChangeListenerTest extends AbstractConcurrentDataBroke
         dataBroker = getDataBroker();
         EntityOwnershipService entityOwnershipService = mock(EntityOwnershipService.class);
         InstanceIdentifierCodec instanceIdentifierCodec = mock(InstanceIdentifierCodec.class);
+        UpgradeState upgradeState = mock(UpgradeState.class);
         listener = new OvsdbDataTreeChangeListener(dataBroker,
                 new OvsdbConnectionManager(dataBroker, new TransactionInvokerImpl(dataBroker), entityOwnershipService,
-                        ovsdbConnection, instanceIdentifierCodec), instanceIdentifierCodec);
+                        ovsdbConnection, instanceIdentifierCodec, upgradeState), instanceIdentifierCodec);
     }
 
     @Test
index ba5dce98292137610992047bcd135efe4309322e..e7b78c6f64122032b355d9ddc2829bcc3885df39 100644 (file)
@@ -41,6 +41,7 @@ import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException
 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipState;
 import org.opendaylight.ovsdb.lib.OvsdbConnection;
+import org.opendaylight.serviceutils.upgrade.UpgradeState;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
@@ -77,7 +78,8 @@ public class SouthboundProviderTest extends AbstractConcurrentDataBrokerTest {
                 Mockito.mock(DOMSchemaService.class),
                 Mockito.mock(BindingNormalizedNodeSerializer.class),
                 new TestSystemReadyMonitor(IMMEDIATE),
-                Mockito.mock(DiagStatusService.class))) {
+                Mockito.mock(DiagStatusService.class),
+                Mockito.mock(UpgradeState.class))) {
 
             // Initiate the session
             southboundProvider.init();
@@ -104,7 +106,8 @@ public class SouthboundProviderTest extends AbstractConcurrentDataBrokerTest {
                 Mockito.mock(DOMSchemaService.class),
                 Mockito.mock(BindingNormalizedNodeSerializer.class),
                 new TestSystemReadyMonitor(IMMEDIATE),
-                Mockito.mock(DiagStatusService.class))) {
+                Mockito.mock(DiagStatusService.class),
+                Mockito.mock(UpgradeState.class))) {
 
             // Initiate the session
             southboundProvider.init();
@@ -133,7 +136,8 @@ public class SouthboundProviderTest extends AbstractConcurrentDataBrokerTest {
                 Mockito.mock(DOMSchemaService.class),
                 Mockito.mock(BindingNormalizedNodeSerializer.class),
                 new TestSystemReadyMonitor(IMMEDIATE),
-                Mockito.mock(DiagStatusService.class))) {
+                Mockito.mock(DiagStatusService.class),
+                Mockito.mock(UpgradeState.class))) {
 
             southboundProvider.init();
 
@@ -157,7 +161,8 @@ public class SouthboundProviderTest extends AbstractConcurrentDataBrokerTest {
                 Mockito.mock(DOMSchemaService.class),
                 Mockito.mock(BindingNormalizedNodeSerializer.class),
                 new TestSystemReadyMonitor(IMMEDIATE),
-                Mockito.mock(DiagStatusService.class))) {
+                Mockito.mock(DiagStatusService.class),
+                Mockito.mock(UpgradeState.class))) {
 
             southboundProvider.init();