ADTRAN: Update to containerized adapters.
Loading and running but still needs about a week or so of work to
catch up to where the OpenOLT/ONU containerized adapters are

Change-Id: I5522232e21dd76b3f95b4698af6c7e4cef96753d
diff --git a/adapters/adtran_olt/adtran_olt.yml b/adapters/adtran_olt/adapters-adtran-olt.yml
similarity index 100%
rename from adapters/adtran_olt/adtran_olt.yml
rename to adapters/adtran_olt/adapters-adtran-olt.yml
diff --git a/adapters/adtran_olt/adtran_olt.py b/adapters/adtran_olt/adtran_olt.py
index c052b78..e25b42a 100644
--- a/adapters/adtran_olt/adtran_olt.py
+++ b/adapters/adtran_olt/adtran_olt.py
@@ -22,7 +22,7 @@
 from pyvoltha.adapters.iadapter import OltAdapter
 from pyvoltha.protos import third_party
 from pyvoltha.protos.common_pb2 import AdminState
-
+from pyvoltha.protos.health_pb2 import HealthStatus
 from adtran_olt_handler import AdtranOltHandler
 
 
@@ -43,7 +43,7 @@
                                                version='2.0.0',
                                                device_type=AdtranOltAdapter.name,
                                                accepts_bulk_flow_update=True,
-                                               accepts_add_remove_flow_updates=False)  # TODO: Implement me
+                                               accepts_add_remove_flow_updates=True)
 
         log.debug('adtran_olt.__init__')
 
@@ -55,7 +55,6 @@
         """
         # TODO: Currently this is always healthy for every adapter.
         #       If we decide not to modify this, delete this method and use base class method
-        from pyvoltha.protos.health_pb2 import HealthStatus
         return HealthStatus(state=HealthStatus.HEALTHY)
 
     def abandon_device(self, device):
@@ -75,8 +74,9 @@
         is provisioned top-down and needs to be activated by the adapter.
 
         :param device: A voltha.Device object, with possible device-type
-                specific extensions. Such extensions shall be described as part of
-                the device type specification returned by device_types().
+                       specific extensions. Such extensions shall be described as part of
+                       the device type specification returned by device_types().
+
         :return: (Deferred) Shall be fired to acknowledge device ownership.
         """
         log.info('adopt-device', device=device)
@@ -84,23 +84,36 @@
             'adapter': self,
             'device-id': device.id
         }
-        self.devices_handlers[device.id] = self.device_handler_class(**kwargs)
-        d = defer.Deferred()
-        reactor.callLater(0, self.devices_handlers[device.id].activate, d, False)
-        return d
+        try:
+            self.devices_handlers[device.id] = self.device_handler_class(**kwargs)
+            d = defer.Deferred()
+            reactor.callLater(0, self.devices_handlers[device.id].activate, d, False)
+            return d
+
+        except Exception as _e:
+            raise
 
     def reconcile_device(self, device):
+        """
+        Make sure the adapter looks after given device. Called when this
+        device has changed ownership from another Voltha instance to
+        this one (typically, this occurs when the previous voltha
+        instance went down).
+
+        :param device: A voltha.Device object, with possible device-type
+                       specific extensions. Such extensions shall be described as part of
+                       the device type specification returned by device_types().
+
+        :return: (Deferred) Shall be fired to acknowledge device ownership.
+        """
         try:
-            self.devices_handlers[device.id] = self.device_handler_class(self,
-                                                                         device.id)
+            kwargs = {
+                'adapter': self,
+                'device-id': device.id
+            }
+            self.devices_handlers[device.id] = self.device_handler_class(**kwargs)
             # Work only required for devices that are in ENABLED state
             if device.admin_state == AdminState.ENABLED:
-
-                kwargs = {
-                    'adapter': self,
-                    'device-id': device.id
-                }
-                self.devices_handlers[device.id] =self.device_handler_class(**kwargs)
                 d = defer.Deferred()
                 reactor.callLater(0, self.devices_handlers[device.id].activate, d, True)
 
diff --git a/adapters/adtran_olt/adtran_olt_handler.py b/adapters/adtran_olt/adtran_olt_handler.py
index ad32b84..92c3398 100644
--- a/adapters/adtran_olt/adtran_olt_handler.py
+++ b/adapters/adtran_olt/adtran_olt_handler.py
@@ -160,9 +160,6 @@
             'startup-revision': 'unknown',
             'software-images': []
         }
-        if self.is_virtual_olt:
-            returnValue(device)
-
         try:
             pe_state = PhysicalEntitiesState(self.netconf_client)
             self.startup = pe_state.get_state()
@@ -322,12 +319,8 @@
             from nni_port import MockNniPort
 
             ietf_interfaces = IetfInterfacesState(self.netconf_client)
-
-            if self.is_virtual_olt:
-                results = MockNniPort.get_nni_port_state_results()
-            else:
-                self.startup = ietf_interfaces.get_state()
-                results = yield self.startup
+            self.startup = ietf_interfaces.get_state()
+            results = yield self.startup
 
             ports = ietf_interfaces.get_port_entries(results, 'ethernet')
             returnValue(ports)
@@ -355,10 +348,9 @@
             # May already exist if device was not fully reachable when first enabled
             if port_no not in self.northbound_ports:
                 self.log.info('processing-nni', port_no=port_no, name=port['port_no'])
-                self.northbound_ports[port_no] = NniPort(self, **port) if not self.is_virtual_olt \
-                    else MockNniPort(self, **port)
+                self.northbound_ports[port_no] = NniPort(self, **port)
 
-            if len(self.northbound_ports) >= self.max_nni_ports: # TODO: For now, limit number of NNI ports to make debugging easier
+            if len(self.northbound_ports) >= self.max_nni_ports:  # TODO: For now, limit number of NNI ports to make debugging easier
                 break
 
         self.num_northbound_ports = len(self.northbound_ports)
@@ -407,12 +399,8 @@
             results = yield self.startup
 
             ietf_interfaces = IetfInterfacesState(self.netconf_client)
-
-            if self.is_virtual_olt:
-                nc_results = MockNniPort.get_pon_port_state_results()
-            else:
-                self.startup = ietf_interfaces.get_state()
-                nc_results = yield self.startup
+            self.startup = ietf_interfaces.get_state()
+            nc_results = yield self.startup
 
             ports = ietf_interfaces.get_port_entries(nc_results, 'xpon')
             if len(ports) == 0:
@@ -692,7 +680,7 @@
         # Upstream direction?
         if self.is_pon_port(port_no):
             #TODO: Validate the evc-map name
-            from python.adapters.adtran.adtran_common.flow.evc_map import EVCMap
+            from pyvoltha.adapters.adtran_common.flow.evc_map import EVCMap
             map_info = EVCMap.decode_evc_map_name(evc_map)
             logical_port_no = int(map_info.get('ingress-port'))
 
@@ -1162,6 +1150,7 @@
 
         self.adapter_agent.update_image_download(request)
 
+    @inlineCallbacks
     def start_download(self, device, request, done):
         """
         This is called to request downloading a specified image into
@@ -1193,7 +1182,7 @@
                 self._downloads[download.name] = download
                 self._update_download_status(request, download)
                 done.callback('started')
-                return done
+                returnValue(done)
 
             except Exception:
                 request.additional_info = 'Download request startup failed due to exception'
@@ -1214,9 +1203,10 @@
 
             # restore admin state to enabled
             device.admin_state = AdminState.ENABLED
-            self.adapter_agent.update_device(device)
+            yield self.adapter_agent.device_update(device)
             raise
 
+    @inlineCallbacks
     def download_status(self, device, request, done):
         """
         This is called to inquire about a requested image download status based
@@ -1241,11 +1231,12 @@
                                  ImageDownload.DOWNLOAD_FAILED]:
             # restore admin state to enabled
             device.admin_state = AdminState.ENABLED
-            self.adapter_agent.update_device(device)
+            yield self.adapter_agent.device_update(device)
 
         done.callback(request.state)
-        return done
+        returnValue(done)
 
+    @inlineCallbacks
     def cancel_download(self, device, request, done):
         """
         This is called to cancel a requested image download based on a NBI
@@ -1273,10 +1264,11 @@
 
         if device.admin_state == AdminState.DOWNLOADING_IMAGE:
             device.admin_state = AdminState.ENABLED
-            self.adapter_agent.update_device(device)
+            yield self.adapter_agent.device_update(device)
 
-        return done
+        returnValue(done)
 
+    @inlineCallbacks
     def activate_image(self, device, request, done):
         """
         This is called to activate a downloaded image from a standby partition
@@ -1306,9 +1298,10 @@
 
         # restore admin state to enabled
         device.admin_state = AdminState.ENABLED
-        self.adapter_agent.update_device(device)
-        return done
+        yield self.adapter_agent.device_update(device)
+        returnValue(done)
 
+    @inlineCallbacks
     def revert_image(self, device, request, done):
         """
         This is called to deactivate the specified image at active partition,
@@ -1338,8 +1331,8 @@
 
         # restore admin state to enabled
         device.admin_state = AdminState.ENABLED
-        self.adapter_agent.update_device(device)
-        return done
+        yield self.adapter_agent.device_update(device)
+        returnValue(done)
 
     def add_onu_device(self, pon_id, onu_id, serial_number):
         onu_device = self.adapter_agent.get_child_device(self.device_id,
diff --git a/adapters/adtran_olt/main.py b/adapters/adtran_olt/main.py
index 07bcc07..bea91bf 100755
--- a/adapters/adtran_olt/main.py
+++ b/adapters/adtran_olt/main.py
@@ -49,9 +49,9 @@
 _ = third_party
 
 
-defs = dict(
-    version_file='./VERSION',
-    config=os.environ.get('CONFIG', './adapters-adtran_olt.yml'),
+defs=dict(
+    version_file='/voltha/VERSION',
+    config=os.environ.get('CONFIG', './adapters-adtran-olt.yml'),
     container_name_regex=os.environ.get('CONTAINER_NUMBER_EXTRACTOR', '^.*\.(['
                                                                       '0-9]+)\..*$'),
     consul=os.environ.get('CONSUL', 'localhost:8500'),
@@ -64,8 +64,8 @@
     core_topic=os.environ.get('CORE_TOPIC', 'rwcore'),
     interface=os.environ.get('INTERFACE', get_my_primary_interface()),
     instance_id=os.environ.get('INSTANCE_ID', os.environ.get('HOSTNAME', '1')),
-    kafka_adapter=os.environ.get('KAFKA_ADAPTER', '172.20.10.3:9092'),
-    kafka_cluster=os.environ.get('KAFKA_CLUSTER', '172.20.10.3:9092'),
+    kafka_adapter=os.environ.get('KAFKA_ADAPTER', '192.168.0.20:9092'),
+    kafka_cluster=os.environ.get('KAFKA_CLUSTER', '10.100.198.220:9092'),
     backend=os.environ.get('BACKEND', 'none'),
     retry_interval=os.environ.get('RETRY_INTERVAL', 2),
     heartbeat_topic=os.environ.get('HEARTBEAT_TOPIC', "adapters.heartbeat"),
@@ -74,7 +74,7 @@
     debug_enabled=True,
     debug_host='work.bcsw.net',
     # debug_host='10.0.2.15',
-    debug_port=8765,
+    debug_port=5678,
 )
 
 
@@ -286,7 +286,7 @@
     except:
         import sys
         logger.error("pydevd startup exception: %s" % sys.exc_info()[0])
-        print('REMOTE DEBUGGING will not be supported in this run...')
+        logger.error('REMOTE DEBUGGING will not be supported in this run...')
 
 
 def load_config(args):
@@ -295,6 +295,7 @@
         dir = os.path.dirname(os.path.abspath(__file__))
         path = os.path.join(dir, path)
     path = os.path.abspath(path)
+
     with open(path) as fd:
         config = yaml.load(fd)
     return config
@@ -308,6 +309,7 @@
     log.info("  / ____ \| |__| | | |  | | \ \  / ____ \| |\  |   | |__| | |____| |   ")
     log.info(" /_/    \_\_____/  |_|  |_| _\_\/_/    \_\_| \_|    \____/|______|_|   ")
     log.info("     /\      | |           | |                                         ")
+    log.info('   _       _             _                            ')
     log.info("    /  \   __| | __ _ _ __ | |_ ___ _ __                               ")
     log.info("   / /\ \ / _` |/ _` | '_ \| __/ _ \ '__|                              ")
     log.info("  / ____ \ (_| | (_| | |_) | ||  __/ |                                 ")
@@ -322,42 +324,45 @@
 class Main(object):
 
     def __init__(self):
+        try:
+            self.args = args = parse_args()
+            self.config = load_config(args)
 
-        self.args = args = parse_args()
-        self.config = load_config(args)
+            verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
+            self.log = setup_logging(self.config.get('logging', {}),
+                                     args.instance_id,
+                                     verbosity_adjust=verbosity_adjust)
+            self.log.info('container-number-extractor',
+                          regex=args.container_name_regex)
 
-        verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
-        self.log = setup_logging(self.config.get('logging', {}),
-                                 args.instance_id,
-                                 verbosity_adjust=verbosity_adjust)
-        self.log.info('container-number-extractor',
-                      regex=args.container_name_regex)
+            if args.debug_enabled:
+                setup_remote_debug(args.debug_host, args.debug_port, self.log)
 
-        if args.debug_enabled:
-            setup_remote_debug(args.debug_host, args.debug_port, self.log)
+            self.adtran_olt_adapter_version = self.get_version()
+            self.log.info('ADTRAN-OLT-Adapter-Version',
+                          version=self.adtran_olt_adapter_version)
 
-        self.adtran_olt_adapter_version = self.get_version()
-        self.log.info('ADTRAN-OLT-Adapter-Version', version=self.adtran_olt_adapter_version)
+            if not args.no_banner:
+                print_banner(self.log)
 
-        if not args.no_banner:
-            print_banner(self.log)
+            self.adapter = None
 
-        self.adapter = None
-        self.core_proxy = None
-        self.adapter_proxy = None
+            # Create a unique instance id using the passed-in instance id and
+            # UTC timestamp
+            current_time = arrow.utcnow().timestamp
+            self.instance_id = self.args.instance_id + '_' + str(current_time)
 
-        # Create a unique instance id using the passed-in instance id and
-        # UTC timestamp
-        current_time = arrow.utcnow().timestamp
-        self.instance_id = self.args.instance_id + '_' + str(current_time)
+            self.core_topic = args.core_topic
+            self.listening_topic = args.name
+            self.startup_components()
 
-        self.core_topic = args.core_topic
-        self.listening_topic = args.name
-        self.startup_components()
+            if not args.no_heartbeat:
+                self.start_heartbeat()
+                self.start_kafka_cluster_heartbeat(self.instance_id)
 
-        if not args.no_heartbeat:
-            self.start_heartbeat()
-            self.start_kafka_cluster_heartbeat(self.instance_id)
+        except Exception as e:
+            self.log.exception('unhandled-exception', e=e)
+            raise
 
     def get_version(self):
         path = defs['version_file']
@@ -442,6 +447,7 @@
                     kv_store=self.args.backend,
                     default_topic=self.args.name,
                     group_id_prefix=self.args.instance_id,
+                    # Needs to assign a real class
                     target_cls=adtran_request_handler
                 )
             ).start()
@@ -543,8 +549,8 @@
                     kafka_cluster_proxy.send_message(topic, dumps(message))
                 else:
                     self.log.error('kafka-proxy-unavailable')
-            except Exception, err:
-                self.log.exception('failed-sending-message-heartbeat', e=err)
+            except Exception as e:
+                self.log.exception('failed-sending-message-heartbeat', e=e)
 
         try:
             t0 = time.time()
diff --git a/adapters/adtran_olt/resources/adtran_olt_resource_manager.py b/adapters/adtran_olt/resources/adtran_olt_resource_manager.py
index caf5a46..8cce46c 100644
--- a/adapters/adtran_olt/resources/adtran_olt_resource_manager.py
+++ b/adapters/adtran_olt/resources/adtran_olt_resource_manager.py
@@ -245,7 +245,7 @@
             # we need to derive the ONU Id for which the packet arrived based
             # on the pon_intf and gemport available in the packet_indication
             # self.kv_store[str(pon_intf_gemport)] = ' '.join(map(str, (onu_id, uni_id)))
-            self.kv_store.put(self._make_path(str(pon_intf_gemport)), ' '.join(map(str, (onu_id, uni_id)))
+            self.kv_store.put(self._make_path(str(pon_intf_gemport)), ' '.join(map(str, (onu_id, uni_id))))
 
     def get_onu_uni_from_ponport_gemport(self, pon_port, gemport):
         pon_intf_gemport = (pon_port, gemport)