RPC for netconf node addition. Supports encrypt option for password encryption.
[netconf.git] / netconf / callhome-provider / src / main / java / org / opendaylight / netconf / callhome / mount / IetfZeroTouchCallHomeServerProvider.java
index ca26f8606432136ee0ff8dc619ad701787d451b9..62c4c51b32e595dcc7aee559b5f0b9326cb94ab4 100644 (file)
@@ -8,24 +8,24 @@
 
 package org.opendaylight.netconf.callhome.mount;
 
-import static com.google.common.base.Preconditions.checkArgument;
-
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
-import java.io.File;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+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.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.netconf.callhome.protocol.CallHomeAuthorizationProvider;
@@ -39,30 +39,28 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.DeviceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev161109.netconf.callhome.server.allowed.devices.DeviceKey;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
-public class IetfZeroTouchCallHomeServerProvider implements AutoCloseable, DataChangeListener {
+public class IetfZeroTouchCallHomeServerProvider implements AutoCloseable, DataTreeChangeListener<AllowedDevices> {
     private static final String APPNAME = "CallHomeServer";
-    static final InstanceIdentifier<AllowedDevices> ALL_DEVICES = InstanceIdentifier.create(NetconfCallhomeServer.class).child(AllowedDevices.class);
+    static final InstanceIdentifier<AllowedDevices> ALL_DEVICES = InstanceIdentifier.create(NetconfCallhomeServer.class)
+        .child(AllowedDevices.class);
 
     private static final Logger LOG = LoggerFactory.getLogger(IetfZeroTouchCallHomeServerProvider.class);
 
     private final DataBroker dataBroker;
     private final CallHomeMountDispatcher mountDispacher;
-    private CallHomeAuthProviderImpl authProvider;
+    private final CallHomeAuthProviderImpl authProvider;
 
     protected NetconfCallHomeServer server;
 
     private ListenerRegistration<IetfZeroTouchCallHomeServerProvider> listenerReg = null;
 
     private static final String CALL_HOME_PORT_KEY = "DefaultCallHomePort";
-    private static String configurationPath = "etc" + File.pathSeparator + "ztp-callhome-config.cfg";
     private int port = 0; // 0 = use default in NetconfCallHomeBuilder
-    private CallhomeStatusReporter statusReporter;
+    private final CallhomeStatusReporter statusReporter;
 
     public IetfZeroTouchCallHomeServerProvider(DataBroker dataBroker, CallHomeMountDispatcher mountDispacher) {
         this.dataBroker = dataBroker;
@@ -75,22 +73,23 @@ public class IetfZeroTouchCallHomeServerProvider implements AutoCloseable, DataC
         // Register itself as a listener to changes in Devices subtree
         try {
             LOG.info("Initializing provider for {}", APPNAME);
-            loadConfigurableValues(configurationPath);
             initializeServer();
-            dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, ALL_DEVICES, this, AsyncDataBroker.DataChangeScope.SUBTREE);
+            listenerReg = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(
+                    LogicalDatastoreType.CONFIGURATION, ALL_DEVICES), this);
             LOG.info("Initialization complete for {}", APPNAME);
         } catch (IOException | Configuration.ConfigurationException e) {
             LOG.error("Unable to successfully initialize", e);
         }
     }
 
-    private void loadConfigurableValues(String configurationPath)
-            throws Configuration.ConfigurationException {
+    public void setPort(String portStr) {
         try {
-            Configuration configuration = new Configuration(configurationPath);
+            Configuration configuration = new Configuration();
+            configuration.set(CALL_HOME_PORT_KEY, portStr);
             port = configuration.getAsPort(CALL_HOME_PORT_KEY);
+            LOG.info("Setting port for call home server to {}", portStr);
         } catch (Configuration.ConfigurationException e) {
-            LOG.error("Problem trying to load configuration values from {}", configurationPath, e);
+            LOG.error("Problem trying to set port for call home server {}", portStr, e);
         }
     }
 
@@ -103,8 +102,9 @@ public class IetfZeroTouchCallHomeServerProvider implements AutoCloseable, DataC
         CallHomeAuthorizationProvider provider = this.getCallHomeAuthorization();
         NetconfCallHomeServerBuilder builder = new NetconfCallHomeServerBuilder(
                 provider, mountDispacher, statusReporter);
-        if (port > 0)
+        if (port > 0) {
             builder.setBindAddress(new InetSocketAddress(port));
+        }
         server = builder.build();
         server.bind();
         mountDispacher.createTopology();
@@ -113,8 +113,10 @@ public class IetfZeroTouchCallHomeServerProvider implements AutoCloseable, DataC
 
     @VisibleForTesting
     void assertValid(Object obj, String description) {
-        if (obj == null)
-            throw new RuntimeException(String.format("Failed to find %s in IetfZeroTouchCallHomeProvider.initialize()", description));
+        if (obj == null) {
+            throw new RuntimeException(
+                String.format("Failed to find %s in IetfZeroTouchCallHomeProvider.initialize()", description));
+        }
     }
 
     @Override
@@ -134,8 +136,7 @@ public class IetfZeroTouchCallHomeServerProvider implements AutoCloseable, DataC
     }
 
     @Override
-    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-
+    public void onDataTreeChanged(Collection<DataTreeModification<AllowedDevices>> changes) {
         // In case of any changes to the devices datatree, register the changed values with callhome server
         // As of now, no way to add a new callhome client key to the CallHomeAuthorization instance since
         // its created under CallHomeAuthorizationProvider.
@@ -145,8 +146,19 @@ public class IetfZeroTouchCallHomeServerProvider implements AutoCloseable, DataC
         CheckedFuture<Optional<AllowedDevices>, ReadFailedException> devicesFuture =
                 roConfigTx.read(LogicalDatastoreType.CONFIGURATION, IetfZeroTouchCallHomeServerProvider.ALL_DEVICES);
 
-        if (hasDeletedDevices(change))
-            handleDeletedDevices(change);
+        Set<InstanceIdentifier<?>> deletedDevices = new HashSet<>();
+        for (DataTreeModification<AllowedDevices> change: changes) {
+            DataObjectModification<AllowedDevices> rootNode = change.getRootNode();
+            switch (rootNode.getModificationType()) {
+                case DELETE:
+                    deletedDevices.add(change.getRootPath().getRootIdentifier());
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        handleDeletedDevices(deletedDevices);
 
         try {
             for (Device confDevice : getReadDevices(devicesFuture)) {
@@ -157,27 +169,25 @@ public class IetfZeroTouchCallHomeServerProvider implements AutoCloseable, DataC
         }
     }
 
-    private boolean hasDeletedDevices(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-        return change.getRemovedPaths() != null;
-    }
-
-    private void handleDeletedDevices(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-        checkArgument(change.getRemovedPaths() != null);
+    private void handleDeletedDevices(Set<InstanceIdentifier<?>> deletedDevices) {
+        if (deletedDevices.isEmpty()) {
+            return;
+        }
 
         ReadWriteTransaction opTx = dataBroker.newReadWriteTransaction();
 
-        Set<InstanceIdentifier<?>> removedDevices = change.getRemovedPaths();
-        int numRemoved = removedDevices.size();
+        int numRemoved = deletedDevices.size();
 
-        Iterator<InstanceIdentifier<?>> iterator = removedDevices.iterator();
+        Iterator<InstanceIdentifier<?>> iterator = deletedDevices.iterator();
         while (iterator.hasNext()) {
             InstanceIdentifier<?> removedIID = iterator.next();
             LOG.info("Deleting the entry for callhome device {}", removedIID);
             opTx.delete(LogicalDatastoreType.OPERATIONAL, removedIID);
         }
 
-        if (numRemoved > 0)
+        if (numRemoved > 0) {
             opTx.submit();
+        }
     }
 
     private List<Device> getReadDevices(CheckedFuture<Optional<AllowedDevices>, ReadFailedException> devicesFuture)
@@ -201,7 +211,8 @@ public class IetfZeroTouchCallHomeServerProvider implements AutoCloseable, DataC
                 .child(Device.class, new DeviceKey(cfgDevice.getUniqueId()));
 
         ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
-        CheckedFuture<Optional<Device>, ReadFailedException> deviceFuture = tx.read(LogicalDatastoreType.OPERATIONAL, deviceIID);
+        CheckedFuture<Optional<Device>, ReadFailedException> deviceFuture = tx.read(
+            LogicalDatastoreType.OPERATIONAL, deviceIID);
 
         Optional<Device> opDevGet = deviceFuture.checkedGet();
         Device1 devStatus = new Device1Builder().setDeviceStatus(Device1.DeviceStatus.DISCONNECTED).build();