Skip to content
Snippets Groups Projects
lg.py 3.38 KiB
import json
import logging

from flask import Blueprint, jsonify, Response, request

from inventory_provider.routes import common
from inventory_provider.routes.common import _ignore_cache_or_retrieve

logger = logging.getLogger(__name__)

routes = Blueprint("lg-query-routes", __name__)

ACCESS_PUBLIC = 'public'
ACCESS_INTERNAL = 'all'


LG_ROUTERS_SCHEMA = {
    "$schema": "http://json-schema.org/draft-07/schema#",

    "definitions": {
        "pop-info": {
            "type": "object",
            "properties": {
                "name": {"type": "string"},
                "abbreviation": {"type": "string"},
                "country": {"type": "string"},
                "country code": {"type": "string"},
                "city": {"type": "string"},
                "longitude": {"type": "number"},
                "latitude": {"type": "number"}
            },
            "required": [
                "name",
                "abbreviation",
                "country",
                "country code",
                "city",
                "longitude",
                "latitude"
            ],
            "additionalProperties": False
        },
        "router": {
            "type": "object",
            "properties": {
                "equipment name": {"type": "string"},
                "type": {
                    "type": "string",
                    "enum": ["INTERNAL", "CORE"]
                },
                "pop": {"$ref": "#/definitions/pop-info"}
            },
            "required": ["equipment name", "type", "pop"],
            "additionalProperties": False
        }
    },

    "type": "array",
    "items": {"$ref": "#/definitions/router"}
}


@routes.after_request
def after_request(resp):
    return common.after_request(resp)


@routes.route("/routers/<string:access>", methods=['GET', 'POST'])
@common.require_accepts_json
def routers(access):
    """
    Handler for `/lg/routers/[access]` that returns a list of
    router information for use by LG.

    Endpoints `/lg/routers/public` and `/lg/routers/all`
    are supported, and only publicly accessible routers
    or all routers, respectively, are returned.

    The response will be formatted according to the following schema:

    .. asjson::
       inventory_provider.routes.lg.LG_ROUTERS_SCHEMA

    :param access: one of `public` or `all`
    :return:
    """

    if access not in {ACCESS_INTERNAL, ACCESS_PUBLIC}:
        return Response(
            response='unknown access level',
            status=404,
            mimetype='text/html')

    redis = common.get_current_redis()

    def _visible(router):
        if access == ACCESS_INTERNAL:
            return True
        return router['type'] == 'CORE'

    def _routers():
        i = 0
        for k in redis.scan_iter('ims:lg:*'):
            rtr = redis.get(k.decode('utf-8')).decode('utf-8')
            rtr = json.loads(rtr)
            i += 1
            if _visible(rtr):
                yield rtr

    cache_key = f'classifier-cache:ims-lg:{access}'

    result = _ignore_cache_or_retrieve(request, cache_key, redis)

    if not result:
        result = list(_routers())
        # cache this data for the next call
        redis.set(cache_key, json.dumps(result).encode('utf-8'))

    if not result:
        return Response(
            response=f'no routers found for access level {access}',
            status=404,
            mimetype="text/html")

    return jsonify(result)