From 68a52f40d6acad9aa478c6d5041feb1ce2d564fd Mon Sep 17 00:00:00 2001
From: Erik Reid <erik.reid@geant.org>
Date: Thu, 12 Dec 2019 20:40:40 +0100
Subject: [PATCH] add customers to interface list

---
 inventory_provider/tasks/worker.py | 83 ++++++++++++++++++++++++++++--
 1 file changed, 78 insertions(+), 5 deletions(-)

diff --git a/inventory_provider/tasks/worker.py b/inventory_provider/tasks/worker.py
index 9e7c90fc..a744560b 100644
--- a/inventory_provider/tasks/worker.py
+++ b/inventory_provider/tasks/worker.py
@@ -574,12 +574,14 @@ def refresh_finalizer(self, pending_task_ids_json):
     logger.debug('<<< refresh_finalizer')
 
 
-def _build_service_category_interface_list(update_callback=lambda s: None):
-    logger.debug('>>> _build_interface_services')
-
-    r = get_next_redis(InventoryTask.config)
+def _build_service_interface_user_list():
 
     def _interfaces():
+        """
+        yields interface info from netconf
+        :return:
+        """
+        r = get_next_redis(InventoryTask.config)
         for k in r.scan_iter('netconf-interfaces:*'):
             k = k.decode('utf-8')
             (_, router_name, ifc_name) = k.split(':')
@@ -594,6 +596,77 @@ def _build_service_category_interface_list(update_callback=lambda s: None):
                 'description': info['description']
             }
 
+    def _lookup_interface_services(wanted_interfaces):
+        """
+        yields interface info from opsdb (with service id)
+        ... only interfaces in wanted_interfaces
+        :param wanted_interfaces:
+        :return:
+        """
+        r = get_next_redis(InventoryTask.config)
+        for k in r.scan_iter('opsdb:interface_services:*'):
+            k = k.decode('utf-8')
+            (_, _, router, ifc_name) = k.split(':')
+
+            router_interface_key = f'{router}:{ifc_name}'
+            if router_interface_key not in wanted_interfaces:
+                continue
+
+            info = r.get(k).decode('utf-8')
+            info = json.loads(info)
+
+            for service in info:
+                yield {
+                    'router': router,
+                    'interface': ifc_name,
+                    'service_id': service['id']
+                }
+
+    # dict: 'router:interface' -> {'router', 'interface', 'description'}
+    netconf_interface_map = dict([
+        (f'{i["router"]}:{i["interface"]}', i) for i in _interfaces()])
+
+    # dict: 'router:interface' -> [list of service_ids]
+    opsdb_interface_map = {}
+    for i in _lookup_interface_services(netconf_interface_map.keys()):
+        key = f'{i["router"]}:{i["interface"]}'
+        opsdb_interface_map.setdefault(key, []).append(i['service_id'])
+
+    # dict service_id[int] -> [list of users]
+    service_user_map = {}
+    with db.connection(InventoryTask.config["ops-db"]) as cx:
+        service_ids = set()
+        for l in opsdb_interface_map.values():
+            for id in l:
+                service_ids.add(id)
+        for user in opsdb.get_service_users(cx, list(service_ids)):
+            service_user_map.setdefault(
+                user['service_id'], []).append(user['user'])
+
+    def _users(ifc_key):
+        """
+        ifc = 'router:ifc_name'
+        :param ifc:
+        :return: list of users
+        """
+        for service_id in opsdb_interface_map.get(ifc_key, []):
+            for user in service_user_map.get(service_id, []):
+                yield user
+
+    for k, v in netconf_interface_map.items():
+        users = _users(k)
+        if not users:
+            yield v
+        else:
+            for u in users:
+                info = {'user': u}
+                info.update(v)
+                yield info
+
+
+def _build_service_category_interface_list(update_callback=lambda s: None):
+    logger.debug('>>> _build_interface_services')
+
     def _classify(ifc):
         if ifc['description'].startswith('SRV_MDVPN'):
             return 'mdvpn'
@@ -605,7 +678,7 @@ def _build_service_category_interface_list(update_callback=lambda s: None):
     rp = r.pipeline()
 
     update_callback('loading all known interfaces')
-    interfaces = list(_interfaces())
+    interfaces = list(_build_service_interface_user_list())
     update_callback(f'loaded {len(interfaces)} interfaces, '
                     'saving by service category')
 
-- 
GitLab