VOL-1493 VOL-1454:

Process omci messages. Properly set device state
using new core_proxy api

Implement and process inter adapter messages.
Handle omci_indications. Also keep track of stacked
up onu discovery indications so we dont repeatedly
add onu.  Future data_model changes could
likely encompass this.

Can now successfully mib upload and mib_sync
is success with onu adapter

Change-Id: Ib0f0c2f29f6410736ef8db3bde143206d603a140
diff --git a/python/Makefile b/python/Makefile
index 27aec1d..4799a78 100644
--- a/python/Makefile
+++ b/python/Makefile
@@ -119,8 +119,10 @@
 venv: ${VENVDIR}/.built
 
 ${VENVDIR}/.built:
-	@ virtualenv ${VENVDIR}
-	@ . ${VENVDIR}/bin/activate && \
+	virtualenv -v ${VENVDIR}
+	# these are just symlinks to the other folders in the venv.  this makes it appear as if there are duplicate definitions in PYTHONPATH.  venv bug?
+	rm ${VENVDIR}/local/bin ${VENVDIR}/local/lib ${VENVDIR}/local/include
+	. ${VENVDIR}/bin/activate && \
 	    pip install --upgrade pip; \
 	    if ! pip install -r requirements.txt; \
 	    then \
@@ -135,7 +137,7 @@
 	cp ../../pyvoltha/dist/*.tar.gz pyvoltha/dist/
 	mkdir -p voltha-protos/dist
 	cp ../../voltha-protos/dist/*.tar.gz voltha-protos/dist/
-	@ . ${VENVDIR}/bin/activate && \
+	. ${VENVDIR}/bin/activate && \
 	    pip install pyvoltha/dist/*.tar.gz && \
 	    pip install voltha-protos/dist/*.tar.gz
 endif
diff --git a/python/adapters/openolt/main.py b/python/adapters/openolt/main.py
index e23d532..024be85 100755
--- a/python/adapters/openolt/main.py
+++ b/python/adapters/openolt/main.py
@@ -372,6 +372,8 @@
                                           adapter_proxy=self.adapter_proxy,
                                           config=config)
 
+            self.adapter.start()
+
             openolt_request_handler = AdapterRequestFacade(adapter=self.adapter,
                                                            core_proxy=self.core_proxy)
 
diff --git a/python/adapters/openolt/openolt.py b/python/adapters/openolt/openolt.py
index 49e0d16..abc95c1 100644
--- a/python/adapters/openolt/openolt.py
+++ b/python/adapters/openolt/openolt.py
@@ -352,6 +352,20 @@
         except Exception as e:
             log.error('packet-out:exception', e=e.message)
 
+    def process_inter_adapter_message(self, msg):
+        log.debug('process-inter-adapter-message', msg=msg)
+        # Unpack the header to know which device needs to handle this message
+        handler = None
+        if msg.header.proxy_device_id:
+            # typical request
+            handler = self.devices[msg.header.proxy_device_id]
+        elif msg.header.to_device_id and \
+                msg.header.to_device_id in self.devices_handlers:
+            # typical response
+            handler = self.devices[msg.header.to_device_id]
+        if handler:
+            reactor.callLater(0, handler.process_inter_adapter_message, msg)
+
     def receive_inter_adapter_message(self, msg):
         log.info('rx_inter_adapter_msg - Not implemented')
         raise NotImplementedError()
diff --git a/python/adapters/openolt/openolt_device.py b/python/adapters/openolt/openolt_device.py
index 7fae0de..55f2a54 100644
--- a/python/adapters/openolt/openolt_device.py
+++ b/python/adapters/openolt/openolt_device.py
@@ -35,11 +35,9 @@
     OFPC_GROUP_STATS, OFPC_PORT_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS, \
     ofp_switch_features, ofp_port, ofp_port_stats, ofp_desc
 from pyvoltha.common.utils.registry import registry
-#from voltha_protos import third_party
 from voltha_protos.common_pb2 import AdminState, OperStatus, ConnectStatus
-from voltha_protos.common_pb2 import LogLevel
 from voltha_protos.device_pb2 import Port, Device
-
+from voltha_protos.inter_container_pb2 import InterAdapterMessageType, InterAdapterOmciMessage
 from voltha_protos.logical_device_pb2 import LogicalDevice, LogicalPort
 
 
@@ -98,6 +96,7 @@
         self.stats_mgr_class = kwargs['support_classes']['stats_mgr']
         self.bw_mgr_class = kwargs['support_classes']['bw_mgr']
 
+        self.seen_discovery_indications = []
         self.stub = None
         self.connected = False
         is_reconciliation = kwargs.get('reconciliation', False)
@@ -465,10 +464,6 @@
             self.add_port(intf_oper_indication.intf_id,
                                     Port.ETHERNET_NNI, oper_state)
 
-            # TODO NEW CORE:  Is this needed anymore, or does the new core synthesize this
-            #self.add_logical_port(port_no, intf_oper_indication.intf_id,
-            #                      oper_state)
-
         elif intf_oper_indication.type == "pon":
             # FIXME - handle PON oper state change
             pass
@@ -483,6 +478,13 @@
         self.log.debug("onu discovery indication", intf_id=intf_id,
                        serial_number=serial_number_str)
 
+        if serial_number_str in self.seen_discovery_indications:
+            self.log.debug("skipping-seen-onu-discovery-indication", intf_id=intf_id,
+                           serial_number=serial_number_str)
+            return
+        else:
+            self.seen_discovery_indications.append(serial_number_str)
+
         # Post ONU Discover alarm  20180809_0805
         try:
             OnuDiscoveryAlarm(self.alarm_mgr.alarms, pon_id=intf_id,
@@ -513,8 +515,7 @@
 
         else:
             if onu_device.connect_status != ConnectStatus.REACHABLE:
-                onu_device.connect_status = ConnectStatus.REACHABLE
-                yield self.adapter_agent.device_update(onu_device)
+                yield self.adapter_agent.device_state_update(onu_device.id, connect_status=ConnectStatus.REACHABLE)
 
             onu_id = onu_device.proxy_address.onu_id
             if onu_device.oper_status == OperStatus.DISCOVERED \
@@ -533,8 +534,8 @@
                               reboot probably, activate onu", intf_id=intf_id,
                               onu_id=onu_id, serial_number=serial_number_str)
 
-                onu_device.oper_status = OperStatus.DISCOVERED
-                yield self.adapter_agent.device_update(onu_device)
+                yield self.adapter_agent.device_state_update(onu_device.id, oper_status=OperStatus.DISCOVERED)
+
                 try:
                     self.activate_onu(intf_id, onu_id, serial_number,
                                       serial_number_str)
@@ -608,37 +609,33 @@
 
         self.log.debug('admin-state-dealt-with')
 
-        onu_adapter_agent = \
-            registry('adapter_loader').get_agent(onu_device.adapter)
-        if onu_adapter_agent is None:
-            self.log.error('onu_adapter_agent-could-not-be-retrieved',
-                           onu_device=onu_device)
-            return
-
         # Operating state
         if onu_indication.oper_state == 'down':
 
             if onu_device.connect_status != ConnectStatus.UNREACHABLE:
-                onu_device.connect_status = ConnectStatus.UNREACHABLE
-                yield self.adapter_agent.device_update(onu_device)
+                yield self.adapter_agent.device_state_update(onu_device.id, connect_status=ConnectStatus.UNREACHABLE)
 
             # Move to discovered state
             self.log.debug('onu-oper-state-is-down')
 
             if onu_device.oper_status != OperStatus.DISCOVERED:
-                onu_device.oper_status = OperStatus.DISCOVERED
-                yield self.adapter_agent.device_update(onu_device)
-            # Set port oper state to Discovered
-            self.onu_ports_down(onu_device, OperStatus.DISCOVERED)
+                yield self.adapter_agent.device_state_update(onu_device.id, oper_status=OperStatus.DISCOVERED)
 
-            onu_adapter_agent.update_interface(onu_device,
-                                               {'oper_state': 'down'})
+            self.log.debug('inter-adapter-send-onu-ind', onu_indication=onu_indication)
+
+            # TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
+            yield self.adapter_proxy.send_inter_adapter_message(
+                msg=onu_indication,
+                type=InterAdapterMessageType.ONU_IND_REQUEST,
+                from_adapter="openolt",
+                to_adapter=onu_device.type,
+                to_device_id=onu_device.id
+            )
 
         elif onu_indication.oper_state == 'up':
 
             if onu_device.connect_status != ConnectStatus.REACHABLE:
-                onu_device.connect_status = ConnectStatus.REACHABLE
-                yield self.adapter_agent.device_update(onu_device)
+                yield self.adapter_agent.device_state_update(onu_device.id, connect_status=ConnectStatus.REACHABLE)
 
             if onu_device.oper_status != OperStatus.DISCOVERED:
                 self.log.debug("ignore onu indication",
@@ -648,11 +645,16 @@
                                msg_oper_state=onu_indication.oper_state)
                 return
 
-            # Device was in Discovered state, setting it to active
+            self.log.debug('inter-adapter-send-onu-ind', onu_indication=onu_indication)
 
-            # Prepare onu configuration
-
-            onu_adapter_agent.create_interface(onu_device, onu_indication)
+            # TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
+            yield self.adapter_proxy.send_inter_adapter_message(
+                msg=onu_indication,
+                type=InterAdapterMessageType.ONU_IND_REQUEST,
+                from_adapter="openolt",
+                to_adapter=onu_device.type,
+                to_device_id=onu_device.id
+            )
 
         else:
             self.log.warn('Not-implemented-or-invalid-value-of-oper-state',
@@ -701,8 +703,18 @@
             parent_port_no=self.platform.intf_id_to_port_no(
                 omci_indication.intf_id, Port.PON_OLT), )
 
-        yield self.adapter_agent.receive_proxied_message(onu_device.proxy_address,
-                                                   omci_indication.pkt)
+        omci_msg = InterAdapterOmciMessage(message=omci_indication.pkt)
+
+        self.log.debug('inter-adapter-send-omci', omci_msg=omci_msg)
+
+        # TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
+        yield self.adapter_proxy.send_inter_adapter_message(
+            msg=omci_msg,
+            type=InterAdapterMessageType.OMCI_REQUEST,
+            from_adapter="openolt",
+            to_adapter=onu_device.type,
+            to_device_id=onu_device.id
+        )
 
     @inlineCallbacks
     def packet_indication(self, pkt_indication):
@@ -812,22 +824,40 @@
                           port_type=egress_port_type)
 
     @inlineCallbacks
-    def send_proxied_message(self, proxy_address, msg):
-        onu_device = yield self.adapter_agent.get_child_device(
-            self.device_id, onu_id=proxy_address.onu_id,
-            parent_port_no=self.platform.intf_id_to_port_no(
-                proxy_address.channel_id, Port.PON_OLT)
-        )
+    def process_inter_adapter_message(self, request):
+        self.log.debug('process-inter-adapter-message', msg=request)
+        try:
+            if request.header.type == InterAdapterMessageType.OMCI_REQUEST:
+                omci_msg = InterAdapterOmciMessage()
+                request.body.Unpack(omci_msg)
+                self.log.debug('inter-adapter-recv-omci', omci_msg=omci_msg)
+
+                onu_device_id = request.header.to_device_id
+                onu_device = yield self.adapter_agent.get_device(onu_device_id)
+                self.send_proxied_message(onu_device, omci_msg.message)
+
+            else:
+                self.log.error("inter-adapter-unhandled-type", request=request)
+
+        except Exception as e:
+            self.log.exception("error-processing-inter-adapter-message", e=e)
+
+    def send_proxied_message(self, onu_device, msg):
+
         if onu_device.connect_status != ConnectStatus.REACHABLE:
             self.log.debug('ONU is not reachable, cannot send OMCI',
                            serial_number=onu_device.serial_number,
                            intf_id=onu_device.proxy_address.channel_id,
                            onu_id=onu_device.proxy_address.onu_id)
             return
-        omci = openolt_pb2.OmciMsg(intf_id=proxy_address.channel_id,
-                                   onu_id=proxy_address.onu_id, pkt=str(msg))
+
+        omci = openolt_pb2.OmciMsg(intf_id=onu_device.proxy_address.channel_id,
+                                   onu_id=onu_device.proxy_address.onu_id, pkt=str(msg))
         self.stub.OmciMsgOut(omci)
 
+        self.log.debug("omci-message-sent", intf_id=onu_device.proxy_address.channel_id,
+                                   onu_id=onu_device.proxy_address.onu_id, pkt=str(msg))
+
     @inlineCallbacks
     def add_onu_device(self, intf_id, port_no, onu_id, serial_number):
         self.log.info("adding-onu", port_no=port_no, onu_id=onu_id,
@@ -835,6 +865,7 @@
 
         serial_number_str = self.stringify_serial_number(serial_number)
 
+        # TODO NEW CORE dont hardcode child device type.  find some way of determining by vendor in serial number
         yield self.adapter_agent.child_device_detected(
             parent_device_id=self.device_id,
             parent_port_no=port_no,