[VOL-1036] Device management implementation.  This update includes
the the ability to reboot and delete a device.  It contains changes
to both the Go Core and the Twisted ponsim adapters.

Change-Id: I15539827c654d7186cdae3300a107ffc8e921756
diff --git a/adapters/iadapter.py b/adapters/iadapter.py
index 3388d5a..8cdcd6e 100644
--- a/adapters/iadapter.py
+++ b/adapters/iadapter.py
@@ -109,18 +109,20 @@
 
     def disable_device(self, device):
         log.info('disable-device', device_id=device.id)
-        reactor.callLater(1, self.devices_handlers[device.id].disable)
-        log.debug('disable_device_done', device_id=device.id)
+        reactor.callLater(0, self.devices_handlers[device.id].disable)
+        log.debug('disable-device-done', device_id=device.id)
         return device
 
     def reenable_device(self, device):
         log.info('reenable-device', device_id=device.id)
         reactor.callLater(0, self.devices_handlers[device.id].reenable)
+        log.info('reenable-device-done', device_id=device.id)
         return device
 
     def reboot_device(self, device):
         log.info('reboot-device', device_id=device.id)
         reactor.callLater(0, self.devices_handlers[device.id].reboot)
+        log.info('reboot-device-done', device_id=device.id)
         return device
 
     def download_image(self, device, request):
@@ -139,14 +141,15 @@
         raise NotImplementedError()
 
     def self_test_device(self, device):
-        log.info('self-test-req', device_id=device.id)
+        log.info('self-test', device_id=device.id)
         result = reactor.callLater(0, self.devices_handlers[device.id].self_test_device)
+        log.info('self-test-done', device_id=device.id)
         return result
 
     def delete_device(self, device):
         log.info('delete-device', device_id=device.id)
-        #  TODO: Update the logical device mapping
         reactor.callLater(0, self.devices_handlers[device.id].delete)
+        log.info('delete-device-done', device_id=device.id)
         return device
 
     def get_device_details(self, device):
diff --git a/adapters/kafka/adapter_request_facade.py b/adapters/kafka/adapter_request_facade.py
index 2517a31..f4898a3 100644
--- a/adapters/kafka/adapter_request_facade.py
+++ b/adapters/kafka/adapter_request_facade.py
@@ -156,10 +156,12 @@
         return self.adapter.self_test_device(device)
 
     def delete_device(self, device):
-        # Remove all child devices
-        self.delete_all_child_devices(device.id)
-
-        return self.adapter.delete_device(device)
+        d = Device()
+        if device:
+            device.Unpack(d)
+            return (True, self.adapter.delete_device(d))
+        else:
+            return (False, d)
 
     def get_device_details(self, device):
         return self.adapter.get_device_details(device)
diff --git a/adapters/kafka/core_proxy.py b/adapters/kafka/core_proxy.py
index 32a4c9d..512262f 100644
--- a/adapters/kafka/core_proxy.py
+++ b/adapters/kafka/core_proxy.py
@@ -259,6 +259,31 @@
                                 connect_status=c_status)
         returnValue(res)
 
+
+    @wrap_request(None)
+    @inlineCallbacks
+    def children_state_update(self, device_id,
+                            oper_status=None,
+                            connect_status=None):
+        id = ID()
+        id.id = device_id
+        o_status = IntType()
+        if oper_status or oper_status==OperStatus.UNKNOWN:
+            o_status.val = oper_status
+        else:
+            o_status.val = -1
+        c_status = IntType()
+        if connect_status or connect_status==ConnectStatus.UNKNOWN:
+            c_status.val = connect_status
+        else:
+            c_status.val = -1
+
+        res = yield self.invoke(rpc="ChildrenStateUpdate",
+                                device_id=id,
+                                oper_status=o_status,
+                                connect_status=c_status)
+        returnValue(res)
+
     @wrap_request(None)
     @inlineCallbacks
     def port_state_update(self,
diff --git a/adapters/ponsim_olt/ponsim_olt.py b/adapters/ponsim_olt/ponsim_olt.py
index 95bafaa..e47d14d 100644
--- a/adapters/ponsim_olt/ponsim_olt.py
+++ b/adapters/ponsim_olt/ponsim_olt.py
@@ -48,6 +48,11 @@
 from adapters.protos.ponsim_pb2 import FlowTable, PonSimFrame
 from adapters.protos.core_adapter_pb2 import SwitchCapability, PortCapability
 from adapters.common.utils.registry import registry
+from adapters.kafka.kafka_proxy import get_kafka_proxy
+from simplejson import dumps
+from google.protobuf.json_format import MessageToDict
+from google.protobuf.message import Message
+
 
 _ = third_party
 log = structlog.get_logger()
@@ -370,6 +375,7 @@
             )
         )
 
+    # TODO - change for core 2.0
     def reconcile(self, device):
         self.log.info('reconciling-OLT-device-starts')
 
@@ -537,34 +543,23 @@
     def reboot(self):
         self.log.info('rebooting', device_id=self.device_id)
 
-        # Update the operational status to ACTIVATING and connect status to
-        # UNREACHABLE
-        device = self.adapter_agent.get_device(self.device_id)
-        previous_oper_status = device.oper_status
-        previous_conn_status = device.connect_status
-        device.oper_status = OperStatus.ACTIVATING
-        device.connect_status = ConnectStatus.UNREACHABLE
-        self.adapter_agent.device_update(device)
+        yield self.adapter_agent.device_state_update(self.device_id, connect_status=ConnectStatus.UNREACHABLE)
 
-        # Update the child devices connect state to UNREACHABLE
-        self.adapter_agent.update_child_devices_state(self.device_id,
+       # Update the child devices connect state to UNREACHABLE
+        yield self.adapter_agent.children_state_update(self.device_id,
                                                       connect_status=ConnectStatus.UNREACHABLE)
 
         # Sleep 10 secs, simulating a reboot
         # TODO: send alert and clear alert after the reboot
         yield asleep(10)
 
-        # Change the operational status back to its previous state.  With a
-        # real OLT the operational state should be the state the device is
-        # after a reboot.
-        # Get the latest device reference
-        device = self.adapter_agent.get_device(self.device_id)
-        device.oper_status = previous_oper_status
-        device.connect_status = previous_conn_status
-        self.adapter_agent.device_update(device)
+        # Change the connection status back to REACHABLE.  With a
+        # real OLT the connection state must be the actual state
+        yield self.adapter_agent.device_state_update(self.device_id, connect_status=ConnectStatus.REACHABLE)
+
 
         # Update the child devices connect state to REACHABLE
-        self.adapter_agent.update_child_devices_state(self.device_id,
+        yield self.adapter_agent.children_state_update(self.device_id,
                                                       connect_status=ConnectStatus.REACHABLE)
 
         self.log.info('rebooted', device_id=self.device_id)
@@ -652,6 +647,8 @@
 
     def start_kpi_collection(self, device_id):
 
+        kafka_cluster_proxy = get_kafka_proxy()
+
         def _collect(device_id, prefix):
 
             try:
@@ -675,8 +672,11 @@
                     }
                 )
 
-                # Step 3: submit
-                self.adapter_agent.submit_kpis(kpi_event)
+                # Step 3: submit directlt to kafka bus
+                if kafka_cluster_proxy:
+                    if isinstance(kpi_event, Message):
+                        kpi_event = dumps(MessageToDict(kpi_event, True, True))
+                    kafka_cluster_proxy.send_message("voltha.kpis", kpi_event)
 
             except Exception as e:
                 log.exception('failed-to-submit-kpis', e=e)
diff --git a/adapters/ponsim_onu/ponsim_onu.py b/adapters/ponsim_onu/ponsim_onu.py
index d1b2e27..a9d3710 100644
--- a/adapters/ponsim_onu/ponsim_onu.py
+++ b/adapters/ponsim_onu/ponsim_onu.py
@@ -79,14 +79,6 @@
         self.log.info('activating')
 
         # TODO:  Register for proxy address
-        # # first we verify that we got parent reference and proxy info
-        # assert device.parent_id
-        # assert device.proxy_address.device_id
-        # assert device.proxy_address.channel_id
-        #
-        # # register for proxied messages right away
-        # self.proxy_address = device.proxy_address
-        # self.adapter_agent.register_for_proxied_messages(device.proxy_address)
 
         # populate device info
         device.root = False
@@ -95,7 +87,7 @@
         # device.connect_status = ConnectStatus.REACHABLE
         yield self.adapter_agent.device_update(device)
 
-    # register physical ports
+        # register physical ports
         self.uni_port = Port(
             port_no=2,
             label='UNI facing Ethernet port',
@@ -147,12 +139,6 @@
             )
         )
 
-    # def _get_uni_port(self):
-    #     ports = self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_UNI)
-    #     if ports:
-    #         # For now, we use on one uni port
-    #         return ports[0]
-
     @inlineCallbacks
     def _get_uni_port(self):
         ports = yield self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_UNI)
@@ -163,12 +149,6 @@
         ports = yield self.adapter_agent.get_ports(self.device_id, Port.PON_ONU)
         returnValue(ports)
 
-    # def _get_pon_port(self):
-    #     ports = self.adapter_agent.get_ports(self.device_id, Port.PON_ONU)
-    #     if ports:
-    #         # For now, we use on one uni port
-    #         return ports[0]
-
     def reconcile(self, device):
         self.log.info('reconciling-ONU-device-starts')
 
@@ -228,27 +208,17 @@
     def reboot(self):
         self.log.info('rebooting', device_id=self.device_id)
 
-        # Update the operational status to ACTIVATING and connect status to
-        # UNREACHABLE
-        device = self.adapter_agent.get_device(self.device_id)
-        previous_oper_status = device.oper_status
-        previous_conn_status = device.connect_status
-        device.oper_status = OperStatus.ACTIVATING
-        device.connect_status = ConnectStatus.UNREACHABLE
-        self.adapter_agent.update_device(device)
+        # Update the connect status to UNREACHABLE
+        yield self.adapter_agent.device_state_update(self.device_id, connect_status=ConnectStatus.UNREACHABLE)
 
         # Sleep 10 secs, simulating a reboot
         # TODO: send alert and clear alert after the reboot
         yield asleep(10)
 
-        # Change the operational status back to its previous state.  With a
-        # real OLT the operational state should be the state the device is
-        # after a reboot.
-        # Get the latest device reference
-        device = self.adapter_agent.get_device(self.device_id)
-        device.oper_status = previous_oper_status
-        device.connect_status = previous_conn_status
-        self.adapter_agent.update_device(device)
+        # Change the connection status back to REACHABLE.  With a
+        # real ONU the connection state must be the actual state
+        yield self.adapter_agent.device_state_update(self.device_id, connect_status=ConnectStatus.REACHABLE)
+
         self.log.info('rebooted', device_id=self.device_id)
 
     def self_test_device(self, device):
@@ -278,18 +248,6 @@
     def reenable(self):
         self.log.info('re-enabling', device_id=self.device_id)
         try:
-            # Get the latest device reference
-            # device = self.adapter_agent.get_device(self.device_id)
-
-            # First we verify that we got parent reference and proxy info
-            # assert device.parent_id
-            # assert device.proxy_address.device_id
-            # assert device.proxy_address.channel_id
-
-            # Re-register for proxied messages right away
-            # self.proxy_address = device.proxy_address
-            # self.adapter_agent.register_for_proxied_messages(
-            #     device.proxy_address)
 
             # Refresh the port reference - we only use one port for now
             ports = yield self._get_uni_port()
@@ -314,47 +272,6 @@
                                                    port_no=self.pon_port.port_no,
                                                    oper_status=OperStatus.ACTIVE)
 
-
-            # # Re-enable the ports on that device
-            # self.adapter_agent.enable_all_ports(self.device_id)
-
-
-            # Add the pon port reference to the parent
-            # self.adapter_agent.add_port_reference_to_parent(device.id,
-            #                                                 self.pon_port)
-
-            # Update the connect status to REACHABLE
-            # device.connect_status = ConnectStatus.REACHABLE
-            # self.adapter_agent.update_device(device)
-
-            # re-add uni port to logical device
-            # parent_device = self.adapter_agent.get_device(device.parent_id)
-            # logical_device_id = parent_device.parent_id
-            # assert logical_device_id
-            # port_no = device.proxy_address.channel_id
-            # cap = OFPPF_1GB_FD | OFPPF_FIBER
-            # self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
-            #     id='uni-{}'.format(port_no),
-            #     ofp_port=ofp_port(
-            #         port_no=port_no,
-            #         hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
-            #         name='uni-{}'.format(port_no),
-            #         config=0,
-            #         state=OFPPS_LIVE,
-            #         curr=cap,
-            #         advertised=cap,
-            #         peer=cap,
-            #         curr_speed=OFPPF_1GB_FD,
-            #         max_speed=OFPPF_1GB_FD
-            #     ),
-            #     device_id=device.id,
-            #     device_port_no=self.uni_port.port_no
-            # ))
-
-            # device = self.adapter_agent.get_device(device.id)
-            # device.oper_status = OperStatus.ACTIVE
-            # self.adapter_agent.update_device(device)
-
             yield self.adapter_agent.device_state_update(self.device_id, oper_status=OperStatus.ACTIVE, connect_status=ConnectStatus.REACHABLE)
 
             self.log.info('re-enabled', device_id=self.device_id)
@@ -364,8 +281,6 @@
     def delete(self):
         self.log.info('deleting', device_id=self.device_id)
 
-        # A delete request may be received when an OLT is dsiabled
-
         # TODO:
         # 1) Remove all flows from the device
         # 2) Remove the device from ponsim