diff --git a/inventory_provider/routes/msr.py b/inventory_provider/routes/msr.py index 1ae5c5d8b4dffd6e3df5ac47588302480631d304..4f81e71e057891947a7bbc313abe051a297e3fd0 100644 --- a/inventory_provider/routes/msr.py +++ b/inventory_provider/routes/msr.py @@ -140,7 +140,7 @@ PEERING_LIST_SCHEMA = { 'description': {'type': 'string'}, 'logical-system': {'type': 'string'}, 'group': {'type': 'string'}, - 'hostname': {'type': 'string'}, + 'hostname': {'type': 'string', 'format': 'hostname'}, 'remote-asn': {'type': 'integer'}, 'local-asn': {'type': 'integer'}, 'instance': {'type': 'string'} @@ -371,6 +371,17 @@ DOMAIN_TO_POP_MAPPING = { IP_SERVICES_LIST_SCHEMA = { '$schema': 'http://json-schema.org/draft-07/schema#', 'definitions': { + 'minimal-peering-schema': { + # cf. PEERING_LIST_SCHEMA + 'type': 'object', + 'properties': { + 'address': {'type': 'string'}, + 'group': {'type': 'string'}, + 'hostname': {'type': 'string', 'format': 'hostname'} + }, + 'required': ['address', 'group', 'hostname'], + 'additionalProperties': True + }, 'service': { 'type': 'object', 'properties': { @@ -398,9 +409,14 @@ IP_SERVICES_LIST_SCHEMA = { 'services': { 'type': 'array', 'items': {'$ref': '#/definitions/service'} + }, + 'peerings': { + 'type': 'array', + 'items': {'$ref': '#/definitions/minimal-peering-schema'} } }, - 'required': ['hostname', 'port', 'address', 'services'], + 'required': [ + 'hostname', 'port', 'address', 'services', 'peerings'], 'additionalProperties': False } }, @@ -1498,25 +1514,37 @@ def _load_ip_services(): } } - def _merged_result(): - for key, ifc in netconf_interfaces.items(): - _services = map( - _service_info, - ims_interface_services.get(key, [])) - _services = list(_dedupe(_services)) - - for address in ifc['ipv4'] + ifc['ipv6']: - try: - yield { - 'hostname': ifc['hostname'], - 'port': ifc['name'], - 'address': address, - 'services': _services - } - except TypeError: - raise - - yield from _merged_result() + # pre-compute remote ipaddress objects, and group to avoid duplicates + r = common.get_current_redis() + all_peerings = {} + for _remote in json.loads(r.get('juniper-peerings:all').decode('utf-8')): + remote_info = all_peerings.setdefault(_remote['address'], { + 'address': ipaddress.ip_address(_remote['address']), + 'info': [] + }) + remote_info['info'].append(_remote) + + def _remotes_in_network(ifc_address): + network = ipaddress.ip_interface(ifc_address).network + for _r in all_peerings.values(): + if _r['address'] in network: + yield from _r['info'] + + for key, ifc in netconf_interfaces.items(): + _services = map( + _service_info, + ims_interface_services.get(key, [])) + _services = list(_dedupe(_services)) + + for address in ifc['ipv4'] + ifc['ipv6']: + + yield { + 'hostname': ifc['hostname'], + 'port': ifc['name'], + 'address': address, + 'services': _services, + 'peerings': list(_remotes_in_network(address)) + } @routes.route('/ip-services', methods=['GET', 'POST']) diff --git a/test/test_msr_routes.py b/test/test_msr_routes.py index 15f8844d9e098b2fabd6a554a2788ce24754e851..80fef05fd235d194c90df84fde787c5f1168b05c 100644 --- a/test/test_msr_routes.py +++ b/test/test_msr_routes.py @@ -415,4 +415,6 @@ def test_ip_services(client): response_data = json.loads(rv.data.decode('utf-8')) jsonschema.validate(response_data, IP_SERVICES_LIST_SCHEMA) - assert response_data # test data is non-empty + # sanity that there are some non-trivial elements in test data + assert any(len(_x['peerings']) > 0 for _x in response_data) + assert any(len(_x['services']) > 0 for _x in response_data)