From a649e62db2321a96c9da4ddbb1b8e4505d5e05b5 Mon Sep 17 00:00:00 2001
From: Robert Latta <robert.latta@geant.org>
Date: Thu, 12 Nov 2020 11:15:29 +0000
Subject: [PATCH] refactored location and related_services retrieval

---
 inventory_provider/routes/ims_classifier.py | 169 ++++++++++++--------
 1 file changed, 103 insertions(+), 66 deletions(-)

diff --git a/inventory_provider/routes/ims_classifier.py b/inventory_provider/routes/ims_classifier.py
index 96b63a0f..fc0eea3a 100644
--- a/inventory_provider/routes/ims_classifier.py
+++ b/inventory_provider/routes/ims_classifier.py
@@ -21,6 +21,15 @@ def _LOCATION(equipment, name, abbreviation):
     }
 
 
+def build_locations(loc_a, loc_b=None):
+    locations = None
+    if loc_a:
+        locations = {'a': loc_a}
+        if loc_b:
+            locations['b'] = loc_b
+    return locations
+
+
 def _remove_duplicates_from_list(all):
     """
     removes duplicates from the input list
@@ -32,8 +41,7 @@ def _remove_duplicates_from_list(all):
     return list(tmp_dict.values())
 
 
-def _locations_from_router(router_name):
-    r = common.get_current_redis()
+def _locations_from_router(router_name, r):
     result = r.get(f'ims:location:{router_name}')
     if not result:
         logger.error(f'error looking up location for {router_name}')
@@ -54,8 +62,30 @@ def _locations_from_router(router_name):
 
 # once the switchover is done then will refactor to get rid of
 # _locations_from_router
-def _location_from_equipment(equipment_name):
-    return _locations_from_router(equipment_name)
+def _location_from_equipment(equipment_name, r):
+    # return _locations_from_router(equipment_name, r)
+    result = r.get(f'ims:location:{equipment_name}')
+    if not result:
+        logger.error(f'error looking up location for {equipment_name}')
+        return None
+
+    result = json.loads(result.decode('utf-8'))
+    if not result:
+        logger.error(f'sanity failure: empty list for location {equipment_name}')
+        return None
+
+    return _LOCATION(
+        equipment=result[0]['equipment-name'],
+        name=result[0]['pop']['name'],
+        abbreviation=result[0]['pop']['abbreviation'])
+
+
+def _location_from_services(services, r):
+    for s in services:
+        loc_a = _location_from_equipment(s['equipment'], r)
+        loc_b = _location_from_equipment(s['other_end_equipment'], r) \
+            if s['other_end_equipment'] else None
+        yield build_locations(loc_a, loc_b)
 
 
 # def _location_from_service_dict(s):
@@ -108,6 +138,17 @@ def after_request(resp):
     return common.after_request(resp)
 
 
+def get_ims_equipment_name(equipment_name: str) -> str:
+    ims_equipment_name = equipment_name.upper()
+    if ims_equipment_name.startswith('MX'):
+        ims_equipment_name = ims_equipment_name.split('.GEANT.NET')[0]
+    return ims_equipment_name
+
+
+def get_ims_interface(interface: str) -> str:
+    return interface.upper()
+
+
 def related_interfaces(hostname, interface):
     r = common.get_current_redis()
     prefix = f'netconf-interfaces:{hostname}:'
@@ -143,15 +184,22 @@ def get_top_level_services(circuit_id, r):
     return list(tls.values())
 
 
-def get_ims_equipment_name(equipment_name: str) -> str:
-    ims_equipment_name = equipment_name.upper()
-    if ims_equipment_name.startswith('MX'):
-        ims_equipment_name = ims_equipment_name.split('.GEANT.NET')[0]
-    return ims_equipment_name
-
-
-def get_ims_interface(interface: str) -> str:
-    return interface.upper()
+def get_related_services(source_equipment, interface, r):
+    ims_source_equipment = get_ims_equipment_name(source_equipment)
+    ims_interface = get_ims_interface(interface)
+    if_services = r.get(f'ims:interface_services:{ims_source_equipment}:'
+               f'{ims_interface}')
+    if if_services:
+        for s in json.loads(if_services.decode('utf-8')):
+            yield from get_top_level_services(s['id'], r)
+    for related in related_interfaces(source_equipment, interface):
+        ims_interface = get_ims_interface(related)
+        logger.debug(f'Related Interface: {ims_interface}')
+        rif_services = r.get(
+            f'ims:interface_services:{ims_source_equipment}:{ims_interface}')
+        if rif_services:
+            for s in json.loads(rif_services.decode('utf-8')):
+                yield from get_top_level_services(s['id'], r)
 
 
 @routes.route("/juniper-link-info/<source_equipment>/<path:interface>",
@@ -177,19 +225,6 @@ def get_juniper_link_info(source_equipment: str, interface: str):
             'locations': []
         }
 
-        top_level_services = []
-
-        services = r.get(
-            f'ims:interface_services:{ims_source_equipment}:{ims_interface}')
-        if services:
-            result['services'] = json.loads(services.decode('utf=8'))
-            for s in result['services']:
-                top_level_services.extend(get_top_level_services(s['id'], r))
-
-                result['locations'] += _location_from_equipment(s['equipment'])
-                result['locations'] += \
-                    _location_from_equipment(s['other_end_equipment'])
-
         ifc_info = r.get(f'netconf-interfaces:{source_equipment}:{interface}')
         if ifc_info:
             result['interface'] = json.loads(ifc_info.decode('utf-8'))
@@ -211,30 +246,22 @@ def get_juniper_link_info(source_equipment: str, interface: str):
         else:
             result['interface']['bundle_members'] = []
 
-        def _related_services():
-            for related in related_interfaces(source_equipment, interface):
-                logger.debug(f'Related Interface: {related}')
-                rs = r.get(f'ims:interface_services:{ims_source_equipment}:'
-                           f'{related.upper()}')
-                if rs:
-                    for s in json.loads(rs.decode('utf-8')):
-                        top_level_services.extend(
-                            get_top_level_services(s['id'], r))
-                        yield {
-                            'name': s['name'],
-                            'status': s['status'],
-                            'circuit_type': s['circuit_type'],
-                            'project': s['project']
-                        }
-
-        related_services = list(_related_services())
-        if related_services:
-            top_level_services.extend(related_services)
-        if top_level_services:
-            result['related-services'] = top_level_services
-
-        if not result['locations']:
-            result['locations'] = _locations_from_router(ims_source_equipment)
+        # use a dict to get rid of  duplicates
+        rs_dict = {r['id']: r for r in get_related_services(
+            source_equipment, interface, r)}
+        result['related-services'] = list(rs_dict.values())
+
+        if_services = r.get(f'ims:interface_services:{ims_source_equipment}:'
+                            f'{ims_interface}')
+        if if_services:
+            if_services = json.loads(if_services.decode('utf-8'))
+            result['locations'] = list(_location_from_services(if_services, r))
+
+        if not result.get('locations'):
+            result['locations'] = [
+                build_locations(
+                    _location_from_equipment(ims_source_equipment, r))
+            ]
 
         result['locations'] = _remove_duplicates_from_list(result['locations'])
         result = json.dumps(result)
@@ -371,24 +398,32 @@ def peer_info(address):
             info = info.decode('utf-8')
             info = json.loads(info)
             result['ix-public-peer-info'] = ix_peering_info(info)
-            result['locations'] += _location_from_equipment(info['router'])
+            result['locations'].append(build_locations(
+                _location_from_equipment(info['router'], r)))
 
         info = r.get(f'vpn_rr_peer:{address}')
         if info:
             info = info.decode('utf-8')
             info = json.loads(info)
             result['vpn-rr-peer-info'] = info
-            result['locations'] += _location_from_equipment(info['router'])
+            result['locations'].append(build_locations(
+                _location_from_equipment(info['router'], r)))
 
         interfaces = list(find_interfaces_and_services(address))
         if interfaces:
             result['interfaces'] = interfaces
             for i in interfaces:
                 for s in i['services']:
-                    result['locations'] += \
-                        _location_from_equipment(s['equipment'])
-                    result['locations'] += \
-                        _location_from_equipment(s['other_end_equipment'])
+                    result['locations'].append(
+                        build_locations(
+                            _location_from_equipment(s['router'], r),
+                            _location_from_equipment(
+                                s['other_end_equipment'], r))
+                    )
+                    # result['locations'] += \
+                    #     _location_from_equipment(s['equipment'], r)
+                    # result['locations'] += \
+                    #     _location_from_equipment(s['other_end_equipment'], r)
 
         result['locations'] = _remove_duplicates_from_list(result['locations'])
         result = json.dumps(result)
@@ -431,10 +466,15 @@ def get_trap_metadata(source_equipment, interface, circuit_id):
             if top_level_services:
                 result['related-services'] = top_level_services
             for s in result['services']:
-                result['locations'] += \
-                    _location_from_equipment(s['equipment'])
-                result['locations'] += \
-                    _location_from_equipment(s['other_end_equipment'])
+                result['locations'].append(
+                    build_locations(
+                        _location_from_equipment(s['router'], r),
+                        _location_from_equipment(s['other_end_equipment'], r))
+                )
+                # result['locations'] += \
+                #     _location_from_equipment(s['equipment'], r)
+                # result['locations'] += \
+                #     _location_from_equipment(s['other_end_equipment'], r)
         gls = {tls['id']: {
                 'id': tls['id'],
                 'name': tls['name'],
@@ -503,8 +543,8 @@ def get_fiberlink_trap_metadata(ne_name_str, object_name_str):
                        x[0]['df_route_id'] == x[1]['df_route_id']]
             if matches:
                 match = matches[0]
-                locations_a = _location_from_equipment(equipment_a)
-                locations_b = _location_from_equipment(equipment_b)
+                locations_a = _location_from_equipment(equipment_a, r)
+                locations_b = _location_from_equipment(equipment_b, r)
                 if locations_a:
                     loc_a = locations_a[0]['a']
                 else:
@@ -520,10 +560,7 @@ def get_fiberlink_trap_metadata(ne_name_str, object_name_str):
                 # removed
                 result = {
                     'locations': [
-                        {
-                            'a': loc_a,
-                            'b': loc_b
-                        }
+                        build_locations(loc_a, loc_b)
                     ],
                     'ends': {
                         'a': {
-- 
GitLab