From 49a7ade45297e53b18c429521d017b40396a9873 Mon Sep 17 00:00:00 2001
From: Erik Reid <erik.reid@geant.org>
Date: Fri, 15 Mar 2019 13:56:35 +0100
Subject: [PATCH] added related services & made test validation schema stricter

---
 inventory_provider/routes/classifier.py | 28 ++++++++++++++
 test/test_classifier_routes.py          | 51 +++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/inventory_provider/routes/classifier.py b/inventory_provider/routes/classifier.py
index b2e96b65..bcf80690 100644
--- a/inventory_provider/routes/classifier.py
+++ b/inventory_provider/routes/classifier.py
@@ -1,5 +1,6 @@
 import ipaddress
 import json
+import re
 
 from flask import Blueprint, Response
 
@@ -33,6 +34,22 @@ def handle_request_error(error):
         status=error.status_code)
 
 
+def base_interface_name(interface):
+    m = re.match(r'(.*?)(\.\d+)?$', interface)
+    assert m  # sanity: anything should match
+    return m.group(1)
+
+
+def related_interfaces(hostname, interface):
+    r = common.get_redis()
+    prefix = 'netconf-interfaces:%s:' % hostname
+    for k in r.keys(prefix + base_interface_name(interface) + '*'):
+        k = k.decode('utf-8')
+        assert k.startswith(prefix)  # sanity
+        assert len(k) > len(prefix)  # sanity (contains at least an interface)
+        yield k[len(prefix):]
+
+
 @routes.route("/trap-metadata/<source_equipment>/<path:interface>",
               methods=['GET', 'POST'])
 @common.require_accepts_json
@@ -57,6 +74,17 @@ def get_trap_metadata(source_equipment, interface):
         if ifc_info:
             result['interface'] = json.loads(ifc_info.decode('utf-8'))
 
+        def _related_services():
+            for related in related_interfaces(source_equipment, interface):
+                s = r.get('opsdb:interface_services:%s:%s'
+                          % (source_equipment, related))
+                if s:
+                    yield json.loads(s.decode('utf-8'))
+
+        related_services = list(_related_services())
+        if related_services:
+            result['related-services'] = related_services
+
         if not result:
             return Response(
                 response="no available info for {} {}".format(
diff --git a/test/test_classifier_routes.py b/test/test_classifier_routes.py
index 308a7257..f44770dc 100644
--- a/test/test_classifier_routes.py
+++ b/test/test_classifier_routes.py
@@ -7,6 +7,57 @@ DEFAULT_REQUEST_HEADERS = {
     "Accept": ["application/json"]
 }
 
+JUNIPER_LINK_METADATA = {
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "type": "object",
+
+    "definitions": {
+        "ip-address": {
+            "type": "string",
+            "oneOf": [
+                {"pattern": r'^(\d+\.){3}\d+$'},
+                {"pattern": r'^([a-f\d]{4}:){7}[a-f\d]{4}$'}
+            ]
+        },
+        "ipv4-interface-address": {
+            "type": "string",
+            "pattern": r'^(\d+\.){3}\d+/\d+$'
+        },
+        "ipv6-interface-address": {
+            "type": "string",
+            "pattern": r'^[a-f\d:]+/\d+$'
+        },
+        "interface-info": {
+            "type": "object",
+            "properties": {
+                "name": {"type": "string"},
+                "description": {"type": "string"},
+                "ipv4": {"$ref": "#/definitions/ipv4-interface-addres"},
+                "ipv4": {"$ref": "#/definitions/ipv6-interface-addres"},
+            },
+            "required": ["name", "description", "ipv4", "ipv6"],
+            "additionalProperties": False
+        },
+        "service-info": {
+            "type": "object"
+        }
+    },
+
+    "type": "object",
+    "properties": {
+        "services": {
+            "type": "array",
+            "items": {"$ref": "#/definitions/service-info"}
+        },
+        "interface": {"$ref": "#/definitions/interface-info"},
+        "related-services": {
+            "type": "array",
+            "items": {"$ref": "#/definitions/service-info"}
+        }
+    },
+    "additionalProperties": False
+}
+
 
 def test_trap_metadata(client_with_mocked_data):
     response_schema = {
-- 
GitLab