Skip to content
Snippets Groups Projects
data.py 5.23 KiB
import functools
import json

from flask import Blueprint, request, Response, current_app
import redis

routes = Blueprint("inventory-data-query-routes", __name__)

VERSION = {
    "api": "0.1",
    "module": "0.1"
}


def require_accepts_json(f):
    """
    used as a route handler decorator to return an error
    unless the request allows responses with type "application/json"
    :param f: the function to be decorated
    :return: the decorated function
    """
    @functools.wraps(f)
    def decorated_function(*args, **kwargs):
        # TODO: use best_match to disallow */* ...?
        if not request.accept_mimetypes.accept_json:
            return Response(
                response="response will be json",
                status=406,
                mimetype="text/html")
        return f(*args, **kwargs)
    return decorated_function


@routes.route("/version", methods=['GET', 'POST'])
@require_accepts_json
def version():
    return Response(
        json.dumps(VERSION),
        mimetype="application/json"
    )


@routes.route("/routers", methods=['GET', 'POST'])
@require_accepts_json
def routers():
    redis_config = current_app.config["INVENTORY_PROVIDER_CONFIG"]["redis"]
    r = redis.StrictRedis(
        host=redis_config["hostname"],
        port=redis_config["port"])
    return Response(
        json.dumps(list([k.decode("utf-8") for k in r.keys("*")])),
        mimetype="application/json")


@routes.route("/interfaces/<hostname>", methods=['GET', 'POST'])
@require_accepts_json
def router_interfaces(hostname):
    redis_config = current_app.config["INVENTORY_PROVIDER_CONFIG"]["redis"]
    r = redis.StrictRedis(
        host=redis_config["hostname"],
        port=redis_config["port"])
    ifc_data_string = r.hget(hostname, 'interfaces')
    if not ifc_data_string:
        return Response(
            response="no available info for '%s'" % hostname,
            status=404,
            mimetype="text/html")

    def _interfaces(d):
        for ii in d['interface-information']:
            for ifc_list in ii['physical-interface'] + ii['logical-interface']:
                for ifc in ifc_list:
                    yield {
                        'name': ifc['name'][0]['data'],
                        'description': ifc['description'][0]['data']
                    }

    ifc_data = json.loads(ifc_data_string.decode('utf-8'))
    interfaces = list(_interfaces(ifc_data))
    if not interfaces:
        return Response(
            response="no interfaces found for '%s'" % hostname,
            status=404,
            mimetype="text/html")

    return Response(
        json.dumps(interfaces),
        mimetype="application/json")


@routes.route("/snmp/<hostname>", methods=['GET', 'POST'])
@require_accepts_json
def snmp_ids(hostname):
    redis_config = current_app.config["INVENTORY_PROVIDER_CONFIG"]["redis"]
    r = redis.StrictRedis(
        host=redis_config["hostname"],
        port=redis_config["port"])
    ifc_data_string = r.hget(hostname, 'snmp-interfaces')
    if not ifc_data_string:
        return Response(
            response="no available info for '%s'" % hostname,
            status=404,
            mimetype="text/html")

    def _ifc_name(ifc):
        if 'v4InterfaceName' in ifc:
            return ifc['v4InterfaceName']
        if 'v6InterfaceName' in ifc:
            return ifc['v6InterfaceName']
        assert False, "sanity failure: no interface name found"

    ifc_data = json.loads(ifc_data_string.decode('utf-8'))
    result = [
        {'index': i['index'], 'name': _ifc_name(i)}
        for i in ifc_data]
    return Response(
        json.dumps(result),
        mimetype="application/json")


@routes.route("/debug-dump/<hostname>", methods=['GET', 'POST'])
@require_accepts_json
def debug_dump_router_info(hostname):
    redis_config = current_app.config["INVENTORY_PROVIDER_CONFIG"]["redis"]
    r = redis.StrictRedis(
        host=redis_config["hostname"],
        port=redis_config["port"])

    info = dict([(k.decode('utf-8'), json.loads(v.decode('utf-8')))
                 for k, v in r.hgetall(hostname).items()])
    if not info:
        return Response(
            response="no info found for router '%s'" % hostname,
            status=404,
            mimetype="text/html")

    return Response(
        json.dumps(info),
        mimetype="application/json")


@routes.route("/bgp/<hostname>", methods=['GET', 'POST'])
@require_accepts_json
def bgp_configs(hostname):
    redis_config = current_app.config["INVENTORY_PROVIDER_CONFIG"]["redis"]
    r = redis.StrictRedis(
        host=redis_config["hostname"],
        port=redis_config["port"])
    bgp_data_string = r.hget(hostname, 'bgp')
    if not bgp_data_string:
        return Response(
            response="no available bgp info for '%s'" % hostname,
            status=404,
            mimetype="text/html")

    def _interfaces(s):
        for ifc in json.loads(s):
            yield {
                "description": ifc["description"][0]["data"],
                "as": {
                    "peer": ifc["peer-as"][0]["data"],
                    "local": ifc["local-as"][0]["as-number"][0]["data"]
                }
            }
    interfaces = list(_interfaces(bgp_data_string.decode('utf-8')))
    return Response(
        json.dumps(interfaces),
        mimetype="application/json")