Skip to content
Snippets Groups Projects
Commit 97831d60 authored by Erik Reid's avatar Erik Reid
Browse files

more general, but less strict peer list schema

also handle test errors caused by removing space filter
parent 125fb8b3
No related branches found
No related tags found
No related merge requests found
...@@ -109,28 +109,29 @@ UNIT_SCHEMA = """<?xml version="1.1" encoding="UTF-8" ?> ...@@ -109,28 +109,29 @@ UNIT_SCHEMA = """<?xml version="1.1" encoding="UTF-8" ?>
</xs:schema> </xs:schema>
""" # noqa: E501 """ # noqa: E501
PEERING_LIST_SCHEMA = { # PEERING_LIST_SCHEMA = {
"$schema": "http://json-schema.org/draft-07/schema#", # "$schema": "http://json-schema.org/draft-07/schema#",
"definitions": { # "definitions": {
"peering": { # "peering": {
"type": "object", # "type": "object",
"properties": { # "properties": {
"group": {"type": "string"}, # "group": {"type": "string"},
"description": {"type": "string"}, # "description": {"type": "string"},
"address": {"type": "string"}, # "address": {"type": "string"},
"remote-asn": {"type": "integer"}, # "remote-asn": {"type": "integer"},
"local-asn": {"type": "integer"}, # "local-asn": {"type": "integer"},
"instance": {"type": "string"}, # "instance": {"type": "string"},
"logical-system": {"type": "string"}, # "logical-system": {"type": "string"},
}, # "hostname": {"type": "string"}
# lots of internal peerings - so maybe no explicit asn's # },
"required": ["group", "address"], # # lots of internal peerings - so maybe no explicit asn's
"additionalProperties": False # "required": ["group", "address", "hostname"],
} # "additionalProperties": False
}, # }
"type": "array", # },
"items": {"$ref": "#/definitions/peering"} # "type": "array",
} # "items": {"$ref": "#/definitions/peering"}
# }
class NetconfHandlingError(Exception): class NetconfHandlingError(Exception):
......
...@@ -169,15 +169,16 @@ def bgp_configs(hostname): ...@@ -169,15 +169,16 @@ def bgp_configs(hostname):
status=404, status=404,
mimetype="text/html") mimetype="text/html")
routes = list(juniper.all_bgp_peers( peers = list(juniper.all_bgp_peers(
etree.XML(netconf_string.decode('utf-8')))) etree.XML(netconf_string.decode('utf-8'))))
if not routes:
if not peers:
return Response( return Response(
response="no interfaces found for '%s'" % hostname, response="no interfaces found for '%s'" % hostname,
status=404, status=404,
mimetype="text/html") mimetype="text/html")
return jsonify(routes) return jsonify(peers)
@routes.route("snmp/<hostname>", methods=['GET', 'POST']) @routes.route("snmp/<hostname>", methods=['GET', 'POST'])
......
...@@ -56,6 +56,12 @@ def test_snmp_refresh_peerings(mocked_worker_module, router): ...@@ -56,6 +56,12 @@ def test_snmp_refresh_peerings(mocked_worker_module, router):
def test_reload_router_config(mocked_worker_module, router, mocker): def test_reload_router_config(mocked_worker_module, router, mocker):
if router.startswith('qfx'):
# test env hack (router doesn't have snmp acl for us)
mocker.patch('inventory_provider.juniper.snmp_community_string') \
.return_value = 'blah'
saved_data = {} saved_data = {}
for key in ('netconf:' + router, 'snmp-interfaces:' + router): for key in ('netconf:' + router, 'snmp-interfaces:' + router):
saved_data[key] = backend_db().pop(key) saved_data[key] = backend_db().pop(key)
......
import copy
import json import json
import pytest import pytest
import jsonschema import jsonschema
from inventory_provider.juniper import PEERING_LIST_SCHEMA from inventory_provider.routes import msr
DEFAULT_REQUEST_HEADERS = { DEFAULT_REQUEST_HEADERS = {
"Content-type": "application/json", "Content-type": "application/json",
...@@ -76,10 +77,12 @@ def test_snmp_ids(router, client): ...@@ -76,10 +77,12 @@ def test_snmp_ids(router, client):
def test_router_bgp_routes(router, client): def test_router_bgp_routes(router, client):
ROUTERS_WITHOUT_PEERING_DATA = [ def _no_peering_data_expected(h):
'mx2.bru.be.geant.net' if h == 'mx2.bru.be.geant.net':
] return None
if router in ROUTERS_WITHOUT_PEERING_DATA: return h.startswith('qfx')
if _no_peering_data_expected(router):
pytest.skip('%s is not expected to have bgp peers' % router) pytest.skip('%s is not expected to have bgp peers' % router)
return return
...@@ -87,7 +90,11 @@ def test_router_bgp_routes(router, client): ...@@ -87,7 +90,11 @@ def test_router_bgp_routes(router, client):
"/testing/bgp/" + router, "/testing/bgp/" + router,
headers=DEFAULT_REQUEST_HEADERS) headers=DEFAULT_REQUEST_HEADERS)
internal_peering_list_schema = copy.deepcopy(msr.PEERING_LIST_SCHEMA)
internal_peering_list_schema[
'definitions']['peering-instance']['required'].remove('hostname')
assert rv.status_code == 200 assert rv.status_code == 200
response = json.loads(rv.data.decode("utf-8")) response = json.loads(rv.data.decode("utf-8"))
jsonschema.validate(response, PEERING_LIST_SCHEMA) jsonschema.validate(response, internal_peering_list_schema)
assert response # at least shouldn't be empty assert response # at least shouldn't be empty
import copy
import ipaddress import ipaddress
import jsonschema import jsonschema
import pytest import pytest
from inventory_provider import juniper from inventory_provider import juniper
from inventory_provider.routes import msr
def test_interface_list(netconf_doc): def test_interface_list(netconf_doc):
...@@ -39,6 +41,10 @@ def test_interface_list(netconf_doc): ...@@ -39,6 +41,10 @@ def test_interface_list(netconf_doc):
def test_bgp_peering_data(netconf_doc): def test_bgp_peering_data(netconf_doc):
internal_peering_list_schema = copy.deepcopy(msr.PEERING_LIST_SCHEMA)
internal_peering_list_schema[
'definitions']['peering-instance']['required'].remove('hostname')
active_peers = set() active_peers = set()
inactive_peers = set() inactive_peers = set()
for neighbor in netconf_doc.xpath('//group/neighbor'): for neighbor in netconf_doc.xpath('//group/neighbor'):
...@@ -58,7 +64,7 @@ def test_bgp_peering_data(netconf_doc): ...@@ -58,7 +64,7 @@ def test_bgp_peering_data(netconf_doc):
pytest.skip('no peerings configured for this router') pytest.skip('no peerings configured for this router')
peerings = list(juniper.all_bgp_peers(netconf_doc)) peerings = list(juniper.all_bgp_peers(netconf_doc))
jsonschema.validate(peerings, juniper.PEERING_LIST_SCHEMA) jsonschema.validate(peerings, internal_peering_list_schema)
assert peerings # there's always at least one assert peerings # there's always at least one
# confirm the addresses are in canonical (exploded) form # confirm the addresses are in canonical (exploded) form
...@@ -81,7 +87,9 @@ def test_bgp_peering_data(netconf_doc): ...@@ -81,7 +87,9 @@ def test_bgp_peering_data(netconf_doc):
f'{inactive_peers & returned_addresses}') f'{inactive_peers & returned_addresses}')
def test_snmp_community_string(mocked_netifaces, netconf_doc): def test_snmp_community_string(mocked_netifaces, router, netconf_doc):
if router.startswith('qfx'):
pytest.skip(f'no snmp community string expected for {router}')
assert juniper.snmp_community_string(netconf_doc) == '0pBiFbD' assert juniper.snmp_community_string(netconf_doc) == '0pBiFbD'
......
""" """
tests of a few worker utilities tests of a few worker utilities
""" """
import copy
import ipaddress import ipaddress
import json import json
import re import re
...@@ -11,7 +12,6 @@ from inventory_provider.tasks import worker ...@@ -11,7 +12,6 @@ from inventory_provider.tasks import worker
from inventory_provider.tasks import common from inventory_provider.tasks import common
from inventory_provider.routes import msr from inventory_provider.routes import msr
def backend_db(): def backend_db():
return common._get_redis({ return common._get_redis({
'redis': { 'redis': {
...@@ -92,72 +92,99 @@ def test_build_juniper_peering_db(mocked_worker_module): ...@@ -92,72 +92,99 @@ def test_build_juniper_peering_db(mocked_worker_module):
# same as inventory_provider.juniper.PEERING_LIST_SCHEMA, # same as inventory_provider.juniper.PEERING_LIST_SCHEMA,
# but with "hostname" in every returned record # but with "hostname" in every returned record
LOGICAL_SYSTEM_PEERING_SCHEMA = { # LOGICAL_SYSTEM_PEERING_SCHEMA = {
"type": "object", # "type": "object",
"properties": { # "properties": {
"logical-system": {"type": "string"}, # "logical-system": {"type": "string"},
"group": {"type": "string"}, # "group": {"type": "string"},
"description": {"type": "string"}, # "description": {"type": "string"},
"address": {"type": "string"}, # "address": {"type": "string"},
"remote-asn": {"type": "integer"}, # "remote-asn": {"type": "integer"},
"local-asn": {"type": "integer"}, # "local-asn": {"type": "integer"},
"hostname": {"type": "string"} # "hostname": {"type": "string"}
}, # },
# local/remote-asn and/or description are not always present, # # local/remote-asn and/or description are not always present,
# just based on empirical tests - not a problem # # just based on empirical tests - not a problem
"required": ["logical-system", "group", "address"], # "required": ["logical-system", "group", "address"],
"additionalProperties": False # "additionalProperties": False
} # }
#
TOP_LEVEL_PEERING_SCHEMA = { # TOP_LEVEL_PEERING_SCHEMA = {
"type": "object", # "type": "object",
"properties": { # "properties": {
"group": {"type": "string"}, # "group": {"type": "string"},
"description": {"type": "string"}, # "description": {"type": "string"},
"address": {"type": "string"}, # "address": {"type": "string"},
"remote-asn": {"type": "integer"}, # "remote-asn": {"type": "integer"},
"local-asn": {"type": "integer"}, # "local-asn": {"type": "integer"},
"hostname": {"type": "string"} # "hostname": {"type": "string"}
}, # },
# lots of internal peerings - so maybe no explicit asn's # # lots of internal peerings - so maybe no explicit asn's
"required": ["group", "address"], # "required": ["group", "address"],
"additionalProperties": False # "additionalProperties": False
} # }
#
INSTANCE_PEERING = { # INSTANCE_PEERING = {
"type": "object", # "type": "object",
"properties": { # "properties": {
"instance": {"type": "string"}, # "instance": {"type": "string"},
"group": {"type": "string"}, # "group": {"type": "string"},
"description": {"type": "string"}, # "description": {"type": "string"},
"address": {"type": "string"}, # "address": {"type": "string"},
"remote-asn": {"type": "integer"}, # "remote-asn": {"type": "integer"},
"local-asn": {"type": "integer"}, # "local-asn": {"type": "integer"},
"hostname": {"type": "string"} # "hostname": {"type": "string"}
}, # },
# description and-or local-asn is not always present, # # description and-or local-asn is not always present,
# just based on empirical tests - not a problem # # just based on empirical tests - not a problem
"required": ["instance", "group", "address", "remote-asn"], # "required": ["instance", "group", "address", "remote-asn"],
"additionalProperties": False # "additionalProperties": False
} # }
#
DETAILED_PEERING_LIST_SCHEMA = { # DETAILED_PEERING_LIST_SCHEMA = {
"$schema": "http://json-schema.org/draft-07/schema#", # "$schema": "http://json-schema.org/draft-07/schema#",
"definitions": { # "definitions": {
"top-level-peering": TOP_LEVEL_PEERING_SCHEMA, # "top-level-peering": TOP_LEVEL_PEERING_SCHEMA,
"instance-peering": INSTANCE_PEERING, # "instance-peering": INSTANCE_PEERING,
"logical-system-peering": LOGICAL_SYSTEM_PEERING_SCHEMA, # "logical-system-peering": LOGICAL_SYSTEM_PEERING_SCHEMA,
"peering": { # "peering": {
"oneOf": [ # "oneOf": [
{"$ref": "#/definitions/top-level-peering"}, # {"$ref": "#/definitions/top-level-peering"},
{"$ref": "#/definitions/instance-peering"}, # {"$ref": "#/definitions/instance-peering"},
{"$ref": "#/definitions/logical-system-peering"} # {"$ref": "#/definitions/logical-system-peering"}
] # ]
} # }
}, # },
"type": "array", # "type": "array",
"items": {"$ref": "#/definitions/peering"} # "items": {"$ref": "#/definitions/peering"}
} # }
# PEERING_LIST_SCHEMA = {
# "$schema": "http://json-schema.org/draft-07/schema#",
# "definitions": {
# "peering": {
# "type": "object",
# "properties": {
# "group": {"type": "string"},
# "description": {"type": "string"},
# "address": {"type": "string"},
# "remote-asn": {"type": "integer"},
# "local-asn": {"type": "integer"},
# "instance": {"type": "string"},
# "logical-system": {"type": "string"},
# },
# # lots of internal peerings - so maybe no explicit asn's
# "required": ["group", "address"],
# "additionalProperties": False
# }
# },
# "type": "array",
# "items": {"$ref": "#/definitions/peering"}
# }
logical_system_peering_list_schema = copy.deepcopy(msr.PEERING_LIST_SCHEMA)
logical_system_peering_list_schema[
'definitions']['peering-instance']['required'].append('logical-system')
db = backend_db() # also forces initialization db = backend_db() # also forces initialization
...@@ -194,16 +221,15 @@ def test_build_juniper_peering_db(mocked_worker_module): ...@@ -194,16 +221,15 @@ def test_build_juniper_peering_db(mocked_worker_module):
assert address == canonical assert address == canonical
continue continue
jsonschema.validate(value, DETAILED_PEERING_LIST_SCHEMA) jsonschema.validate(value, msr.PEERING_LIST_SCHEMA)
if 'logical-system:' in key: if 'logical-system:' in key:
jsonschema.validate(value, msr.PEERING_LIST_SCHEMA) jsonschema.validate(value, logical_system_peering_list_schema)
m = re.match(r'.*logical-system:(.+)$', key) m = re.match(r'.*logical-system:(.+)$', key)
assert all(p['logical-system'] == m.group(1) for p in value) assert all(p['logical-system'] == m.group(1) for p in value)
found_logical_system = True found_logical_system = True
if 'group:' in key: if 'group:' in key:
jsonschema.validate(value, msr.PEERING_LIST_SCHEMA)
m = re.match(r'.*group:(.+)$', key) m = re.match(r'.*group:(.+)$', key)
assert all(p['group'] == m.group(1) for p in value) assert all(p['group'] == m.group(1) for p in value)
found_group = True found_group = True
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment