Skip to content
Snippets Groups Projects
msr.py 4.75 KiB
import itertools
import json

from flask import Blueprint, jsonify, Response

from inventory_provider.routes import common

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


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

    "definitions": {
        "service": {
            "type": "object",
            "properties": {
                "id": {"type": "integer"},
                "name": {"type": "string"},
                "equipment": {"type": "string"},
                "pop_name": {"type": "string"},
                "other_end_equipment": {"type": "string"},
                "other_end_pop_name": {"type": "string"},
                "speed_value": {"type": "integer"},
                "speed_unit": {"type": "string"}
            },
            "required": [
                "id", "name",
                "pop_name", "equipment",
                "other_end_pop_name", "other_end_equipment",
                "speed_value", "speed_unit"
            ],
            "additionalProperties": False
        }
    },

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


LOGICAL_SYSTEM_PEERING_LIST_SCHEMA = {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "definitions": {
        "peering-instance": {
            "type": "object",
            "properties": {
                "address": {"type": "string"},
                "description": {"type": "string"},
                "logical-system": {"type": "string"},
                "group": {"type": "string"},
                "hostname": {"type": "string"},
                "remote-asn": {"type": "integer"}
            },
            # only vrr peerings have remote-asn
            "required": [
                "address", "description", "logical-system", "group", "hostname"],
            "additionalProperties": False
        }
    },
    "type": "array",
    "items": {"$ref": "#/definitions/peering-instance"}
}


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


@routes.route("/access-services", methods=['GET', 'POST'])
@common.require_accepts_json
def access_services():
    """
    Handler for `/msr/access-services`.

    This method is in development, not yet used.

    The response will be formatted according to the following schema:

    .. asjson::
       inventory_provider.routes.msr.ACCESS_SERVICES_LIST_SCHEMA

    :param name:
    :return:
    """
    redis = common.get_current_redis()

    def _services():
        for k in redis.scan_iter('opsdb:access_services:*'):
            service = redis.get(k.decode('utf-8')).decode('utf-8')
            yield json.loads(service)

    cache_key = 'classifier-cache:msr:access-services'
    result = redis.get(cache_key)

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

    if not result:
        return Response(
            response='no access services found',
            status=404,
            mimetype="text/html")

    return jsonify(result)


@routes.route("/logical-system-peerings", methods=['GET', 'POST'])
@routes.route("/logical-system-peerings/<name>", methods=['GET', 'POST'])
@common.require_accepts_json
def logical_system_peerings(name=None):
    """
    Handler for `/msr/logical-system-peerings

    This method will return a list of all peerings configured
    for the requested logical-system name on any router, or for any
    logical system if no parameter is given.

    The response will be formatted according to the following schema:

    .. asjson::
       inventory_provider.routes.msr.LOGICAL_SYSTEM_PEERING_LIST_SCHEMA

    :return:
    """

    r = common.get_current_redis()

    def _get_all_ls_keys():
        keys = []
        for k in r.scan_iter(f'juniper-peerings:logical-system:*', count=1000):
            keys.append(k.decode('utf-8'))
        return keys

    def _load_list_items(key):
        value = r.get(key)
        if value:
            yield from json.loads(value.decode('utf-8'))

    cache_key = 'classifier-cache:msr:logical-system-peerings'
    if name:
        cache_key = f'{cache_key}:name'

    items = r.get(cache_key)

    if items:
        items = json.loads(items.decode('utf-8'))
    else:
        if name:
            items = _load_list_items(f'juniper-peerings:logical-system:{name}')
        else:
            gen_list = list(map(_load_list_items, _get_all_ls_keys()))
            items = itertools.chain(*gen_list)

        items = list(items)
        if not items:
            return Response(
                response='no peerings found',
                status=404,
                mimetype="text/html")

        r.set(cache_key, json.dumps(items).encode('utf-8'))

    return jsonify(items)