BUG 4010:Reintroduce inventory code into sal-netconf-connector 10/26710/3
authorTomas Cere <tcere@cisco.com>
Wed, 9 Sep 2015 08:32:47 +0000 (10:32 +0200)
committerTomas Cere <tcere@cisco.com>
Wed, 9 Sep 2015 11:42:22 +0000 (11:42 +0000)
Change-Id: I946907d9ef835d3e5ffdd198d1ec39158ff91feb
Signed-off-by: Tomas Cere <tcere@cisco.com>
opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java [new file with mode: 0644]
opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceSalFacade.java
opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceSalProvider.java

diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java
new file mode 100644 (file)
index 0000000..9b499c0
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.netconf.sal.connect.netconf.sal;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.FluentIterable;
+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.ListenableFuture;
+import java.util.Set;
+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.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+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.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.inventory.rev140108.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.inventory.rev140108.NetconfNodeBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Asynchronous (Binding-aware) adapter over datastore subtree for netconf device.
+ *
+ * All data changes are submitted to an ExecutorService to avoid Thread blocking while sal is waiting for schema.
+ *
+ * @deprecated Data is pushed into Topology instead if Inventory model
+ */
+@Deprecated
+final class NetconfDeviceDatastoreAdapter implements AutoCloseable {
+
+    private static final Logger logger  = LoggerFactory.getLogger(NetconfDeviceDatastoreAdapter.class);
+
+    private final RemoteDeviceId id;
+    private final BindingTransactionChain txChain;
+
+    NetconfDeviceDatastoreAdapter(final RemoteDeviceId deviceId, final DataBroker dataService) {
+        this.id = Preconditions.checkNotNull(deviceId);
+        this.txChain = Preconditions.checkNotNull(dataService).createTransactionChain(new TransactionChainListener() {
+            @Override
+            public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction, Throwable cause) {
+                logger.error("{}: TransactionChain({}) {} FAILED!", id, chain, transaction.getIdentifier(), cause);
+                throw new IllegalStateException(id + "  TransactionChain(" + chain + ") not committed correctly", cause);
+            }
+
+            @Override
+            public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
+                logger.trace("{}: TransactionChain({}) {} SUCCESSFUL", id, chain);
+            }
+        });
+
+        initDeviceData();
+    }
+
+    public void updateDeviceState(final boolean up, final Set<QName> capabilities) {
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node data = buildDataForDeviceState(
+                up, capabilities, id);
+
+        final ReadWriteTransaction transaction = txChain.newReadWriteTransaction();
+        logger.trace("{}: Update device state transaction {} merging operational data started.", id, transaction.getIdentifier());
+        transaction.put(LogicalDatastoreType.OPERATIONAL, id.getBindingPath(), data);
+        logger.trace("{}: Update device state transaction {} merging operational data ended.", id, transaction.getIdentifier());
+
+        commitTransaction(transaction, "update");
+    }
+
+    private void removeDeviceConfigAndState() {
+        final WriteTransaction transaction = txChain.newWriteOnlyTransaction();
+        logger.trace("{}: Close device state transaction {} removing all data started.", id, transaction.getIdentifier());
+        transaction.delete(LogicalDatastoreType.CONFIGURATION, id.getBindingPath());
+        transaction.delete(LogicalDatastoreType.OPERATIONAL, id.getBindingPath());
+        logger.trace("{}: Close device state transaction {} removing all data ended.", id, transaction.getIdentifier());
+
+        commitTransaction(transaction, "close");
+    }
+
+    private void initDeviceData() {
+        final WriteTransaction transaction = txChain.newWriteOnlyTransaction();
+
+        createNodesListIfNotPresent(transaction);
+
+        final InstanceIdentifier<Node> path = id.getBindingPath();
+        final Node nodeWithId = getNodeWithId(id);
+
+        logger.trace("{}: Init device state transaction {} putting if absent operational data started.", id, transaction.getIdentifier());
+        transaction.put(LogicalDatastoreType.OPERATIONAL, path, nodeWithId);
+        logger.trace("{}: Init device state transaction {} putting operational data ended.", id, transaction.getIdentifier());
+
+        logger.trace("{}: Init device state transaction {} putting if absent config data started.", id, transaction.getIdentifier());
+        transaction.put(LogicalDatastoreType.CONFIGURATION, path, nodeWithId);
+        logger.trace("{}: Init device state transaction {} putting config data ended.", id, transaction.getIdentifier());
+
+        commitTransaction(transaction, "init");
+    }
+
+    private void createNodesListIfNotPresent(final WriteTransaction writeTx) {
+        final Nodes nodes = new NodesBuilder().build();
+        final InstanceIdentifier<Nodes> path = InstanceIdentifier.builder(Nodes.class).build();
+        logger.trace("{}: Merging {} container to ensure its presence", id, Nodes.QNAME, writeTx.getIdentifier());
+        writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, nodes);
+        writeTx.merge(LogicalDatastoreType.OPERATIONAL, path, nodes);
+    }
+
+    private void commitTransaction(final WriteTransaction transaction, final String txType) {
+        logger.trace("{}: Committing Transaction {}:{}", id, txType, transaction.getIdentifier());
+        final CheckedFuture<Void, TransactionCommitFailedException> result = transaction.submit();
+
+        Futures.addCallback(result, new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(final Void result) {
+                logger.trace("{}: Transaction({}) {} SUCCESSFUL", id, txType, transaction.getIdentifier());
+            }
+
+            @Override
+            public void onFailure(final Throwable t) {
+                logger.error("{}: Transaction({}) {} FAILED!", id, txType, transaction.getIdentifier(), t);
+                throw new IllegalStateException(id + "  Transaction(" + txType + ") not committed correctly", t);
+            }
+        });
+
+    }
+
+    @Override
+    public void close() throws Exception {
+        removeDeviceConfigAndState();
+        txChain.close();
+    }
+
+    public static org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node buildDataForDeviceState(
+            final boolean up, final Set<QName> capabilities, final RemoteDeviceId id) {
+
+        final NodeBuilder nodeBuilder = getNodeWithIdBuilder(id);
+        final NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder();
+        netconfNodeBuilder.setConnected(up);
+        netconfNodeBuilder.setInitialCapability(FluentIterable.from(capabilities)
+                .transform(new Function<QName, String>() {
+                    @Override
+                    public String apply(final QName input) {
+                        return input.toString();
+                    }
+                }).toList());
+        nodeBuilder.addAugmentation(NetconfNode.class, netconfNodeBuilder.build());
+
+        return nodeBuilder.build();
+    }
+
+    private static ListenableFuture<Optional<Node>> readNodeData(
+            final LogicalDatastoreType store,
+            final ReadWriteTransaction transaction,
+            final InstanceIdentifier<Node> path) {
+        return transaction.read(store, path);
+    }
+
+    private static Node getNodeWithId(final RemoteDeviceId id) {
+        final NodeBuilder nodeBuilder = getNodeWithIdBuilder(id);
+        return nodeBuilder.build();
+    }
+
+    private static NodeBuilder getNodeWithIdBuilder(final RemoteDeviceId id) {
+        final NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setKey(id.getBindingKey());
+        nodeBuilder.setId(id.getBindingKey().getId());
+        return nodeBuilder;
+    }
+}
index 172bcd9955764bdadfdadc379dbc2d06ddf1114f..7bb3df08a5ef6644028be5fcd162145b361dd1db 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.netconf.sal.connect.netconf.sal;
 
 import com.google.common.collect.Lists;
+import java.util.Collections;
 import java.util.List;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
@@ -18,6 +19,7 @@ import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -57,20 +59,24 @@ public final class NetconfDeviceSalFacade implements AutoCloseable, RemoteDevice
 
         final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
 
+        salProvider.getMountInstance().onDeviceConnected(schemaContext, domBroker, deviceRpc, notificationService);
+        salProvider.getDatastoreAdapter().updateDeviceState(true, netconfSessionPreferences.getModuleBasedCaps());
         salProvider.getMountInstance().onTopologyDeviceConnected(schemaContext, domBroker, deviceRpc, notificationService);
         salProvider.getTopologyDatastoreAdapter().updateDeviceData(true, netconfSessionPreferences.getNetconfDeviceCapabilities());
     }
 
     @Override
     public synchronized void onDeviceDisconnected() {
-        salProvider.getTopologyDatastoreAdapter().updateDeviceData(false,
-                new NetconfDeviceCapabilities());
+        salProvider.getDatastoreAdapter().updateDeviceState(false, Collections.<QName>emptySet());
+        salProvider.getTopologyDatastoreAdapter().updateDeviceData(false, new NetconfDeviceCapabilities());
+        salProvider.getMountInstance().onDeviceDisconnected();
         salProvider.getMountInstance().onTopologyDeviceDisconnected();
     }
 
     @Override
     public synchronized void onDeviceFailed(final Throwable throwable) {
         salProvider.getTopologyDatastoreAdapter().setDeviceAsFailed(throwable);
+        salProvider.getMountInstance().onDeviceDisconnected();
         salProvider.getMountInstance().onTopologyDeviceDisconnected();
     }
 
@@ -87,8 +93,7 @@ public final class NetconfDeviceSalFacade implements AutoCloseable, RemoteDevice
             try {
                 resource.close();
             } catch (final Exception e) {
-                LOG.warn("{}: Ignoring exception while closing {}", id,
-                        resource, e);
+                LOG.warn("{}: Ignoring exception while closing {}", id, resource, e);
             }
         }
     }
index 890c0aa0a98cb3a079226eb2fe4f089926c8d651..8cb34c15daeeda9a2b540010eac8bac4a24832c6 100644 (file)
@@ -29,9 +29,10 @@ import org.slf4j.LoggerFactory;
 
 final class NetconfDeviceSalProvider implements AutoCloseable, Provider, BindingAwareProvider {
 
-    private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSalProvider.class);
+    private static final Logger logger = LoggerFactory.getLogger(NetconfDeviceSalProvider.class);
 
     private final RemoteDeviceId id;
+    private volatile NetconfDeviceDatastoreAdapter datastoreAdapter;
     private MountInstance mountInstance;
 
     private volatile NetconfDeviceTopologyAdapter topologyDatastoreAdapter;
@@ -46,6 +47,12 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
         return mountInstance;
     }
 
+    public NetconfDeviceDatastoreAdapter getDatastoreAdapter() {
+        Preconditions.checkState(datastoreAdapter != null,
+                "%s: Sal provider %s was not initialized by sal. Cannot get datastore adapter", id);
+        return datastoreAdapter;
+    }
+
     public NetconfDeviceTopologyAdapter getTopologyDatastoreAdapter() {
         Preconditions.checkState(topologyDatastoreAdapter != null,
                 "%s: Sal provider %s was not initialized by sal. Cannot get topology datastore adapter", id);
@@ -54,7 +61,7 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
 
     @Override
     public void onSessionInitiated(final Broker.ProviderSession session) {
-        LOG.debug("{}: (BI)Session with sal established {}", id, session);
+        logger.debug("{}: (BI)Session with sal established {}", id, session);
 
         final DOMMountPointService mountService = session.getService(DOMMountPointService.class);
         if (mountService != null) {
@@ -69,15 +76,18 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
 
     @Override
     public void onSessionInitiated(final BindingAwareBroker.ProviderContext session) {
-        LOG.debug("{}: Session with sal established {}", id, session);
+        logger.debug("{}: Session with sal established {}", id, session);
 
         final DataBroker dataBroker = session.getSALService(DataBroker.class);
+        datastoreAdapter = new NetconfDeviceDatastoreAdapter(id, dataBroker);
 
         topologyDatastoreAdapter = new NetconfDeviceTopologyAdapter(id, dataBroker);
     }
 
     public void close() throws Exception {
         mountInstance.close();
+        datastoreAdapter.close();
+        datastoreAdapter = null;
         topologyDatastoreAdapter.close();
         topologyDatastoreAdapter = null;
     }
@@ -86,6 +96,7 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
 
         private DOMMountPointService mountService;
         private final RemoteDeviceId id;
+        private ObjectRegistration<DOMMountPoint> registration;
         private NetconfDeviceNotificationService notificationService;
 
         private ObjectRegistration<DOMMountPoint> topologyRegistration;
@@ -95,6 +106,44 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
             this.id = Preconditions.checkNotNull(id);
         }
 
+        @Deprecated
+        synchronized void onDeviceConnected(final SchemaContext initialCtx,
+                                            final DOMDataBroker broker, final DOMRpcService rpc,
+                                            final NetconfDeviceNotificationService notificationService) {
+
+            Preconditions.checkNotNull(mountService, "Closed");
+            Preconditions.checkState(registration == null, "Already initialized");
+
+            final DOMMountPointService.DOMMountPointBuilder mountBuilder = mountService.createMountPoint(id.getPath());
+            mountBuilder.addInitialSchemaContext(initialCtx);
+
+            mountBuilder.addService(DOMDataBroker.class, broker);
+            mountBuilder.addService(DOMRpcService.class, rpc);
+            mountBuilder.addService(DOMNotificationService.class, notificationService);
+            this.notificationService = notificationService;
+
+            registration = mountBuilder.register();
+            logger.debug("{}: Mountpoint exposed into MD-SAL {}", id, registration);
+        }
+
+        @Deprecated
+        synchronized void onDeviceDisconnected() {
+            if(registration == null) {
+                logger.trace("{}: Not removing mountpoint from MD-SAL, mountpoint was not registered yet", id);
+                return;
+            }
+
+            try {
+                registration.close();
+            } catch (final Exception e) {
+                // Only log and ignore
+                logger.warn("Unable to unregister mount instance for {}. Ignoring exception", id.getPath(), e);
+            } finally {
+                logger.debug("{}: Mountpoint removed from MD-SAL {}", id, registration);
+                registration = null;
+            }
+        }
+
         synchronized void onTopologyDeviceConnected(final SchemaContext initialCtx,
                                                     final DOMDataBroker broker, final DOMRpcService rpc,
                                                     final NetconfDeviceNotificationService notificationService) {
@@ -108,19 +157,15 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
             mountBuilder.addService(DOMDataBroker.class, broker);
             mountBuilder.addService(DOMRpcService.class, rpc);
             mountBuilder.addService(DOMNotificationService.class, notificationService);
-            this.notificationService = notificationService;
 
             topologyRegistration = mountBuilder.register();
-            LOG.debug("{}: TOPOLOGY Mountpoint exposed into MD-SAL {}", id,
-                    topologyRegistration);
+            logger.debug("{}: TOPOLOGY Mountpoint exposed into MD-SAL {}", id, registration);
 
         }
 
         synchronized void onTopologyDeviceDisconnected() {
             if(topologyRegistration == null) {
-                LOG.trace(
-                        "{}: Not removing TOPOLOGY mountpoint from MD-SAL, mountpoint was not registered yet",
-                        id);
+                logger.trace("{}: Not removing TOPOLOGY mountpoint from MD-SAL, mountpoint was not registered yet", id);
                 return;
             }
 
@@ -128,18 +173,16 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
                 topologyRegistration.close();
             } catch (final Exception e) {
                 // Only log and ignore
-                LOG.warn(
-                        "Unable to unregister mount instance for {}. Ignoring exception",
-                        id.getTopologyPath(), e);
+                logger.warn("Unable to unregister mount instance for {}. Ignoring exception", id.getTopologyPath(), e);
             } finally {
-                LOG.debug("{}: TOPOLOGY Mountpoint removed from MD-SAL {}",
-                        id, topologyRegistration);
+                logger.debug("{}: TOPOLOGY Mountpoint removed from MD-SAL {}", id, registration);
                 topologyRegistration = null;
             }
         }
 
         @Override
         synchronized public void close() throws Exception {
+            onDeviceDisconnected();
             onTopologyDeviceDisconnected();
             mountService = null;
         }