Skip to content
Snippets Groups Projects
provision.py 7.42 KiB
Newer Older
from brian_dashboard_manager.config import DEFAULT_ORGANIZATIONS
Bjarke Madsen's avatar
Bjarke Madsen committed
from brian_dashboard_manager.grafana.utils.request import \
    AdminRequest, \
    TokenRequest
from brian_dashboard_manager.grafana.organization import \
    get_organizations, create_organization, create_api_token, \
    delete_api_token, delete_expired_api_tokens, set_home_dashboard
Bjarke Madsen's avatar
Bjarke Madsen committed
from brian_dashboard_manager.grafana.dashboard import \
    get_dashboard_definitions, create_dashboard, find_dashboard
Bjarke Madsen's avatar
Bjarke Madsen committed
from brian_dashboard_manager.grafana.datasource import \
    check_provisioned, create_datasource
from brian_dashboard_manager.grafana.folder import \
    get_folders, create_folder
from brian_dashboard_manager.inventory_provider.interfaces import \
    get_interfaces
from brian_dashboard_manager.templating.nren_access import generate_nrens
Bjarke Madsen's avatar
Bjarke Madsen committed

from brian_dashboard_manager.templating.helpers import is_re_customer, \
    is_cls, is_ias_customer, is_ias_private, is_ias_public, is_ias_upstream, \
    is_lag_backbone, is_nren, is_phy_upstream, is_re_peer, is_gcs, \
    is_geantopen, is_l2circuit, is_lhcone_peer, is_lhcone_customer, is_mdvpn,\
    get_interface_data, parse_backbone_name, parse_phy_upstream_name, \
    get_dashboard_data

from brian_dashboard_manager.templating.render import render_dashboard

logger = logging.getLogger(__name__)


def provision(config):

    request = AdminRequest(**config)
    all_orgs = get_organizations(request)

    orgs_to_provision = config.get('organizations', DEFAULT_ORGANIZATIONS)
    missing = (org['name'] for org in orgs_to_provision
               if org['name'] not in [org['name'] for org in all_orgs])
    for org_name in missing:
        org_data = create_organization(request, org_name)
        all_orgs.append(org_data)

    interfaces = get_interfaces(config['inventory_provider'])
    for org in all_orgs:
        org_id = org['id']
        delete_expired_api_tokens(request, org_id)
        token = create_api_token(request, org_id)
        token_request = TokenRequest(token=token['key'], **config)

        folders = get_folders(token_request)

        def find_folder(title):

            try:
                folder = next(
                    f for f in folders if f['title'].lower() == title.lower())
            except StopIteration:
                folder = None

            if not folder:
                logger.info(f'Created folder: {title}')
                folder = create_folder(token_request, title)
                folders.append(folder)
            return folder

        logger.info(
            f'--- Provisioning org {org["name"]} (ID #{org_id}) ---')

        try:
            org_config = next(
                o for o in orgs_to_provision if o['name'] == org['name'])
        except StopIteration:
            org_config = None

        if not org_config:
            logger.error(
                f'Org {org["name"]} does not have valid configuration.')
            org['info'] = 'Org exists in grafana but is not configured'
            continue

        # Only provision influxdb datasource for now
        datasource = config.get('datasources').get('influxdb')

        # Provision missing data sources
        if not check_provisioned(token_request, datasource):
            ds = create_datasource(token_request,
                                   datasource,
                                   config.get('datasources'))
            if ds:
                logger.info(
                    f'Provisioned datasource: {datasource["name"]}')

        excluded_nrens = org_config.get('excluded_nrens', [])
        excluded_nrens = list(map(lambda f: f.lower(), excluded_nrens))

        def excluded(interface):
            desc = interface.get('description', '').lower()
            return not any(nren.lower() in desc for nren in excluded_nrens)
        excluded_interfaces = list(filter(excluded, interfaces))

        dashboards = {
            'CLS': {'predicate': is_cls, 'tag': 'CLS'},
            'RE PEER': {'predicate': is_re_peer, 'tag': 'RE_PEER'},
            'RE CUST': {'predicate': is_re_customer, 'tag': 'RE_CUST'},
            'GEANTOPEN': {'predicate': is_geantopen, 'tag': 'GEANTOPEN'},
            'GCS': {'predicate': is_gcs, 'tag': 'AUTOMATED_L2_CIRCUITS'},
            'L2 CIRCUIT': {'predicate': is_l2circuit, 'tag': 'L2_CIRCUITS'},
            'LHCONE PEER': {'predicate': is_lhcone_peer, 'tag': 'LHCONE_PEER'},
            'LHCONE CUST': {
                'predicate': is_lhcone_customer,
                'tag': 'LHCONE_CUST'
            },
            'MDVPN Customers': {'predicate': is_mdvpn, 'tag': 'MDVPN'},
            'Infrastructure Backbone': {
                'predicate': is_lag_backbone,
                'tag': 'BACKBONE',
                'errors': True,
                'parse_func': parse_backbone_name
            },
            'IAS PRIVATE': {'predicate': is_ias_private, 'tag': 'IAS_PRIVATE'},
            'IAS PUBLIC': {'predicate': is_ias_public, 'tag': 'IAS_PUBLIC'},
            'IAS CUSTOMER': {
                'predicate': is_ias_customer,
                'tag': 'IAS_CUSTOMER'
            },
            'IAS UPSTREAM': {
                'predicate': is_ias_upstream,
                'tag': 'IAS_UPSTREAM'
            },
            'GWS PHY Upstream': {
                'predicate': is_phy_upstream,
                'tag': 'GWS_UPSTREAM',
                'errors': True,
                'parse_func': parse_phy_upstream_name
            }

        }
        # Provision dashboards, overwriting existing ones.

        datasource_name = datasource.get('name', 'PollerInfluxDB')
        for folder_name, dash in dashboards.items():
            folder = find_folder(folder_name)
            predicate = dash['predicate']
            tag = dash['tag']

            # dashboard will include error panel
            errors = dash.get('errors')

            # custom parsing function for description to dashboard name
            parse_func = dash.get('parse_func')

            logger.info(f'Provisioning {folder_name} dashboards')

            relevant_interfaces = filter(predicate, excluded_interfaces)
            data = get_interface_data(relevant_interfaces, parse_func)
            dash_data = get_dashboard_data(data, datasource_name, tag, errors)
            for dashboard in dash_data:
                rendered = render_dashboard(dashboard)
                create_dashboard(token_request, rendered, folder['id'])

        # NREN Access dashboards
        # uses a different template than the above.
        logger.info('Provisioning NREN Access dashboards')
        folder = find_folder('NREN Access')
        nrens = filter(is_nren, excluded_interfaces)
        for dashboard in generate_nrens(nrens, datasource_name):
            create_dashboard(token_request, dashboard, folder['id'])

        # Non-generated dashboards
        excluded_dashboards = org_config.get('excluded_dashboards', [])
        logger.info('Provisioning static dashboards')
        for dashboard in get_dashboard_definitions():
            if dashboard['title'] not in excluded_dashboards:
                if dashboard['title'].lower() == 'home':
                    dashboard['uid'] = 'home'
                create_dashboard(token_request, dashboard)

        # Home dashboard is always called "Home"
        # Make sure it's set for the organization
        home_dashboard = find_dashboard(token_request, 'Home')
        if home_dashboard:
            set_home_dashboard(token_request, home_dashboard['id'])

        delete_api_token(request, org_id, token['id'])

    return all_orgs