diff --git a/inventory_provider/routes/msr.py b/inventory_provider/routes/msr.py index 6fe5b0a544730129ab5ac97d565e600a54dd3ba9..ba7a70ba6ca27695bffdf9e5501b8a56f0b56440 100644 --- a/inventory_provider/routes/msr.py +++ b/inventory_provider/routes/msr.py @@ -172,6 +172,82 @@ PEERING_ADDRESS_SERVICES_LIST = { 'items': {'$ref': '#/definitions/address-service-info'} } +SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA = { + '$schema': 'http://json-schema.org/draft-07/schema#', + + 'definitions': { + 'v4-network': {'type': 'string'}, # TODO: can this be better? + 'v6-network': {'type': 'string'}, # TODO: can this be better? + 'ip-endpoint': { + 'type': 'object', + 'properties': { + 'hostname': {'type': 'string'}, + 'interface': {'type': 'string'}, + 'addresses': { + 'type': 'object', + 'properties': { + 'v4': {'$ref': '#/definitions/v4-network'}, + 'v6': {'$ref': '#/definitions/v6-network'} + }, + # 'required': ['v4', 'v6'], # TODO: always require both? + 'additionalProperties': False + } + }, + 'required': ['hostname', 'interface', 'addresses'], + 'additionalProperties': False + }, + 'optical-endpoint': { + 'type': 'object', + 'properties': { + 'equipment': {'type': 'string'}, + 'port': {'type': 'string'} + }, + 'required': ['equipment', 'port'], + 'additionalProperties': False + }, + 'ip-endpoints': { + 'type': 'array', + 'items': {'$ref': '#/definitions/ip-endpoint'}, + 'minItems': 1 + }, + 'optical-endpoints': { + 'type': 'array', + 'items': {'$ref': '#/definitions/optical-endpoint'}, + 'minItems': 1 + }, + + 'endpoints': { + 'oneOf': [ + {'$ref': '#/definitions/ip-endpoints'}, + {'$ref': '#/definitions/optical-endpoints'} + ] + }, + 'service': { + 'type': 'object', + 'properties': { + 'circuit_id': {'type': 'integer'}, + 'sid': {'type': 'string'}, + 'name': {'type': 'string'}, + 'speed': {'type': 'integer'}, + 'circuit_type': {'type': 'string'}, # TODO: remove this? + 'service_type': {'type': 'string'}, # TODO: enum? + 'project': {'type': 'string'}, # TODO: remove this? + 'customer': {'type': 'string'}, + 'endpoints': {'$ref': '#/definitions/endpoints'} + }, + 'required': [ + 'circuit_id', 'sid', 'name', 'speed', + # 'circuit_type', 'project', # TODO: keeping these?!? + 'service_type', 'customer', 'endpoints'], + 'additionalProperties': False + } + }, + + 'type': 'array', + 'items': {'$ref': '#/definitions/service'}, + 'minItems': 1 # otherwise the route should return 404 +} + @routes.after_request def after_request(resp): @@ -655,3 +731,80 @@ def get_peering_services(): mimetype="text/html") return Response(response, mimetype="application/json") + + +@routes.route('/services', methods=['GET', 'POST']) +@common.require_accepts_json +def get_system_correlation_services(): + """ + Handler for `/msr/services` + + cf. https://jira.software.geant.org/browse/POL1-530 + + The response will be formatted as follows: + + .. asjson:: + inventory_provider.routes.msr.SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA + + :return: + """ + + dummy_data = [ + { + 'circuit_id': 123, + 'sid': 'AABBCC', + 'name': 'BOGUS IP #1', + 'speed': 1 << 20, + 'service_type': 'GEANT IP', + 'customer': 'SURF', + 'endpoints': [ + { + 'hostname': 'mx1.ams.nl.geant.net', + 'interface': 'xe-0/0/1', + 'addresses': { + 'v4': '10.0.0.1/30', + 'v6': '2620:0000:1cff:dead:beee:0000:0000:02d9/127' + } + } + ] + }, + { + 'circuit_id': 234, + 'sid': 'DDEEFF', + 'name': 'BOGUS PLUS SERVICE', + 'speed': 1 << 20, + 'service_type': 'GEANT PLUS', + 'customer': 'SOMEBODY', + 'endpoints': [ + { + 'hostname': 'mx1.ams.nl.geant.net', + 'interface': 'xe-0/0/2', + 'addresses': { + 'v4': '10.0.1.1/30', + 'v6': '2620:0000:1cff:dead:beef:0000:0000:02d9/127' + } + }, + { + 'hostname': 'mx1.lon.uk.geant.net', + 'interface': 'xe-4/3/2', + 'addresses': { + 'v4': '10.0.1.2/30', + 'v6': '2620:0000:1cff:dead:beef:0000:0000:02da/127' + } + } + ] + }, + { + 'circuit_id': 123, + 'sid': 'GGHHIIJJ', + 'name': 'BOGUS LAMBDA SERVICE', + 'speed': 1 << 20, + 'service_type': 'GEANT LAMBDA', + 'customer': 'JISC', + 'endpoints': [ + {'equipment': 'LON01-DTNX10-1', 'port': 'B-2-T7-1'} + ] + } + ] + + return Response(json.dumps(dummy_data), mimetype="application/json") diff --git a/test/test_msr_routes.py b/test/test_msr_routes.py index ba10ce0fbe404a78c29985baf96179dc986cdf92..198864e68ae6613815f037bd8b8673e64fc1166d 100644 --- a/test/test_msr_routes.py +++ b/test/test_msr_routes.py @@ -5,14 +5,11 @@ import pytest from inventory_provider.routes.msr import PEERING_LIST_SCHEMA, \ PEERING_GROUP_LIST_SCHEMA, PEERING_ADDRESS_SERVICES_LIST, \ - _get_services_for_address + SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA, _get_services_for_address from inventory_provider.routes.poller import SERVICES_LIST_SCHEMA from inventory_provider.tasks.common import _get_redis - -DEFAULT_REQUEST_HEADERS = { - "Accept": ["application/json"] -} +DEFAULT_REQUEST_HEADERS = {'Accept': ['application/json']} def test_access_services(client): @@ -302,3 +299,14 @@ def test_peering_services_single_threaded(client): assert response_data # test data is non-empty jsonschema.validate(response_data, PEERING_ADDRESS_SERVICES_LIST) + + +def test_system_correlation_services(client): + rv = client.get( + '/msr/services', + headers=DEFAULT_REQUEST_HEADERS) + assert rv.status_code == 200 + assert rv.is_json + response_data = json.loads(rv.data.decode('utf-8')) + jsonschema.validate(response_data, SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA) + assert response_data # test data is non-empty