Skip to content
Snippets Groups Projects
data.py 3.96 KiB
import json
import logging
import re

from inventory_provider.db import opsdb, db
from inventory_provider.tasks.common import get_next_redis

logger = logging.getLogger(__name__)


def build_service_interface_user_list(config):

    def _interfaces():
        """
        yields interface info from netconf
        :return:
        """
        r = get_next_redis(config)
        for k in r.scan_iter('netconf-interfaces:*'):
            k = k.decode('utf-8')
            (_, router_name, ifc_name) = k.split(':')

            info = r.get(k).decode('utf-8')
            info = json.loads(info)

            assert ifc_name == info['name']
            yield {
                'router': router_name,
                'interface': info['name'],
                'description': info['description']
            }

    def _lookup_interface_services(wanted_interfaces):
        """
        yields interface info from opsdb (with service id)
        ... only interfaces in wanted_interfaces
        :param wanted_interfaces:
        :return:
        """
        r = get_next_redis(config)
        for k in r.scan_iter('opsdb:interface_services:*'):
            k = k.decode('utf-8')
            fields = k.split(':')
            if len(fields) < 4:
                # there are some strange records
                # e.g. TS1.*, ts1.*, dp1.*, dtn*, ...
                continue
            router = fields[2]
            ifc_name = fields[3]

            router_interface_key = f'{router}:{ifc_name}'
            if router_interface_key not in wanted_interfaces:
                continue

            info = r.get(k).decode('utf-8')
            info = json.loads(info)

            yield {
                'router': router,
                'interface': ifc_name,
                'service_ids': set([service['id'] for service in info])
            }

    # dict: 'router:interface' -> {'router', 'interface', 'description'}
    netconf_interface_map = dict([
        (f'{i["router"]}:{i["interface"]}', i) for i in _interfaces()])

    # dict: 'router:interface' -> {'router', 'interface', set([service_ids])}
    opsdb_interface_map = dict([
        (f'{i["router"]}:{i["interface"]}', i)
        for i in _lookup_interface_services(netconf_interface_map.keys())])

    all_service_ids = set()
    for r in opsdb_interface_map.values():
        all_service_ids |= r['service_ids']
    all_service_ids = list(all_service_ids)

    # dict: service_id[int] -> [list of users]
    service_user_map = dict()
    with db.connection(config["ops-db"]) as cx:
        # for user in opsdb.get_service_users(cx, list(all_service_ids)):
        service_users = list(opsdb.get_service_users(cx, all_service_ids))
        for user in service_users:
            service_user_map.setdefault(
                user['service_id'], []).append(user['user'])

    def _users(ifc_key):
        """
        ifc = 'router:ifc_name'
        :param ifc:
        :return: list of users
        """
        users = set()
        if ifc_key not in opsdb_interface_map:
            return []
        service_id_list = opsdb_interface_map[ifc_key].get('service_ids', [])
        for service_id in service_id_list:
            users |= set(service_user_map.get(service_id, []))
        return list(users)

    for k, v in netconf_interface_map.items():
        v['users'] = _users(k)
        yield v


def derive_router_hostnames(config):
    r = get_next_redis(config)

    routers = r.get('netdash')
    assert routers
    netdash_equipment = json.loads(routers.decode('utf-8'))
    assert isinstance(netdash_equipment, (list, tuple))
    netdash_equipment = set(netdash_equipment)

    opsdb_equipment = set()
    for k in r.scan_iter('opsdb:interface_services:*'):
        m = re.match(
            'opsdb:interface_services:([^:]+):.*$',
            k.decode('utf-8'))
        if m:
            opsdb_equipment.add(m.group(1))
        else:
            logger.info("Unable to derive router name from %s" %
                        k.decode('utf-8'))
    return netdash_equipment & opsdb_equipment