From 5243d531b7aa4c3696901ba21da8b55f5ce17324 Mon Sep 17 00:00:00 2001
From: Erik Reid <erik.reid@geant.org>
Date: Sat, 27 Mar 2021 11:52:10 +0100
Subject: [PATCH] draft /poller/eumetsat-multicast handler

---
 inventory_provider/routes/poller.py | 109 ++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)

diff --git a/inventory_provider/routes/poller.py b/inventory_provider/routes/poller.py
index 79c3ec88..6c95ad68 100644
--- a/inventory_provider/routes/poller.py
+++ b/inventory_provider/routes/poller.py
@@ -3,6 +3,8 @@ import logging
 import re
 
 from flask import Blueprint, Response, current_app
+from lxml import etree
+
 from inventory_provider import juniper
 from inventory_provider.routes import common
 
@@ -61,6 +63,7 @@ INTERFACE_LIST_SCHEMA = {
     'items': {'$ref': '#/definitions/interface'}
 }
 
+
 INTERFACE_SPEED_LIST_SCHEMA = {
     '$schema': 'http://json-schema.org/draft-07/schema#',
 
@@ -81,6 +84,37 @@ INTERFACE_SPEED_LIST_SCHEMA = {
     'items': {'$ref': '#/definitions/interface'}
 }
 
+MULTICAST_SUBSCRIPTION_LIST_SCHEMA = {
+    '$schema': 'http://json-schema.org/draft-07/schema#',
+
+    'definitions': {
+        'ipv4-address': {
+            'type': 'string',
+            'pattern': r'^(\d+\.){3}\d+$'
+        },
+        'subscription': {
+            'type': 'object',
+            'properties': {
+                'router': {'type': 'string'},
+                'subscription': {'$ref': '#/definitions/ipv4-address'},
+                'endpoint': {'$ref': '#/definitions/ipv4-address'},
+                'oid': {
+                    'type': 'string',
+                    'pattern': r'^(\d+\.)*\d+$'
+                },
+                'community': {'type': 'string'}
+            },
+            'required': [
+                'router', 'subscription', 'endpoint', 'oid', 'community'],
+            'additionalProperties': False
+        },
+    },
+
+    'type': 'array',
+    'items': {'$ref': '#/definitions/subscription'}
+}
+
+
 
 @routes.after_request
 def after_request(resp):
@@ -387,3 +421,78 @@ def interface_speeds(hostname=None):
         r.set(cache_key, result.encode('utf-8'))
 
     return Response(result, mimetype="application/json")
+
+
+@routes.route("/eumetsat-multicast", methods=['GET', 'POST'])
+@common.require_accepts_json
+def eumetsat_multicast(hostname=None):
+    """
+    Handler for `/poller/eumetsat-multicast` which returns information about
+    multicast subscriptions on mx1.fra.de.geant.net.
+
+    The response is a list of oid/router/community structures that all
+    all subscription octet counters to be polled.
+
+    .. asjson::
+       inventory_provider.routes.poller.MULTICAST_SUBSCRIPTION_LIST_SCHEMA
+
+    This method is basically hard-coded data,
+    based on the information in POL1-395.
+
+    :return:
+    """
+
+    MX1_FRA = 'mx1.fra.de.geant.net'
+    SUBSCRIPTIONS = [{
+            'subscription': f'232.223.223.{idx}',
+            'endpoint':'193.17.9.3',
+        } for idx in range(1, 73)]
+
+    SUBSCRIPTIONS.append(
+        {'subscription': '232.223.223.1',  'endpoint': '193.17.9.7'})
+    SUBSCRIPTIONS.append(
+        {'subscription': '232.223.223.22',  'endpoint': '193.17.9.7'})
+
+    def _oid(sub):
+        return ('1.3.6.1.2.1.83.1.1.2.1.16'
+                f'.{sub["subscription"]}.{sub["endpoint"]}'
+                '.255.255.255.255')
+
+
+    cache_key = f'classifier-cache:poller-eumetsat-multicast'
+
+    r = common.get_current_redis()
+
+    result = r.get(cache_key)
+    if result:
+        result = result.decode('utf-8')
+    else:
+        netconf = r.get(f'netconf:{MX1_FRA}')
+        if not netconf:
+            return Response(
+                status=503,
+                response=f'error loading netconf for {MX1_FRA}')
+
+        netconf_doc = etree.fromstring(netconf.decode('utf-8'))
+        community = juniper.snmp_community_string(netconf_doc)
+        if not community:
+            return Response(
+                status=503,
+                response=f'error extracting community string for {MX1_FRA}')
+
+        def _rsp_element(sub):
+            result = {
+                'router': MX1_FRA,
+                'oid': _oid(sub),
+                'community': community
+            }
+            result.update(sub)
+            return result
+
+        result = [_rsp_element(sub) for sub in SUBSCRIPTIONS]
+
+        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")
-- 
GitLab