[ONOS-4045]Adding mastership service to NetconfProvider

Change-Id: Id39cbef54a079ab6e080a9d3f60770c4bea90b3f
diff --git a/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/NetconfControllerConfig.java b/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/NetconfControllerConfig.java
index 7c0f1b0..8f50d56 100644
--- a/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/NetconfControllerConfig.java
+++ b/drivers/netconf/src/main/java/org/onosproject/drivers/netconf/NetconfControllerConfig.java
@@ -18,6 +18,7 @@
 
 import com.google.common.base.Preconditions;
 import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.behaviour.ControllerConfig;
 import org.onosproject.net.behaviour.ControllerInfo;
@@ -44,21 +45,29 @@
 
     private final Logger log = getLogger(NetconfControllerConfig.class);
 
+
     @Override
     public List<ControllerInfo> getControllers() {
         DriverHandler handler = handler();
         NetconfController controller = handler.get(NetconfController.class);
-        DeviceId ofDeviceId = handler.data().deviceId();
+        MastershipService mastershipService = handler.get(MastershipService.class);
+        DeviceId deviceId = handler.data().deviceId();
         Preconditions.checkNotNull(controller, "Netconf controller is null");
         List<ControllerInfo> controllers = new ArrayList<>();
-        try {
-            String reply = controller.getDevicesMap().get(ofDeviceId).getSession().
-                    getConfig("running");
-            log.debug("Reply XML {}", reply);
-            controllers.addAll(XmlConfigParser.parseStreamControllers(XmlConfigParser.
-                    loadXml(new ByteArrayInputStream(reply.getBytes(StandardCharsets.UTF_8)))));
-        } catch (IOException e) {
-            log.error("Cannot communicate with device {} ", ofDeviceId);
+        if (mastershipService.isLocalMaster(deviceId)) {
+            try {
+                String reply = controller.getNetconfDevice(deviceId).getSession().
+                        getConfig("running");
+                log.debug("Reply XML {}", reply);
+                controllers.addAll(XmlConfigParser.parseStreamControllers(XmlConfigParser.
+                        loadXml(new ByteArrayInputStream(reply.getBytes(StandardCharsets.UTF_8)))));
+            } catch (IOException e) {
+                log.error("Cannot communicate with device {} ", deviceId, e);
+            }
+        } else {
+            log.warn("I'm not master for {} please use master, {} to execute command",
+                     deviceId,
+                     mastershipService.getMasterFor(deviceId));
         }
         return controllers;
     }
@@ -69,30 +78,36 @@
         NetconfController controller = handler.get(NetconfController.class);
         DeviceId deviceId = handler.data().deviceId();
         Preconditions.checkNotNull(controller, "Netconf controller is null");
-        try {
-            NetconfDevice device = controller.getNetconfDevice(deviceId);
-            String config = null;
-
+        MastershipService mastershipService = handler.get(MastershipService.class);
+        if (mastershipService.isLocalMaster(deviceId)) {
             try {
-                String reply = device.getSession().getConfig("running");
-                log.info("reply XML {}", reply);
-                config = XmlConfigParser.createControllersConfig(
-                        XmlConfigParser.loadXml(getClass().getResourceAsStream("controllers.xml")),
-                        XmlConfigParser.loadXml(
-                                new ByteArrayInputStream(reply.getBytes(StandardCharsets.UTF_8))),
-                        "running", "merge", "create", controllers
-                );
+                NetconfDevice device = controller.getNetconfDevice(deviceId);
+                String config = null;
+
+                try {
+                    String reply = device.getSession().getConfig("running");
+                    log.info("reply XML {}", reply);
+                    config = XmlConfigParser.createControllersConfig(
+                            XmlConfigParser.loadXml(getClass().getResourceAsStream("controllers.xml")),
+                            XmlConfigParser.loadXml(
+                                    new ByteArrayInputStream(reply.getBytes(StandardCharsets.UTF_8))),
+                            "running", "merge", "create", controllers
+                    );
+                } catch (IOException e) {
+                    log.error("Cannot comunicate to device {} , exception {}", deviceId, e.getMessage());
+                }
+                device.getSession().editConfig(config.substring(config.indexOf("-->") + 3));
+            } catch (NullPointerException e) {
+                log.warn("No NETCONF device with requested parameters " + e);
+                throw new NullPointerException("No NETCONF device with requested parameters " + e);
             } catch (IOException e) {
                 log.error("Cannot comunicate to device {} , exception {}", deviceId, e.getMessage());
             }
-            device.getSession().editConfig(config.substring(config.indexOf("-->") + 3));
-        } catch (NullPointerException e) {
-            log.warn("No NETCONF device with requested parameters " + e);
-            throw new NullPointerException("No NETCONF device with requested parameters " + e);
-        } catch (IOException e) {
-            log.error("Cannot comunicate to device {} , exception {}", deviceId, e.getMessage());
+        } else {
+            log.warn("I'm not master for {} please use master, {} to execute command",
+                     deviceId,
+                     mastershipService.getMasterFor(deviceId));
         }
-
     }
 
     //TODO maybe put method getNetconfClientService like in ovsdb if we need it
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfController.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfController.java
index 2a301a8..9d5fae8 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfController.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfController.java
@@ -46,31 +46,31 @@
      * Tries to connect to a specific NETCONF device, if the connection is succesful
      * it creates and adds the device to the ONOS core as a NetconfDevice.
      *
-     * @param deviceInfo info about the device to add
+     * @param deviceId deviceId of the device to connect
      * @return NetconfDevice Netconf device
      * @throws NetconfException when device is not available
      */
-    NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo) throws NetconfException;
+    NetconfDevice connectDevice(DeviceId deviceId) throws NetconfException;
 
     /**
      * Disconnects a Netconf device and removes it from the core.
      *
-     * @param deviceInfo info about the device to remove
+     * @param deviceId id of the device to remove
+     * @param remove   true if device is to be removed from core
      */
-    void disconnectDevice(NetconfDeviceInfo deviceInfo);
+    void disconnectDevice(DeviceId deviceId, boolean remove);
 
     /**
      * Removes a Netconf device from the core.
      *
-     * @param deviceInfo info about the device to remove
+     * @param deviceId id of the device to remove
      */
-    void removeDevice(NetconfDeviceInfo deviceInfo);
+    void removeDevice(DeviceId deviceId);
 
     /**
      * Gets all the nodes information.
      *
      * @return map of devices
-     *
      */
     Map<DeviceId, NetconfDevice> getDevicesMap();
 
@@ -97,5 +97,4 @@
      * @return NetconfDevice Netconf device
      */
     NetconfDevice getNetconfDevice(IpAddress ip, int port);
-
 }
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceListener.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceListener.java
index 9c46d4f..c8f0cf0 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceListener.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceListener.java
@@ -16,22 +16,25 @@
 
 package org.onosproject.netconf;
 
+import org.onosproject.net.DeviceId;
+
 /**
  * Allows for providers interested in node events to be notified.
  */
 public interface NetconfDeviceListener {
 
     /**
-     * Notifies that the node was added.
+     * Notifies that the device was added.
      *
-     * @param nodeId the node where the event occurred
+     * @param deviceId the device that was added
      */
-    void deviceAdded(NetconfDeviceInfo nodeId);
+    void deviceAdded(DeviceId deviceId);
 
     /**
-     * Notifies that the node was removed.
+     * Notifies that the device was removed.
      *
-     * @param nodeId the node where the event occurred
+     * @param deviceId the device that was removed
      */
-    void deviceRemoved(NetconfDeviceInfo nodeId);
+
+    void deviceRemoved(DeviceId deviceId);
 }
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/DefaultNetconfDevice.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/DefaultNetconfDevice.java
index 7202fb7..59d8ce7 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/DefaultNetconfDevice.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/DefaultNetconfDevice.java
@@ -35,7 +35,7 @@
             .getLogger(DefaultNetconfDevice.class);
 
     private NetconfDeviceInfo netconfDeviceInfo;
-    private boolean deviceState = false;
+    private boolean deviceState = true;
     protected NetconfSessionFactory sessionFactory = new SshNetconfSessionFactory();
     private NetconfSession netconfSession;
 
@@ -53,10 +53,10 @@
         try {
             netconfSession = sessionFactory.createNetconfSession(deviceInfo);
         } catch (IOException e) {
+            deviceState = false;
             throw new NetconfException("Cannot create connection and session for device " +
                                                deviceInfo, e);
         }
-        deviceState = true;
     }
 
     @Override
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java
index 99ef8ce..432329b 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java
@@ -19,9 +19,16 @@
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.IpAddress;
+import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.key.DeviceKeyId;
+import org.onosproject.net.key.DeviceKeyService;
+import org.onosproject.net.key.UsernamePassword;
 import org.onosproject.netconf.NetconfController;
 import org.onosproject.netconf.NetconfDevice;
 import org.onosproject.netconf.NetconfDeviceFactory;
@@ -34,6 +41,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Arrays;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -45,6 +53,11 @@
 @Component(immediate = true)
 @Service
 public class NetconfControllerImpl implements NetconfController {
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceKeyService deviceKeyService;
 
     public static final Logger log = LoggerFactory
             .getLogger(NetconfControllerImpl.class);
@@ -95,55 +108,93 @@
     }
 
     @Override
-    public NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo) throws NetconfException {
-        if (netconfDeviceMap.containsKey(deviceInfo.getDeviceId())) {
-            log.info("Device {} is already present", deviceInfo);
-            return netconfDeviceMap.get(deviceInfo.getDeviceId());
+    public NetconfDevice connectDevice(DeviceId deviceId) throws NetconfException {
+        if (netconfDeviceMap.containsKey(deviceId)) {
+            log.debug("Device {} is already present", deviceId);
+            return netconfDeviceMap.get(deviceId);
         } else {
-            log.info("Creating NETCONF device {}", deviceInfo);
-            NetconfDevice device = createDevice(deviceInfo);
-            device.getSession().addDeviceOutputListener(downListener);
-            return device;
+            log.debug("Creating NETCONF device {}", deviceId);
+            Device device = deviceService.getDevice(deviceId);
+            String ip;
+            int port;
+            if (device != null) {
+                ip = device.annotations().value("ipaddress");
+                port = Integer.parseInt(device.annotations().value("port"));
+            } else {
+                String[] info = deviceId.toString().split(":");
+                if (info.length == 3) {
+                    ip = info[1];
+                    port = Integer.parseInt(info[2]);
+                } else {
+                    ip = Arrays.asList(info).stream().filter(el -> !el.equals(info[0])
+                    && !el.equals(info[info.length - 1]))
+                            .reduce((t, u) -> t + ":" + u)
+                            .get();
+                    log.debug("ip v6 {}", ip);
+                    port = Integer.parseInt(info[info.length - 1]);
+                }
+            }
+            try {
+                UsernamePassword deviceKey = deviceKeyService.getDeviceKey(
+                        DeviceKeyId.deviceKeyId(deviceId.toString())).asUsernamePassword();
+
+                NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(deviceKey.username(),
+                                                                     deviceKey.password(),
+                                                                     IpAddress.valueOf(ip),
+                                                                     port);
+                NetconfDevice netconfDevicedevice = createDevice(deviceInfo);
+
+                netconfDevicedevice.getSession().addDeviceOutputListener(downListener);
+                return netconfDevicedevice;
+            } catch (NullPointerException e) {
+                throw new NetconfException("No Device Key for device " + deviceId, e);
+            }
         }
     }
 
     @Override
-    public void disconnectDevice(NetconfDeviceInfo deviceInfo) {
-        if (!netconfDeviceMap.containsKey(deviceInfo.getDeviceId())) {
-            log.warn("Device {} is not present", deviceInfo);
+    public void disconnectDevice(DeviceId deviceId, boolean remove) {
+        if (!netconfDeviceMap.containsKey(deviceId)) {
+            log.warn("Device {} is not present", deviceId);
         } else {
-            stopDevice(deviceInfo);
+            stopDevice(deviceId, remove);
         }
     }
 
-    @Override
-    public void removeDevice(NetconfDeviceInfo deviceInfo) {
-        if (!netconfDeviceMap.containsKey(deviceInfo.getDeviceId())) {
-            log.warn("Device {} is not present", deviceInfo);
-        } else {
-            netconfDeviceMap.remove(deviceInfo.getDeviceId());
+    private void stopDevice(DeviceId deviceId, boolean remove) {
+        netconfDeviceMap.get(deviceId).disconnect();
+        netconfDeviceMap.remove(deviceId);
+        if (remove) {
             for (NetconfDeviceListener l : netconfDeviceListeners) {
-                l.deviceRemoved(deviceInfo);
+                l.deviceRemoved(deviceId);
+            }
+        }
+    }
+
+    @Override
+    public void removeDevice(DeviceId deviceId) {
+        if (!netconfDeviceMap.containsKey(deviceId)) {
+            log.warn("Device {} is not present", deviceId);
+            for (NetconfDeviceListener l : netconfDeviceListeners) {
+                l.deviceRemoved(deviceId);
+            }
+        } else {
+            netconfDeviceMap.remove(deviceId);
+            for (NetconfDeviceListener l : netconfDeviceListeners) {
+                l.deviceRemoved(deviceId);
             }
         }
     }
 
     private NetconfDevice createDevice(NetconfDeviceInfo deviceInfo) throws NetconfException {
         NetconfDevice netconfDevice = deviceFactory.createNetconfDevice(deviceInfo);
-        for (NetconfDeviceListener l : netconfDeviceListeners) {
-            l.deviceAdded(deviceInfo);
-        }
         netconfDeviceMap.put(deviceInfo.getDeviceId(), netconfDevice);
+        for (NetconfDeviceListener l : netconfDeviceListeners) {
+            l.deviceAdded(deviceInfo.getDeviceId());
+        }
         return netconfDevice;
     }
 
-    private void stopDevice(NetconfDeviceInfo deviceInfo) {
-        netconfDeviceMap.get(deviceInfo.getDeviceId()).disconnect();
-        netconfDeviceMap.remove(deviceInfo.getDeviceId());
-        for (NetconfDeviceListener l : netconfDeviceListeners) {
-            l.deviceRemoved(deviceInfo);
-        }
-    }
 
     @Override
     public Map<DeviceId, NetconfDevice> getDevicesMap() {
@@ -155,6 +206,8 @@
         return netconfDeviceMap.keySet();
     }
 
+
+
     //Device factory for the specific NetconfDeviceImpl
     private class DefaultNetconfDeviceFactory implements NetconfDeviceFactory {
 
@@ -171,7 +224,7 @@
         @Override
         public void event(NetconfDeviceOutputEvent event) {
             if (event.type().equals(NetconfDeviceOutputEvent.Type.DEVICE_UNREGISTERED)) {
-                removeDevice(event.getDeviceInfo());
+                removeDevice(event.getDeviceInfo().getDeviceId());
             }
         }
 
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
index d554880..ce37e80 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
@@ -375,13 +375,12 @@
 
     private boolean close(boolean force) throws NetconfException {
         StringBuilder rpc = new StringBuilder();
-        rpc.append("<rpc>");
+        rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
         if (force) {
-            rpc.append("<kill-configuration/>");
+            rpc.append("<kill-session/>");
         } else {
-            rpc.append("<close-configuration/>");
+            rpc.append("<close-session/>");
         }
-        rpc.append("<close-configuration/>");
         rpc.append("</rpc>");
         rpc.append(ENDPATTERN);
         return checkReply(sendRequest(rpc.toString())) || close(true);
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfControllerImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfControllerImplTest.java
index 931bfd4..03bb53e 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfControllerImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfControllerImplTest.java
@@ -22,6 +22,8 @@
 import org.junit.Test;
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.key.DeviceKeyService;
 import org.onosproject.netconf.NetconfDevice;
 import org.onosproject.netconf.NetconfDeviceFactory;
 import org.onosproject.netconf.NetconfDeviceInfo;
@@ -44,12 +46,14 @@
  * Unit tests for the Netconf controller implementation test.
  */
 public class NetconfControllerImplTest {
+
     NetconfControllerImpl ctrl;
 
     //DeviceInfo
     NetconfDeviceInfo deviceInfo1;
     NetconfDeviceInfo deviceInfo2;
     NetconfDeviceInfo badDeviceInfo3;
+    NetconfDeviceInfo deviceInfoIpV6;
 
     //Devices & DeviceId
     NetconfDevice device1;
@@ -68,21 +72,29 @@
     private static final String DEVICE_1_IP = "10.10.10.11";
     private static final String DEVICE_2_IP = "10.10.10.12";
     private static final String BAD_DEVICE_IP = "10.10.10.13";
+    private static final String DEVICE_IPV6 = "2001:db8::1";
 
     private static final int DEVICE_1_PORT = 11;
     private static final int DEVICE_2_PORT = 12;
     private static final int BAD_DEVICE_PORT = 13;
+    private static final int IPV6_DEVICE_PORT = 14;
+
+    private static DeviceService deviceService = new NetconfDeviceServiceMock();
+    private static DeviceKeyService deviceKeyService = new NetconfDeviceKeyServiceMock();
 
 
     @Before
     public void setUp() throws Exception {
         ctrl = new NetconfControllerImpl();
         ctrl.deviceFactory = new TestNetconfDeviceFactory();
+        ctrl.deviceService = deviceService;
+        ctrl.deviceKeyService = deviceKeyService;
 
         //Creating mock devices
         deviceInfo1 = new NetconfDeviceInfo("device1", "001", IpAddress.valueOf(DEVICE_1_IP), DEVICE_1_PORT);
         deviceInfo2 = new NetconfDeviceInfo("device2", "002", IpAddress.valueOf(DEVICE_2_IP), DEVICE_2_PORT);
         badDeviceInfo3 = new NetconfDeviceInfo("device3", "003", IpAddress.valueOf(BAD_DEVICE_IP), BAD_DEVICE_PORT);
+        deviceInfoIpV6 = new NetconfDeviceInfo("deviceIpv6", "004", IpAddress.valueOf(DEVICE_IPV6), IPV6_DEVICE_PORT);
 
         device1 = new TestNetconfDevice(deviceInfo1);
         deviceId1 = deviceInfo1.getDeviceId();
@@ -102,9 +114,9 @@
         reflectedDownListener = (NetconfDeviceOutputEventListener) field2.get(ctrl);
 
         eventForDeviceInfo1 = new NetconfDeviceOutputEvent(NetconfDeviceOutputEvent.Type.DEVICE_NOTIFICATION, null,
-                null, Optional.of(1), deviceInfo1);
+                                                           null, Optional.of(1), deviceInfo1);
         eventForDeviceInfo2 = new NetconfDeviceOutputEvent(NetconfDeviceOutputEvent.Type.DEVICE_UNREGISTERED, null,
-                null, Optional.of(2), deviceInfo2);
+                                                           null, Optional.of(2), deviceInfo2);
     }
 
     @After
@@ -128,7 +140,7 @@
         ctrl.addDeviceListener(deviceListener3);
         assertThat("Incorrect number of listeners", ctrl.netconfDeviceListeners, hasSize(3));
         assertThat("Not matching listeners", ctrl.netconfDeviceListeners, hasItems(deviceListener1,
-                deviceListener2, deviceListener3));
+                                                                                   deviceListener2, deviceListener3));
 
         ctrl.removeDeviceListener(deviceListener1);
         assertThat("Incorrect number of listeners", ctrl.netconfDeviceListeners, hasSize(2));
@@ -168,7 +180,7 @@
     public void testConnectBadDevice() throws Exception {
         reflectedDeviceMap.clear();
         try {
-            ctrl.connectDevice(badDeviceInfo3);
+            ctrl.connectDevice(badDeviceInfo3.getDeviceId());
         } finally {
             assertEquals("Incorrect device connection", 0, ctrl.getDevicesMap().size());
         }
@@ -180,25 +192,37 @@
     @Test
     public void testConnectCorrectDevice() throws Exception {
         reflectedDeviceMap.clear();
-        ctrl.connectDevice(deviceInfo1);
-        ctrl.connectDevice(deviceInfo2);
+        ctrl.connectDevice(deviceInfo1.getDeviceId());
+        ctrl.connectDevice(deviceInfo2.getDeviceId());
         assertTrue("Incorrect device connection", ctrl.getDevicesMap().containsKey(deviceId1));
         assertTrue("Incorrect device connection", ctrl.getDevicesMap().containsKey(deviceId2));
         assertEquals("Incorrect device connection", 2, ctrl.getDevicesMap().size());
     }
 
+    /**
+     * Check for correct ipv6 device connection. In this case the device map get modified.
+     */
+    @Test
+    public void testConnectCorrectIpv6Device() throws Exception {
+        reflectedDeviceMap.clear();
+        ctrl.connectDevice(deviceInfoIpV6.getDeviceId());
+        assertTrue("Incorrect device connection", ctrl.getDevicesMap()
+                .containsKey(deviceInfoIpV6.getDeviceId()));
+        assertEquals("Incorrect device connection", 1, ctrl.getDevicesMap().size());
+    }
+
 
     /**
      * Check for connect devices already added to the map.
      */
     @Test
     public void testConnectAlreadyExistingDevice() throws Exception {
-        NetconfDevice alreadyExistingDevice1 = ctrl.connectDevice(deviceInfo1);
-        NetconfDevice alreadyExistingDevice2 = ctrl.connectDevice(deviceInfo2);
+        NetconfDevice alreadyExistingDevice1 = ctrl.connectDevice(deviceInfo1.getDeviceId());
+        NetconfDevice alreadyExistingDevice2 = ctrl.connectDevice(deviceInfo2.getDeviceId());
         assertEquals("Incorrect device connection", alreadyExistingDevice1.getDeviceInfo().getDeviceId(),
-                deviceInfo1.getDeviceId());
+                     deviceInfo1.getDeviceId());
         assertEquals("Incorrect device connection", alreadyExistingDevice2.getDeviceInfo().getDeviceId(),
-                deviceInfo2.getDeviceId());
+                     deviceInfo2.getDeviceId());
     }
 
     /**
@@ -206,7 +230,7 @@
      */
     @Test
     public void testDisconnectDevice() throws Exception {
-        ctrl.disconnectDevice(deviceInfo1);
+        ctrl.disconnectDevice(deviceInfo1.getDeviceId(), true);
         assertFalse("Incorrect device removal", ctrl.getDevicesMap().containsKey(deviceId1));
     }
 
@@ -215,7 +239,7 @@
      */
     @Test
     public void testRemoveDevice() throws Exception {
-        ctrl.removeDevice(deviceInfo1);
+        ctrl.removeDevice(deviceInfo1.getDeviceId());
         assertFalse("Incorrect device removal", ctrl.getDevicesMap().containsKey(deviceId1));
     }
 
@@ -234,13 +258,13 @@
     @Test
     public void testDeviceDownEventListener() throws Exception {
         reflectedDeviceMap.clear();
-        ctrl.connectDevice(deviceInfo1);
+        ctrl.connectDevice(deviceInfo1.getDeviceId());
         boolean result1 = reflectedDownListener.isRelevant(eventForDeviceInfo2);
         assertFalse("Irrelevant Device Event", result1);
         assertEquals("Incorrect device map size", 1, ctrl.getDevicesMap().size());
         reflectedDownListener.event(eventForDeviceInfo1);
         assertEquals("Incorrect device map size", 1, ctrl.getDevicesMap().size());
-        ctrl.connectDevice(deviceInfo2);
+        ctrl.connectDevice(deviceInfo2.getDeviceId());
         boolean result2 = reflectedDownListener.isRelevant(eventForDeviceInfo2);
         assertTrue("Irrelevant Device Event", result2);
         assertEquals("Incorrect device map size", 2, ctrl.getDevicesMap().size());
@@ -269,7 +293,7 @@
 
         public TestNetconfDevice(NetconfDeviceInfo deviceInfo) throws NetconfException {
             netconfDeviceInfo = deviceInfo;
-            if (netconfDeviceInfo.ip() != badDeviceInfo3.ip()) {
+            if (!badDeviceInfo3.getDeviceId().equals(deviceInfo.getDeviceId())) {
                 netconfSession = EasyMock.createMock(NetconfSession.class);
                 deviceState = true;
             } else {
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfDeviceKeyServiceMock.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfDeviceKeyServiceMock.java
new file mode 100644
index 0000000..ace87fb
--- /dev/null
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfDeviceKeyServiceMock.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.netconf.ctl;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.key.DeviceKey;
+import org.onosproject.net.key.DeviceKeyId;
+import org.onosproject.net.key.DeviceKeyListener;
+import org.onosproject.net.key.DeviceKeyService;
+import org.onosproject.netconf.NetconfDeviceInfo;
+
+import java.util.Collection;
+
+/**
+ * Mock DeviceKey service to return device keys.
+ */
+class NetconfDeviceKeyServiceMock implements DeviceKeyService {
+
+    private static final String DEVICE_1_IP = "10.10.10.11";
+    private static final String DEVICE_2_IP = "10.10.10.12";
+    private static final String BAD_DEVICE_IP = "10.10.10.13";
+    private static final String DEVICE_IPV6 = "2001:db8::1";
+
+    private static final int DEVICE_1_PORT = 11;
+    private static final int DEVICE_2_PORT = 12;
+    private static final int BAD_DEVICE_PORT = 13;
+    private static final int IPV6_DEVICE_PORT = 14;
+
+    //DeviceInfo
+    private NetconfDeviceInfo deviceInfo1 =
+            new NetconfDeviceInfo("device1", "001", IpAddress.valueOf(DEVICE_1_IP),
+                                  DEVICE_1_PORT);
+    private NetconfDeviceInfo deviceInfo2 =
+            new NetconfDeviceInfo("device2", "002", IpAddress.valueOf(DEVICE_2_IP),
+                                  DEVICE_2_PORT);
+    private NetconfDeviceInfo badDeviceInfo3 =
+            new NetconfDeviceInfo("device3", "003", IpAddress.valueOf(BAD_DEVICE_IP),
+                                  BAD_DEVICE_PORT);
+    private NetconfDeviceInfo deviceInfoIpV6 =
+            new NetconfDeviceInfo("deviceIpv6", "004", IpAddress.valueOf(DEVICE_IPV6), IPV6_DEVICE_PORT);
+
+    @Override
+    public Collection<DeviceKey> getDeviceKeys() {
+        return null;
+    }
+
+    @Override
+    public DeviceKey getDeviceKey(DeviceKeyId deviceKeyId) {
+        if (deviceKeyId.toString().equals(deviceInfo1.getDeviceId().toString())) {
+            return DeviceKey.createDeviceKeyUsingUsernamePassword(
+                    DeviceKeyId.deviceKeyId(deviceInfo1.getDeviceId().toString()),
+                    null, deviceInfo1.name(), deviceInfo1.password());
+        } else if (deviceKeyId.toString().equals(deviceInfo2.getDeviceId().toString())) {
+            return DeviceKey.createDeviceKeyUsingUsernamePassword(
+                    DeviceKeyId.deviceKeyId(deviceInfo2.getDeviceId().toString()),
+                    null, deviceInfo2.name(), deviceInfo2.password());
+        } else if (deviceKeyId.toString().equals(badDeviceInfo3.getDeviceId().toString())) {
+            return DeviceKey.createDeviceKeyUsingUsernamePassword(
+                    DeviceKeyId.deviceKeyId(badDeviceInfo3.getDeviceId().toString()),
+                    null, badDeviceInfo3.name(), badDeviceInfo3.password());
+        } else if (deviceKeyId.toString().equals(deviceInfoIpV6.getDeviceId().toString())) {
+            return DeviceKey.createDeviceKeyUsingUsernamePassword(
+                    DeviceKeyId.deviceKeyId(deviceInfoIpV6.getDeviceId().toString()),
+                    null, deviceInfoIpV6.name(), deviceInfoIpV6.password());
+        }
+        return null;
+    }
+
+    @Override
+    public void addListener(DeviceKeyListener listener) {
+
+    }
+
+    @Override
+    public void removeListener(DeviceKeyListener listener) {
+
+    }
+}
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfDeviceServiceMock.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfDeviceServiceMock.java
new file mode 100644
index 0000000..e355bbd
--- /dev/null
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfDeviceServiceMock.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.netconf.ctl;
+
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.PortStatistics;
+
+import java.util.List;
+
+/**
+ * Mock device Service.
+ */
+class NetconfDeviceServiceMock implements DeviceService {
+
+    @Override
+    public int getDeviceCount() {
+        return 0;
+    }
+
+    @Override
+    public Iterable<Device> getDevices() {
+        return null;
+    }
+
+    @Override
+    public Iterable<Device> getDevices(Device.Type type) {
+        return null;
+    }
+
+    @Override
+    public Iterable<Device> getAvailableDevices() {
+        return null;
+    }
+
+    @Override
+    public Iterable<Device> getAvailableDevices(Device.Type type) {
+        return null;
+    }
+
+    @Override
+    public Device getDevice(DeviceId deviceId) {
+        return null;
+    }
+
+    @Override
+    public MastershipRole getRole(DeviceId deviceId) {
+        return null;
+    }
+
+    @Override
+    public List<Port> getPorts(DeviceId deviceId) {
+        return null;
+    }
+
+    @Override
+    public List<PortStatistics> getPortStatistics(DeviceId deviceId) {
+        return null;
+    }
+
+    @Override
+    public List<PortStatistics> getPortDeltaStatistics(DeviceId deviceId) {
+        return null;
+    }
+
+    @Override
+    public Port getPort(DeviceId deviceId, PortNumber portNumber) {
+        return null;
+    }
+
+    @Override
+    public boolean isAvailable(DeviceId deviceId) {
+        return false;
+    }
+
+    @Override
+    public void addListener(DeviceListener listener) {
+
+    }
+
+    @Override
+    public void removeListener(DeviceListener listener) {
+
+    }
+}
\ No newline at end of file
diff --git a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java b/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
index 9d2be56..6025e07 100644
--- a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
+++ b/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
@@ -23,9 +23,12 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.ChassisId;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.NodeId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.incubator.net.config.basics.ConfigException;
+import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.Device;
@@ -39,21 +42,27 @@
 import org.onosproject.net.config.NetworkConfigRegistry;
 import org.onosproject.net.device.DefaultDeviceDescription;
 import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceProvider;
 import org.onosproject.net.device.DeviceProviderRegistry;
 import org.onosproject.net.device.DeviceProviderService;
 import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.key.DeviceKey;
+import org.onosproject.net.key.DeviceKeyAdminService;
+import org.onosproject.net.key.DeviceKeyId;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.netconf.NetconfController;
-import org.onosproject.netconf.NetconfDevice;
-import org.onosproject.netconf.NetconfDeviceInfo;
 import org.onosproject.netconf.NetconfDeviceListener;
 import org.onosproject.netconf.NetconfException;
 import org.slf4j.Logger;
 
 import java.io.IOException;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -67,6 +76,8 @@
 @Component(immediate = true)
 public class NetconfDeviceProvider extends AbstractProvider
         implements DeviceProvider {
+
+    public static final String ACTIVE = "active";
     private final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -82,21 +93,36 @@
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DriverService driverService;
+    protected DeviceService deviceService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DeviceService deviceService;
+    protected DeviceKeyAdminService deviceKeyAdminService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MastershipService mastershipService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterService clusterService;
 
     private static final String APP_NAME = "org.onosproject.netconf";
     private static final String SCHEME_NAME = "netconf";
     private static final String DEVICE_PROVIDER_PACKAGE = "org.onosproject.netconf.provider.device";
     private static final String UNKNOWN = "unknown";
+    protected static final String ISNULL = "NetconfDeviceInfo is null";
+    private static final String IPADDRESS = "ipaddress";
+    private static final String NETCONF = "netconf";
+    private static final String PORT = "port";
+    //FIXME eventually a property
+    private static final int ISREACHABLE_TIMEOUT = 2000;
 
     private final ExecutorService executor =
-            Executors.newFixedThreadPool(5, groupedThreads("onos/netconfdeviceprovider", "device-installer-%d", log));
+            Executors.newFixedThreadPool(5, groupedThreads("onos/netconfdeviceprovider",
+                                                           "device-installer-%d", log));
 
     private DeviceProviderService providerService;
     private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener();
+    private InternalDeviceListener deviceListener = new InternalDeviceListener();
+    private NodeId localNodeId;
 
     private final ConfigFactory factory =
             new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY,
@@ -108,31 +134,40 @@
                     return new NetconfProviderConfig();
                 }
             };
-    private final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
+    private final NetworkConfigListener cfgListener = new InternalNetworkConfigListener();
     private ApplicationId appId;
+    private boolean active;
 
 
     @Activate
     public void activate() {
+        active = true;
         providerService = providerRegistry.register(this);
         appId = coreService.registerApplication(APP_NAME);
         cfgService.registerConfigFactory(factory);
-        cfgService.addListener(cfgLister);
+        cfgService.addListener(cfgListener);
         controller.addDeviceListener(innerNodeListener);
+        deviceService.addListener(deviceListener);
         executor.execute(NetconfDeviceProvider.this::connectDevices);
+        localNodeId = clusterService.getLocalNode().id();
         log.info("Started");
     }
 
 
     @Deactivate
     public void deactivate() {
+        deviceService.removeListener(deviceListener);
+        active = false;
+        controller.getNetconfDevices().forEach(id -> {
+            deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(id.toString()));
+            controller.disconnectDevice(id, true);
+        });
         controller.removeDeviceListener(innerNodeListener);
-        controller.getNetconfDevices().forEach(id ->
-            controller.removeDevice(controller.getDevicesMap().get(id)
-                                            .getDeviceInfo()));
+        deviceService.removeListener(deviceListener);
         providerRegistry.unregister(this);
         providerService = null;
         cfgService.unregisterConfigFactory(factory);
+        executor.shutdown();
         log.info("Stopped");
     }
 
@@ -148,52 +183,87 @@
 
     @Override
     public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
-        // TODO: This will be implemented later.
+        if (active) {
+            switch (newRole) {
+                case MASTER:
+                    initiateConnection(deviceId, newRole);
+                    log.debug("Accepting mastership role change to {} for device {}", newRole, deviceId);
+                    break;
+                case STANDBY:
+                    controller.disconnectDevice(deviceId, false);
+                    providerService.receivedRoleReply(deviceId, newRole, MastershipRole.STANDBY);
+                    //else no-op
+                    break;
+                case NONE:
+                    controller.disconnectDevice(deviceId, false);
+                    providerService.receivedRoleReply(deviceId, newRole, MastershipRole.NONE);
+                    break;
+                default:
+                    log.error("Unimplemented Mastership state : {}", newRole);
+
+            }
+        }
     }
 
     @Override
     public boolean isReachable(DeviceId deviceId) {
-        NetconfDevice netconfDevice = controller.getNetconfDevice(deviceId);
-        if (netconfDevice == null) {
-            log.debug("Requested device id: {} is not associated to any " +
-                              "NETCONF Device", deviceId.toString());
-            return false;
+        //FIXME this is a workaround util device state is shared
+        // between controller instances.
+        Device device = deviceService.getDevice(deviceId);
+        String ip;
+        int port;
+        Socket socket = null;
+        if (device != null) {
+            ip = device.annotations().value(IPADDRESS);
+            port = Integer.parseInt(device.annotations().value(PORT));
+        } else {
+            String[] info = deviceId.toString().split(":");
+            if (info.length == 3) {
+                ip = info[1];
+                port = Integer.parseInt(info[2]);
+            } else {
+                ip = Arrays.asList(info).stream().filter(el -> !el.equals(info[0])
+                        && !el.equals(info[info.length - 1]))
+                        .reduce((t, u) -> t + ":" + u)
+                        .get();
+                log.debug("ip v6 {}", ip);
+                port = Integer.parseInt(info[info.length - 1]);
+            }
         }
-        return netconfDevice.isActive();
+        //test connection to device opening a socket to it.
+        try {
+            socket = new Socket(ip, port);
+            log.debug("rechability of {}, {}, {}", deviceId, socket.isConnected() && !socket.isClosed());
+            return socket.isConnected() && !socket.isClosed();
+        } catch (IOException e) {
+            log.info("Device {} is not reachable", deviceId);
+            return false;
+        } finally {
+            if (socket != null) {
+                try {
+                    socket.close();
+                } catch (IOException e) {
+                    log.debug("Test Socket failed {} ", deviceId);
+                    return false;
+                }
+            }
+        }
     }
 
     private class InnerNetconfDeviceListener implements NetconfDeviceListener {
 
-        private static final String IPADDRESS = "ipaddress";
-        protected static final String ISNULL = "NetconfDeviceInfo is null";
 
         @Override
-        public void deviceAdded(NetconfDeviceInfo nodeId) {
-            Preconditions.checkNotNull(nodeId, ISNULL);
-            DeviceId deviceId = nodeId.getDeviceId();
-            //Netconf configuration object
-            ChassisId cid = new ChassisId();
-            String ipAddress = nodeId.ip().toString();
-            SparseAnnotations annotations = DefaultAnnotations.builder()
-                    .set(IPADDRESS, ipAddress)
-                    .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
-                    .build();
-            DeviceDescription deviceDescription = new DefaultDeviceDescription(
-                    deviceId.uri(),
-                    Device.Type.SWITCH,
-                    UNKNOWN, UNKNOWN,
-                    UNKNOWN, UNKNOWN,
-                    cid,
-                    annotations);
-            providerService.deviceConnected(deviceId, deviceDescription);
+        public void deviceAdded(DeviceId deviceId) {
+            //no-op
+            log.debug("Netconf device {} added to Netconf subController", deviceId);
         }
 
         @Override
-        public void deviceRemoved(NetconfDeviceInfo nodeId) {
-            Preconditions.checkNotNull(nodeId, ISNULL);
-            DeviceId deviceId = nodeId.getDeviceId();
+        public void deviceRemoved(DeviceId deviceId) {
+            Preconditions.checkNotNull(deviceId, ISNULL);
+            log.debug("Netconf device {} removed from Netconf subController", deviceId);
             providerService.deviceDisconnected(deviceId);
-
         }
     }
 
@@ -201,41 +271,85 @@
         NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
         if (cfg != null) {
             try {
-                cfg.getDevicesAddresses().stream()
-                        .forEach(addr -> {
-                                     try {
-                                         NetconfDeviceInfo netconf = new NetconfDeviceInfo(addr.name(),
-                                                               addr.password(),
-                                                               addr.ip(),
-                                                               addr.port());
-                                         controller.connectDevice(netconf);
-                                         Device device = deviceService.getDevice(netconf.getDeviceId());
-                                         if (device.is(PortDiscovery.class)) {
-                                             PortDiscovery portConfig = device.as(PortDiscovery.class);
-                                             if (portConfig != null) {
-                                                 providerService.updatePorts(netconf.getDeviceId(),
-                                                                             portConfig.getPorts());
-                                             }
-                                         } else {
-                                             log.warn("No portGetter behaviour for device {}", netconf.getDeviceId());
-                                         }
+                cfg.getDevicesAddresses().stream().forEach(addr -> {
+                    DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
+                    Preconditions.checkNotNull(deviceId, ISNULL);
+                    //Netconf configuration object
+                    ChassisId cid = new ChassisId();
+                    String ipAddress = addr.ip().toString();
+                    SparseAnnotations annotations = DefaultAnnotations.builder()
+                            .set(IPADDRESS, ipAddress)
+                            .set(PORT, String.valueOf(addr.port()))
+                            .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
+                            .build();
+                    DeviceDescription deviceDescription = new DefaultDeviceDescription(
+                            deviceId.uri(),
+                            Device.Type.SWITCH,
+                            UNKNOWN, UNKNOWN,
+                            UNKNOWN, UNKNOWN,
+                            cid,
+                            annotations);
+                    deviceKeyAdminService.addKey(
+                            DeviceKey.createDeviceKeyUsingUsernamePassword(
+                                    DeviceKeyId.deviceKeyId(deviceId.toString()),
+                                    null, addr.name(), addr.password()));
+                    providerService.deviceConnected(deviceId, deviceDescription);
 
-                                     } catch (IOException e) {
-                                         throw new RuntimeException(
-                                                 new NetconfException(
-                                                         "Can't connect to NETCONF " +
-                                                                 "device on " + addr.ip() +
-                                                                 ":" + addr.port(), e));
-                                     }
-                                 }
-                        );
 
+                });
             } catch (ConfigException e) {
                 log.error("Cannot read config error " + e);
             }
         }
     }
 
+    private void initiateConnection(DeviceId deviceId, MastershipRole newRole) {
+        try {
+            if (isReachable(deviceId)) {
+                controller.connectDevice(deviceId);
+                providerService.receivedRoleReply(deviceId, newRole, MastershipRole.MASTER);
+            } else {
+                return;
+            }
+        } catch (Exception e) {
+            if (deviceService.getDevice(deviceId) != null) {
+                providerService.deviceDisconnected(deviceId);
+            }
+            deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(deviceId.toString()));
+            throw new RuntimeException(new NetconfException(
+                    "Can't connect to NETCONF " + "device on " + deviceId + ":" + deviceId, e));
+
+        }
+    }
+
+    private void discoverPorts(DeviceId deviceId) {
+        Device device = deviceService.getDevice(deviceId);
+        if (device.is(PortDiscovery.class)) {
+            PortDiscovery portConfig = device.as(PortDiscovery.class);
+            providerService.updatePorts(deviceId,
+                                        portConfig.getPorts());
+        } else {
+            log.warn("No portGetter behaviour for device {}", deviceId);
+        }
+    }
+
+    /**
+     * Return the DeviceId about the device containing the URI.
+     *
+     * @return DeviceId
+     */
+    public DeviceId getDeviceId(String ip, int port) {
+        try {
+            return DeviceId.deviceId(new URI(NETCONF, ip + ":" + port, null));
+        } catch (URISyntaxException e) {
+            throw new IllegalArgumentException("Unable to build deviceID for device "
+                                                       + ip + ":" + port, e);
+        }
+    }
+
+    /**
+     * Listener for configuration events.
+     */
     private class InternalNetworkConfigListener implements NetworkConfigListener {
 
 
@@ -246,10 +360,35 @@
 
         @Override
         public boolean isRelevant(NetworkConfigEvent event) {
-            //TODO refactor
             return event.configClass().equals(NetconfProviderConfig.class) &&
                     (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
                             event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
         }
     }
+
+    /**
+     * Listener for core device events.
+     */
+    private class InternalDeviceListener implements DeviceListener {
+        @Override
+        public void event(DeviceEvent event) {
+            if ((event.type() == DeviceEvent.Type.DEVICE_ADDED)) {
+                executor.execute(() -> discoverPorts(event.subject().id()));
+            } else if ((event.type() == DeviceEvent.Type.DEVICE_REMOVED)) {
+                log.debug("removing device {}", event.subject().id());
+                deviceService.getDevice(event.subject().id()).annotations().keys();
+                controller.disconnectDevice(event.subject().id(), true);
+            }
+        }
+
+        @Override
+        public boolean isRelevant(DeviceEvent event) {
+            if (mastershipService.getMasterFor(event.subject().id()) == null) {
+                return true;
+            }
+            return event.subject().annotations().value(AnnotationKeys.PROTOCOL)
+                    .equals(SCHEME_NAME.toUpperCase()) &&
+                    mastershipService.getMasterFor(event.subject().id()).equals(localNodeId);
+        }
+    }
 }
diff --git a/tools/test/cells/andrea b/tools/test/cells/andrea
index 0074f2d..1f1dded 100644
--- a/tools/test/cells/andrea
+++ b/tools/test/cells/andrea
@@ -8,4 +8,4 @@
 
 export OCT=$OC1
 export ONOS_USE_SSH=true
-export ONOS_APPS=drivers,openflow,proxyarp,ovsdb,pathpainter
+export ONOS_APPS=drivers,openflow,proxyarp,ovsdb,pathpainter
\ No newline at end of file