Introduce the openolt_data_model module.

A voltha adapter maintains its data model in KV store.
In most cases the interaction with the KV store's
data model is not direct but via the adapter_agent.
There is a fair amount of boiler-plate code in the
adapter related to the interaction with adapter_agent.
Most of this is going to change from voltha 1.x to 2.0.
This, and subsequent related commits, aim to abstract
out the adapter_agent interface in the openolt_data_model.
The resulting de-cluttered logic of the adapter will
be more amenable to re-use in the porting to 2.0.

Change-Id: Ic0d7223db2a6713bae7a0c953d11b1977759fab6
diff --git a/voltha/adapters/openolt/openolt_device.py b/voltha/adapters/openolt/openolt_device.py
index 318d9e1..c7fc9d9 100644
--- a/voltha/adapters/openolt/openolt_device.py
+++ b/voltha/adapters/openolt/openolt_device.py
@@ -16,7 +16,6 @@
 import threading
 import binascii
 import grpc
-import socket
 import structlog
 import time
 from twisted.internet import reactor
@@ -25,17 +24,10 @@
 
 from voltha.protos.device_pb2 import Port, Device
 from voltha.protos.common_pb2 import OperStatus, AdminState, ConnectStatus
-from voltha.protos.logical_device_pb2 import LogicalDevice
-from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
-    OFPPS_LINK_DOWN, OFPPF_1GB_FD, OFPC_GROUP_STATS, OFPC_PORT_STATS, \
-    OFPC_TABLE_STATS, OFPC_FLOW_STATS, ofp_switch_features, ofp_port, \
-    ofp_port_stats, ofp_desc
-from voltha.protos.logical_device_pb2 import LogicalPort
-from voltha.core.logical_device_agent import mac_str_to_tuple
+from voltha.protos.openflow_13_pb2 import OFPPS_LINK_DOWN
 from voltha.registry import registry
 from voltha.adapters.openolt.protos import openolt_pb2_grpc, openolt_pb2
 from voltha.adapters.openolt.openolt_utils import OpenoltUtils
-
 from voltha.extensions.alarms.onu.onu_discovery_alarm import OnuDiscoveryAlarm
 
 
@@ -84,6 +76,7 @@
 
         self.admin_state = "up"
 
+        self.data_model = kwargs['data_model']
         self.adapter_agent = kwargs['adapter_agent']
         self.device_num = kwargs['device_num']
         device = kwargs['device']
@@ -135,55 +128,6 @@
 
         self.go_state_init()
 
-    def create_logical_device(self, device_info):
-        dpid = device_info.device_id
-        serial_number = device_info.device_serial_number
-
-        if dpid is None or dpid == '':
-            uri = self.host_and_port.split(":")[0]
-            try:
-                socket.inet_pton(socket.AF_INET, uri)
-                dpid = '00:00:' + OpenoltUtils.ip_hex(uri)
-            except socket.error:
-                # this is not an IP
-                dpid = OpenoltUtils.str_to_mac(uri)
-
-        self.log.info('creating-openolt-logical-device', dp_id=dpid,
-                      serial_number=serial_number)
-
-        hw_desc = device_info.model
-        if device_info.hardware_version:
-            hw_desc += '-' + device_info.hardware_version
-
-        # Create logical OF device
-        ld = LogicalDevice(
-            root_device_id=self.device_id,
-            switch_features=ofp_switch_features(
-                n_buffers=256,  # TODO fake for now
-                n_tables=2,  # TODO ditto
-                capabilities=(  # TODO and ditto
-                        OFPC_FLOW_STATS
-                        | OFPC_TABLE_STATS
-                        | OFPC_PORT_STATS
-                        | OFPC_GROUP_STATS
-                )
-            ),
-            desc=ofp_desc(
-                serial_num=serial_number
-            )
-        )
-        ld_init = self.adapter_agent.create_logical_device(ld,
-                                                           dpid=dpid)
-
-        device = self.adapter_agent.get_device(self.device_id)
-        device.serial_number = serial_number
-        self.adapter_agent.update_device(device)
-
-        self.log.info('created-openolt-logical-device',
-                      logical_device_id=ld_init.id)
-
-        return ld_init.id
-
     def do_state_init(self, event):
         # Initialize gRPC
         self.channel = grpc.insecure_channel(self.host_and_port)
@@ -222,8 +166,8 @@
 
         if self.logical_device_id is None:
             # first time connect to olt
-            self.logical_device_id = self.create_logical_device(
-                self.device_info)
+            self.logical_device_id = self.data_model.create_logical_device(
+                self.device_id, self.device_info)
         else:
             # reconnect to olt (e.g. olt reboot)
             # TODO - Update logical device with new device_info
@@ -270,49 +214,8 @@
 
     def do_state_down(self, event):
         self.log.debug("do_state_down")
-        oper_state = OperStatus.UNKNOWN
-        connect_state = ConnectStatus.UNREACHABLE
 
-        # Propagating to the children
-
-        # Children ports
-        child_devices = self.adapter_agent.get_child_devices(self.device_id)
-        for onu_device in child_devices:
-            onu_adapter_agent = \
-                registry('adapter_loader').get_agent(onu_device.adapter)
-            onu_adapter_agent.update_interface(onu_device,
-                                               {'oper_state': 'down'})
-            self.onu_ports_down(onu_device, oper_state)
-
-        # Children devices
-        self.adapter_agent.update_child_devices_state(
-            self.device_id, oper_status=oper_state,
-            connect_status=connect_state)
-        # Device Ports
-        device_ports = self.adapter_agent.get_ports(self.device_id,
-                                                    Port.ETHERNET_NNI)
-        logical_ports_ids = [port.label for port in device_ports]
-        device_ports += self.adapter_agent.get_ports(self.device_id,
-                                                     Port.PON_OLT)
-
-        for port in device_ports:
-            port.oper_status = oper_state
-            self.adapter_agent.add_port(self.device_id, port)
-
-        # Device logical port
-        for logical_port_id in logical_ports_ids:
-            logical_port = self.adapter_agent.get_logical_port(
-                self.logical_device_id, logical_port_id)
-            logical_port.ofp_port.state = OFPPS_LINK_DOWN
-            self.adapter_agent.update_logical_port(self.logical_device_id,
-                                                   logical_port)
-
-        # Device
-        device = self.adapter_agent.get_device(self.device_id)
-        device.oper_status = oper_state
-        device.connect_status = connect_state
-
-        reactor.callLater(2, self.adapter_agent.update_device, device)
+        self.data_model.disable_logical_device(self.device_id)
 
     def post_down(self, event):
         self.log.debug('post_down')
@@ -406,13 +309,6 @@
                     self.log.warn('unknown indication type')
 
     def olt_indication(self, olt_indication):
-        '''
-        if self.admin_state is "up":
-            if olt_indication.oper_state == "up":
-                self.go_state_up()
-            elif olt_indication.oper_state == "down":
-                self.go_state_down()
-        '''
         if olt_indication.oper_state == "up":
             self.go_state_up()
         elif olt_indication.oper_state == "down":
@@ -447,8 +343,10 @@
             port_no, label = self.add_port(intf_oper_indication.intf_id,
                                            Port.ETHERNET_NNI, oper_state)
             self.log.debug("int_oper_indication", port_no=port_no, label=label)
-            self.add_logical_port(port_no, intf_oper_indication.intf_id,
-                                  oper_state)
+            self.data_model.add_logical_port(self.logical_device_id,
+                                             self.device_id, port_no,
+                                             intf_oper_indication.intf_id,
+                                             oper_state)
 
         elif intf_oper_indication.type == "pon":
             # FIXME - handle PON oper state change
@@ -831,38 +729,6 @@
             admin_state=AdminState.ENABLED
         )
 
-    def add_logical_port(self, port_no, intf_id, oper_state):
-        self.log.info('adding-logical-port', port_no=port_no)
-
-        label = OpenoltUtils.port_name(port_no, Port.ETHERNET_NNI)
-
-        cap = OFPPF_1GB_FD | OFPPF_FIBER
-        curr_speed = OFPPF_1GB_FD
-        max_speed = OFPPF_1GB_FD
-
-        if oper_state == OperStatus.ACTIVE:
-            of_oper_state = OFPPS_LIVE
-        else:
-            of_oper_state = OFPPS_LINK_DOWN
-
-        ofp = ofp_port(
-            port_no=port_no,
-            hw_addr=mac_str_to_tuple(
-                OpenoltUtils.make_mac_from_port_no(port_no)),
-            name=label, config=0, state=of_oper_state, curr=cap,
-            advertised=cap, peer=cap, curr_speed=curr_speed,
-            max_speed=max_speed)
-
-        ofp_stats = ofp_port_stats(port_no=port_no)
-
-        logical_port = LogicalPort(
-            id=label, ofp_port=ofp, device_id=self.device_id,
-            device_port_no=port_no, root_port=True,
-            ofp_port_stats=ofp_stats)
-
-        self.adapter_agent.add_logical_port(self.logical_device_id,
-                                            logical_port)
-
     def add_port(self, intf_id, port_type, oper_status):
         port_no = self.platform.intf_id_to_port_no(intf_id, port_type)