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

from flask import Blueprint, jsonify, Response, current_app

from inventory_provider.routes import common

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')

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

    def _routers():
        for doc in common.load_json_docs(
                config_params=current_app.config['INVENTORY_PROVIDER_CONFIG'],
                key_pattern='opsdb:lg:*'):
            yield doc['value']

    redis = common.get_current_redis()
    cache_key = f'classifier-cache:lg:{access}'
    result = redis.get(cache_key)

    if result:
        result = json.loads(result.decode('utf-8'))
    else:
        result = list(filter(_visible, _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)