From 88aea80913b1e732d321b7b13f2771e6c03cbb70 Mon Sep 17 00:00:00 2001
From: Erik Reid <erik.reid@geant.org>
Date: Fri, 1 Mar 2019 15:19:46 +0100
Subject: [PATCH] cache peer-info responses

---
 inventory_provider/routes/classifier.py | 82 ++++++++++++++-----------
 inventory_provider/tasks/worker.py      |  1 +
 2 files changed, 47 insertions(+), 36 deletions(-)

diff --git a/inventory_provider/routes/classifier.py b/inventory_provider/routes/classifier.py
index dde5fa03..a39f7a0d 100644
--- a/inventory_provider/routes/classifier.py
+++ b/inventory_provider/routes/classifier.py
@@ -1,7 +1,7 @@
 import ipaddress
 import json
 
-from flask import Blueprint, Response, jsonify
+from flask import Blueprint, Response
 
 from inventory_provider.routes import common
 
@@ -92,40 +92,50 @@ def find_interfaces(address):
 @common.require_accepts_json
 def peer_info(address):
 
-    try:
-        address_obj = ipaddress.ip_address(address)
-    except ValueError:
-        return Response(
-            response='unable to parse %r as an ip address' % address,
-            status=422,
-            mimetype="text/html")
-
     r = common.get_redis()
 
-    result = {}
-
-    info = r.get('ix_public_peer:%s' % address)
-    if info:
-        info = info.decode('utf-8')
-        result['ix-public-peer-info'] = json.loads(info)
-        description = result['ix-public-peer-info']['description']
-        assert description is not None  # sanity
-        result['ix-public-peer-group'] = list(
-            ix_peering_group(address_obj, description))
-
-    info = r.get('vpn_rr_peer:%s' % address)
-    if info:
-        info = info.decode('utf-8')
-        result['vpn-rr-peer-info'] = json.loads(info)
-
-    interfaces = list(find_interfaces(address_obj))
-    if interfaces:
-        result['interfaces'] = interfaces
-
-    if not result:
-        return Response(
-            response='no peering info found for %s' % address,
-            status=404,
-            mimetype="text/html")
-
-    return jsonify(result)
+    cache_key = 'classifier:peer-cache:%s' % address
+
+    result = r.get(cache_key)
+    if result:
+        result = result.decode('utf-8')
+    else:
+        try:
+            address_obj = ipaddress.ip_address(address)
+        except ValueError:
+            return Response(
+                response='unable to parse %r as an ip address' % address,
+                status=422,
+                mimetype="text/html")
+
+        result = {}
+
+        info = r.get('ix_public_peer:%s' % address)
+        if info:
+            info = info.decode('utf-8')
+            result['ix-public-peer-info'] = json.loads(info)
+            description = result['ix-public-peer-info']['description']
+            assert description is not None  # sanity
+            result['ix-public-peer-group'] = list(
+                ix_peering_group(address_obj, description))
+
+        info = r.get('vpn_rr_peer:%s' % address)
+        if info:
+            info = info.decode('utf-8')
+            result['vpn-rr-peer-info'] = json.loads(info)
+
+        interfaces = list(find_interfaces(address_obj))
+        if interfaces:
+            result['interfaces'] = interfaces
+
+        if not result:
+            return Response(
+                response='no peering info found for %s' % address,
+                status=404,
+                mimetype="text/html")
+
+        result = json.dumps(result)
+        # cache this data for the next call
+        r.set(cache_key, result.encode('utf-8'))
+
+    return Response(result, mimetype="application/json")
diff --git a/inventory_provider/tasks/worker.py b/inventory_provider/tasks/worker.py
index 1830053b..59eb170d 100644
--- a/inventory_provider/tasks/worker.py
+++ b/inventory_provider/tasks/worker.py
@@ -260,6 +260,7 @@ def clear_cached_classifier_responses(hostname):
     r = get_redis(InventoryTask.config)
     for k in r.keys('classifier:cache:%s:*' % hostname):
         r.delete(k)
+    # TODO: remove peer-cache (after adding hostname to query)
 
 
 def _refresh_peers(hostname, key_base, peers):
-- 
GitLab