Skip to content
Snippets Groups Projects
Commit 8e08ea7d authored by Release Webservice's avatar Release Webservice
Browse files

Finished release 0.66.

parents 9dbfc4eb 7a2c8469
No related branches found
No related tags found
No related merge requests found
Showing
with 552 additions and 347 deletions
......@@ -2,6 +2,10 @@
All notable changes to this project will be documented in this file.
## [0.66] - 2021-06-09
- POL1-445: added /poller/gws/direct endpoint
- DBOARD3-445: bugfixes in /lg/routers/X endpoint
## [0.65] - 2021-05-28
- DBOARD3-438: Changed status of non-monitored services
- DBOARD3-439: initial LnetD endpoint
......
......@@ -17,4 +17,4 @@ by an HTTP API.
:caption: Contents:
configuration
protocol/index
\ No newline at end of file
protocol
\ No newline at end of file
......@@ -14,6 +14,8 @@ beyond the scope of this document.
Please refer to [RFC 2616](https://tools.ietf.org/html/rfc2616)
and www.json.org for more details.
.. contents:: :local:
/version
-------------
......@@ -24,14 +26,16 @@ and www.json.org for more details.
API modules
--------------
.. toctree::
:maxdepth: 2
:caption: Contents:
classifier
poller
lg
data
jobs
msr
lnetd
\ No newline at end of file
.. automodule:: inventory_provider.routes.classifier
.. automodule:: inventory_provider.routes.poller
.. automodule:: inventory_provider.routes.msr
.. automodule:: inventory_provider.routes.lg
.. automodule:: inventory_provider.routes.lnetd
.. automodule:: inventory_provider.routes.data
.. automodule:: inventory_provider.routes.jobs
.. classifier endpoint docs
Classifier Endpoints
=========================
These endpoints are intended for use by Dashboard V3.
.. contents:: :local:
/classifier/peer-info
---------------------
.. autofunction:: inventory_provider.routes.classifier.get_bgp_peer_info
/classifier/juniper-link-info
-----------------------------
.. autofunction:: inventory_provider.routes.classifier.get_juniper_link_info
/classifier/infinera-lambda-info
--------------------------------
.. autofunction:: inventory_provider.routes.classifier.get_infinera_lambda_info
/classifier/infinera-fiberlink-info
------------------------------------
.. autofunction::
inventory_provider.routes.classifier.get_fiberlink_trap_metadata
/classifier/coriant-info
------------------------
.. autofunction:: inventory_provider.routes.classifier.get_coriant_info
/classifier/mtc-interface-info
--------------------------------
.. autofunction:: inventory_provider.routes.classifier.get_mtc_interface_info
.. poller endpoint docs
Data Endpoints
=========================
These endpoints are temporary and will be removed.
.. contents:: :local:
/data/routers
---------------------------------
.. autofunction:: inventory_provider.routes.data.routers
/data/interfaces
---------------------------------
.. autofunction:: inventory_provider.routes.data.router_interfaces
/data/pop
---------------------------------
.. autofunction:: inventory_provider.routes.data.equipment_location
.. poller endpoint docs
Jobs Endpoints
=========================
These endpoints are used for monitoring running jobs.
.. contents:: :local:
/jobs/update
---------------------------------
.. autofunction:: inventory_provider.routes.jobs.update
/jobs/check-task-status
---------------------------------
.. autofunction:: inventory_provider.routes.jobs.check_task_status
/jobs/log
---------------------------------
.. autofunction:: inventory_provider.routes.jobs.load_task_log
.. LG endpoint docs
LG Support Endpoints
=========================
These endpoints are intended for use by LG.
/lg/interfaces
---------------------------------
.. autofunction:: inventory_provider.routes.lg.routers
.. LnetD endpoint docs
LnetD support
=========================
This endpoint is intended for use with LnetD
.. contents:: :local:
/LnetD/interfaces</hostname>
---------------------------------
.. autofunction:: inventory_provider.routes.lnetd.interfaces
.. poller endpoint docs
MSR Support Endpoints
=========================
These endpoints are intended for use by MSR.
.. contents:: :local:
/msr/access-services
---------------------------------
.. autofunction:: inventory_provider.routes.msr.access_services
/msr/bgp/logical-systems
-------------------------------------
.. autofunction:: inventory_provider.routes.msr.get_logical_systems
/msr/bgp/logical-system-peerings</name>
------------------------------------------
.. autofunction:: inventory_provider.routes.msr.logical_system_peerings
/msr/bgp/groups
-------------------------------------
.. autofunction:: inventory_provider.routes.msr.get_peering_groups
/msr/bgp/group-peerings</name>
-------------------------------------
.. autofunction:: inventory_provider.routes.msr.bgp_group_peerings
/msr/bgp/routing-instances
-------------------------------------
.. autofunction:: inventory_provider.routes.msr.get_peering_routing_instances
/msr/bgp/routing-instance-peeringns</name>
--------------------------------------------
.. autofunction:: inventory_provider.routes.msr.bgp_routing_instance_peerings
helpers
-------------------------------------
.. autofunction:: inventory_provider.routes.msr._handle_peering_group_list_request
.. autofunction:: inventory_provider.routes.msr._handle_peering_group_request
.. poller endpoint docs
BRIAN support Endpoints
=========================
These endpoints are intended for use by BRIAN.
.. contents:: :local:
/poller/interfaces</hostname>
---------------------------------
.. autofunction:: inventory_provider.routes.poller.interfaces
/poller/speeds</hostname>
---------------------------------
.. autofunction:: inventory_provider.routes.poller.interface_speeds
/poller/eumetsat-multicast
---------------------------------
.. autofunction:: inventory_provider.routes.poller.eumetsat_multicast
......@@ -2,144 +2,208 @@ import json
import jsonschema
CONFIG_SCHEMA = {
"$schema": "http://json-schema.org/draft-07/schema#",
'$schema': 'http://json-schema.org/draft-07/schema#',
"definitions": {
"timeout": {
"type": "number",
"maximum": 60, # sanity
"exclusiveMinimum": 0
},
"database-credentials": {
"type": "object",
"properties": {
"hostname": {"type": "string"},
"dbname": {"type": "string"},
"username": {"type": "string"},
"password": {"type": "string"}
'definitions': {
'timeout': {
'type': 'number',
'maximum': 60, # sanity
'exclusiveMinimum': 0
},
'database-credentials': {
'type': 'object',
'properties': {
'hostname': {'type': 'string'},
'dbname': {'type': 'string'},
'username': {'type': 'string'},
'password': {'type': 'string'}
},
"required": ["hostname", "dbname", "username", "password"],
"additionalProperties": False
},
"ssh-credentials": {
"type": "object",
"properties": {
"username": {"type": "string"},
"private-key": {"type": "string"},
"known-hosts": {"type": "string"}
'required': ['hostname', 'dbname', 'username', 'password'],
'additionalProperties': False
},
'ssh-credentials': {
'type': 'object',
'properties': {
'username': {'type': 'string'},
'private-key': {'type': 'string'},
'known-hosts': {'type': 'string'}
},
"required": ["private-key", "known-hosts"],
"additionalProperties": False
},
"ims": {
"type": "object",
"properties": {
"api": {"type": "string"},
"username": {"type": "string"},
"password": {"type": "string"}
'required': ['private-key', 'known-hosts'],
'additionalProperties': False
},
'ims': {
'type': 'object',
'properties': {
'api': {'type': 'string'},
'username': {'type': 'string'},
'password': {'type': 'string'}
},
"required": ["api", "username", "password"],
"additionalProperties": False
},
"otrs-export": {
"type": "object",
"properties": {
"username": {"type": "string"},
"private-key": {"type": "string"},
"known-hosts": {"type": "string"},
"destination": {"type": "string"}
'required': ['api', 'username', 'password'],
'additionalProperties': False
},
'otrs-export': {
'type': 'object',
'properties': {
'username': {'type': 'string'},
'private-key': {'type': 'string'},
'known-hosts': {'type': 'string'},
'destination': {'type': 'string'}
},
"required": [
"username",
"private-key",
"known-hosts",
"destination"
'required': [
'username',
'private-key',
'known-hosts',
'destination'
],
"additionalProperties": False
},
"redis-credentials": {
"type": "object",
"properties": {
"hostname": {"type": "string"},
"port": {"type": "integer"},
"celery-db-index": {"type": "integer"},
"socket_timeout": {"$ref": "#/definitions/timeout"}
'additionalProperties': False
},
'redis-credentials': {
'type': 'object',
'properties': {
'hostname': {'type': 'string'},
'port': {'type': 'integer'},
'celery-db-index': {'type': 'integer'},
'socket_timeout': {'$ref': '#/definitions/timeout'}
},
'required': ['hostname', 'port'],
'additionalProperties': False
},
'redis-sentinel-config': {
'type': 'object',
'properties': {
'hostname': {'type': 'string'},
'port': {'type': 'integer'},
'celery-db-index': {'type': 'integer'},
'name': {'type': 'string'},
'redis_socket_timeout': {'$ref': '#/definitions/timeout'},
'sentinel_socket_timeout': {'$ref': '#/definitions/timeout'}
},
"required": ["hostname", "port"],
"additionalProperties": False
},
"redis-sentinel-config": {
"type": "object",
"properties": {
"hostname": {"type": "string"},
"port": {"type": "integer"},
"celery-db-index": {"type": "integer"},
"name": {"type": "string"},
"redis_socket_timeout": {"$ref": "#/definitions/timeout"},
"sentinel_socket_timeout": {"$ref": "#/definitions/timeout"}
'required': ['hostname', 'port', 'name'],
'additionalProperties': False
},
'interface-address': {
'type': 'object',
'properties': {
'address': {'type': 'string'},
'network': {'type': 'string'},
'interface': {'type': 'string'},
'router': {'type': 'string'}
},
"required": ["hostname", "port", "name"],
"additionalProperties": False
},
"interface-address": {
"type": "object",
"properties": {
"address": {"type": "string"},
"network": {"type": "string"},
"interface": {"type": "string"},
"router": {"type": "string"}
'required': ['address', 'network', 'interface', 'router'],
'additionalProperties': False
},
'oid': {
'type': 'string',
'pattern': r'^(\d+\.)*\d+$'
},
'gws-direct-counters': {
'type': 'object',
'properties': {
'discards_in': {'$ref': '#/definitions/oid'},
'discards_out': {'$ref': '#/definitions/oid'},
'errors_in': {'$ref': '#/definitions/oid'},
'errors_out': {'$ref': '#/definitions/oid'},
'traffic_in': {'$ref': '#/definitions/oid'},
'traffic_out': {'$ref': '#/definitions/oid'},
},
"required": ["address", "network", "interface", "router"],
"additionalProperties": False
}
'additionalProperties': False
},
'gws-direct-interface': {
'type': 'object',
'properties': {
'tag': {'type': 'string'},
'counters': {'$ref': '#/definitions/gws-direct-counters'}
},
'required': ['tag', 'counters'],
'additionalProperties': False
},
'gws-direct-host': {
'type': 'object',
'properties': {
'hostname': {'type': 'string'},
'community': {'type': 'string'},
'interfaces': {
'type': 'array',
'items': {'$ref': '#/definitions/gws-direct-interface'},
'minItems': 1
}
},
'required': ['hostname', 'community', 'interfaces'],
'additionalProperties': False
},
'gws-direct-nren-isp': {
'type': 'object',
'properties': {
'nren': {'type': 'string'},
'isp': {
'type': 'string',
'enum': ['Cogent', 'Telia', 'Century Link']
},
'hosts': {
'type': 'array',
'items': {'$ref': '#/definitions/gws-direct-host'},
'minItems': 1
}
},
'required': ['nren', 'isp', 'hosts'],
'additionalProperties': False
},
'gws-direct': {
'type': 'array',
'items': {'$ref': '#/definitions/gws-direct-nren-isp'}
},
},
"type": "object",
"properties": {
"ops-db": {"$ref": "#/definitions/database-credentials"},
"ssh": {"$ref": "#/definitions/ssh-credentials"},
"redis": {"$ref": "#/definitions/redis-credentials"},
"sentinel": {"$ref": "#/definitions/redis-sentinel-config"},
"ims": {"$ref": "#/definitions/ims"},
"otrs-export": {"$ref": "#/definitions/otrs-export"},
"redis-databases": {
"type": "array",
"minItems": 1,
"items": {"type": "integer"}
},
"managed-routers": {"type": "string"},
"lab-routers": {
"type": "array",
"items": {"type": "string"}
},
"unmanaged-interfaces": {
"type": "array",
"items": {"$ref": "#/definitions/interface-address"}
}
'type': 'object',
'properties': {
'ops-db': {'$ref': '#/definitions/database-credentials'},
'ssh': {'$ref': '#/definitions/ssh-credentials'},
'redis': {'$ref': '#/definitions/redis-credentials'},
'sentinel': {'$ref': '#/definitions/redis-sentinel-config'},
'ims': {'$ref': '#/definitions/ims'},
'otrs-export': {'$ref': '#/definitions/otrs-export'},
'redis-databases': {
'type': 'array',
'minItems': 1,
'items': {'type': 'integer'}
},
'managed-routers': {'type': 'string'},
'lab-routers': {
'type': 'array',
'items': {'type': 'string'}
},
'unmanaged-interfaces': {
'type': 'array',
'items': {'$ref': '#/definitions/interface-address'}
},
'gws-direct': {'$ref': '#/definitions/gws-direct'}
},
"oneOf": [
'oneOf': [
{
"required": [
"ops-db",
"ssh",
"redis",
"redis-databases",
"otrs-export",
"ims",
"managed-routers"]
'required': [
'ops-db',
'ssh',
'redis',
'redis-databases',
'otrs-export',
'ims',
'managed-routers',
'gws-direct']
},
{
"required": [
"ops-db",
"ssh",
"sentinel",
"redis-databases",
"otrs-export",
"ims",
"managed-routers"]
'required': [
'ops-db',
'ssh',
'sentinel',
'redis-databases',
'otrs-export',
'ims',
'managed-routers',
'gws-direct']
}
],
"additionalProperties": False
'additionalProperties': False
}
......
"""
Classifier Endpoints
=========================
These endpoints are intended for use by Dashboard V3.
.. contents:: :local:
/classifier/peer-info
---------------------
.. autofunction:: inventory_provider.routes.classifier.get_bgp_peer_info
/classifier/juniper-link-info
-----------------------------
.. autofunction:: inventory_provider.routes.classifier.get_juniper_link_info
/classifier/infinera-lambda-info
--------------------------------
.. autofunction:: inventory_provider.routes.classifier.get_infinera_lambda_info
/classifier/infinera-fiberlink-info
------------------------------------
.. autofunction::
inventory_provider.routes.classifier.get_fiberlink_trap_metadata
/classifier/coriant-info
------------------------
.. autofunction:: inventory_provider.routes.classifier.get_coriant_info
/classifier/mtc-interface-info
--------------------------------
.. autofunction:: inventory_provider.routes.classifier.get_mtc_interface_info
"""
import ipaddress
import json
import logging
......
"""
Data Endpoints
=========================
These endpoints are temporary and will be removed.
.. contents:: :local:
/data/routers
---------------------------------
.. autofunction:: inventory_provider.routes.data.routers
/data/interfaces
---------------------------------
.. autofunction:: inventory_provider.routes.data.router_interfaces
/data/pop
---------------------------------
.. autofunction:: inventory_provider.routes.data.equipment_location
"""
import json
import logging
import re
......
"""
Jobs Endpoints
=========================
These endpoints are used for monitoring running jobs.
.. contents:: :local:
/jobs/update
---------------------------------
.. autofunction:: inventory_provider.routes.jobs.update
/jobs/check-task-status
---------------------------------
.. autofunction:: inventory_provider.routes.jobs.check_task_status
/jobs/log
---------------------------------
.. autofunction:: inventory_provider.routes.jobs.load_task_log
"""
import json
import logging
......
"""
LG Support Endpoints
=========================
These endpoints are intended for use by LG.
/lg/interfaces
---------------------------------
.. autofunction:: inventory_provider.routes.lg.routers
"""
import json
import logging
import re
from flask import Blueprint, jsonify, Response, request
from flask import Blueprint, Response, request
from inventory_provider.routes import common
from inventory_provider.routes.common import _ignore_cache_or_retrieve
......@@ -81,6 +94,10 @@ def routers(access):
.. asjson::
inventory_provider.routes.lg.LG_ROUTERS_SCHEMA
"equipment name" will be the IMS node name, but if this
doesn't end in ".geant.org" or ".geant.net", will be appended
with "geant.net"
:param access: one of `public` or `all`
:return:
"""
......@@ -99,22 +116,30 @@ def routers(access):
return router['type'] == 'CORE'
def _routers():
i = 0
for k in redis.scan_iter('ims:lg:*'):
for k in redis.scan_iter('ims:lg:*', count=1000):
rtr = redis.get(k.decode('utf-8')).decode('utf-8')
rtr = json.loads(rtr)
i += 1
if _visible(rtr):
yield rtr
hostname = rtr['equipment name'].lower()
if ' ' in hostname:
logger.warning(
'skipping LG router with ws in hostname: {hostname}')
continue
if not re.match(r'.*\.geant\.(net|org)$', hostname):
hostname = f'{hostname}.geant.net'
rtr['equipment name'] = hostname
yield rtr
cache_key = f'classifier-cache:ims-lg:{access}'
result = _ignore_cache_or_retrieve(request, cache_key, redis)
if not result:
result = list(_routers())
# cache this data for the next call
redis.set(cache_key, json.dumps(result).encode('utf-8'))
result = list(filter(_visible, _routers()))
if result:
result = json.dumps(result)
# cache this data for the next call
redis.set(cache_key, result)
if not result:
return Response(
......@@ -122,4 +147,4 @@ def routers(access):
status=404,
mimetype="text/html")
return jsonify(result)
return Response(result, mimetype="application/json")
"""
LnetD support
=========================
This endpoint is intended for use with LnetD
.. contents:: :local:
/LnetD/interfaces</hostname>
---------------------------------
.. autofunction:: inventory_provider.routes.lnetd.interfaces
"""
import json
import logging
import re
......
"""
MSR Support Endpoints
=========================
These endpoints are intended for use by MSR.
.. contents:: :local:
/msr/access-services
---------------------------------
.. autofunction:: inventory_provider.routes.msr.access_services
/msr/bgp/logical-systems
-------------------------------------
.. autofunction:: inventory_provider.routes.msr.get_logical_systems
/msr/bgp/logical-system-peerings</name>
------------------------------------------
.. autofunction:: inventory_provider.routes.msr.logical_system_peerings
/msr/bgp/groups
-------------------------------------
.. autofunction:: inventory_provider.routes.msr.get_peering_groups
/msr/bgp/group-peerings</name>
-------------------------------------
.. autofunction:: inventory_provider.routes.msr.bgp_group_peerings
/msr/bgp/routing-instances
-------------------------------------
.. autofunction:: inventory_provider.routes.msr.get_peering_routing_instances
/msr/bgp/routing-instance-peeringns</name>
--------------------------------------------
.. autofunction:: inventory_provider.routes.msr.bgp_routing_instance_peerings
helpers
-------------------------------------
.. autofunction:: inventory_provider.routes.msr._handle_peering_group_list_request
.. autofunction:: inventory_provider.routes.msr._handle_peering_group_request
""" # noqa E501
import itertools
import json
......
"""
BRIAN support Endpoints
=========================
These endpoints are intended for use by BRIAN.
.. contents:: :local:
/poller/interfaces</hostname>
---------------------------------
.. autofunction:: inventory_provider.routes.poller.interfaces
/poller/speeds</hostname>
---------------------------------
.. autofunction:: inventory_provider.routes.poller.interface_speeds
/poller/eumetsat-multicast
---------------------------------
.. autofunction:: inventory_provider.routes.poller.eumetsat_multicast
/poller/gws/direct
---------------------------------
.. autofunction:: inventory_provider.routes.poller.gws_direct
"""
import json
import logging
import re
......@@ -117,6 +149,59 @@ MULTICAST_SUBSCRIPTION_LIST_SCHEMA = {
'items': {'$ref': '#/definitions/subscription'}
}
GWS_DIRECT_DATA_SCHEMA = {
'$schema': 'http://json-schema.org/draft-07/schema#',
'definitions': {
'oid': {
'type': 'string',
'pattern': r'^(\d+\.)*\d+$'
},
'counter': {
'type': 'object',
'properties': {
'field': {
'enum': [
'discards_in',
'discards_out',
'errors_in',
'errors_out',
'traffic_in',
'traffic_out'
]
},
'oid': {'$ref': '#/definitions/oid'},
'community': {'type': 'string'}
},
'required': ['field', 'oid', 'community'],
'additionalProperties': False
},
'interface-counters': {
'type': 'object',
'properties': {
'nren': {'type': 'string'},
'isp': {
'type': 'string',
'enum': ['Cogent', 'Telia', 'Century Link']
},
'hostname': {'type': 'string'},
'tag': {'type': 'string'},
'counters': {
'type': 'array',
'items': {'$ref': '#/definitions/counter'},
'minItems': 1
}
},
'required': [
'nren', 'isp', 'hostname', 'tag', 'counters'],
'additionalProperties': False
}
},
'type': 'array',
'items': {'$ref': '#/definitions/interface-counters'}
}
@routes.after_request
def after_request(resp):
......@@ -522,3 +607,58 @@ def eumetsat_multicast(hostname=None):
r.set(cache_key, result.encode('utf-8'))
return Response(result, mimetype="application/json")
@routes.route("/gws/direct", methods=['GET', 'POST'])
@common.require_accepts_json
def gws_direct():
"""
Handler for `/poller/gws/direct` which returns required for polling
customer equipment counters for ISP connetions.
The response is a list of nren/isp/counter structures that must be
polled.
.. asjson::
inventory_provider.routes.poller.GWS_DIRECT_DATA_SCHEMA
WARNING: interface tags in the `gws-direct` section of the config data
should be unique for each nren/isp/hostname combination. i.e. if there
are multiple community strings in use for a particular host, then please
keep the interface tags unique.
:return:
"""
cache_key = 'classifier-cache:gws-direct'
r = common.get_current_redis()
result = r.get(cache_key)
if result:
result = result.decode('utf-8')
else:
def _interfaces():
config_params = current_app.config['INVENTORY_PROVIDER_CONFIG']
for nren_isp in config_params['gws-direct']:
for host in nren_isp['hosts']:
for ifc in host['interfaces']:
yield {
'nren': nren_isp['nren'],
'isp': nren_isp['isp'],
'hostname': host['hostname'],
'tag': ifc['tag'],
'counters': [
{
'field': k,
'oid': v,
'community': host['community']
} for k, v in ifc['counters'].items()]
}
result = json.dumps(list(_interfaces()))
# cache this data for the next call
r.set(cache_key, result.encode('utf-8'))
return Response(result, mimetype="application/json")
......@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name='inventory-provider',
version="0.65",
version="0.66",
author='GEANT',
author_email='swd@geant.org',
description='Dashboard inventory provider',
......
......@@ -67,9 +67,13 @@ def data_config_filename():
"interface": "ZZZ/9/a/x:0.123",
"router": "another.bogus.host.name"
}
]
],
'gws-direct': {}
}
with open(os.path.join(TEST_DATA_DIRNAME, 'gws-direct.json')) as gws:
config['gws-direct'] = json.loads(gws.read())
f.write(json.dumps(config).encode('utf-8'))
f.flush()
yield f.name
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment