mirror of
				https://github.com/Telecominfraproject/oopt-gnpy.git
				synced 2025-10-31 10:07:57 +00:00 
			
		
		
		
	 fa6b8c87e4
			
		
	
	fa6b8c87e4
	
	
	
		
			
			in order to be compliant with yang Signed-off-by: EstherLerouzic <esther.lerouzic@orange.com> Change-Id: Ifa6ab93025b18a5a678b625e42e3d351499c69d7
		
			
				
	
	
		
			173 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python3
 | |
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| '''
 | |
| gnpy.tools.rest_example
 | |
| =======================
 | |
| 
 | |
| GNPy as a rest API example
 | |
| '''
 | |
| 
 | |
| import json
 | |
| import logging
 | |
| import os
 | |
| import re
 | |
| from logging.handlers import RotatingFileHandler
 | |
| from pathlib import Path
 | |
| 
 | |
| import werkzeug
 | |
| from flask import Flask, request
 | |
| from numpy import mean
 | |
| from werkzeug.exceptions import InternalServerError
 | |
| 
 | |
| import gnpy.core.ansi_escapes as ansi_escapes
 | |
| import gnpy.core.exceptions as exceptions
 | |
| from gnpy.core.network import build_network
 | |
| from gnpy.core.utils import lin2db, automatic_nch
 | |
| from gnpy.tools.json_io import requests_from_json, disjunctions_from_json, _equipment_from_json, network_from_json
 | |
| from gnpy.topology.request import (ResultElement, compute_path_dsjctn, requests_aggregation,
 | |
|                                    correct_json_route_list,
 | |
|                                    deduplicate_disjunctions, compute_path_with_disjunction)
 | |
| from gnpy.topology.spectrum_assignment import build_oms_list, pth_assign_spectrum
 | |
| 
 | |
| _logger = logging.getLogger(__name__)
 | |
| _examples_dir = Path(__file__).parent.parent / 'example-data'
 | |
| _reaesc = re.compile(r'\x1b[^m]*m')
 | |
| app = Flask(__name__)
 | |
| 
 | |
| 
 | |
| @app.route('/api/v1/path-computation', methods=['POST'])
 | |
| def compute_path():
 | |
|     data = request.json
 | |
|     service = data['gnpy-api:service']
 | |
|     topology = data['gnpy-api:topology']
 | |
|     equipment = _equipment_from_json(data['gnpy-api:equipment'],
 | |
|                                      os.path.join(_examples_dir, 'std_medium_gain_advanced_config.json'))
 | |
|     network = network_from_json(topology, equipment)
 | |
| 
 | |
|     propagatedpths, reversed_propagatedpths, rqs = path_requests_run(service, network, equipment)
 | |
|     # Generate the output
 | |
|     result = []
 | |
|     # assumes that list of rqs and list of propgatedpths have same order
 | |
|     for i, pth in enumerate(propagatedpths):
 | |
|         result.append(ResultElement(rqs[i], pth, reversed_propagatedpths[i]))
 | |
|     return {"result": {"response": [n.json for n in result]}}, 201
 | |
| 
 | |
| 
 | |
| @app.route('/api/v1/status', methods=['GET'])
 | |
| def api_status():
 | |
|     return {"version": "v1", "status": "ok"}, 200
 | |
| 
 | |
| 
 | |
| def _init_logger():
 | |
|     handler = RotatingFileHandler('api.log', maxBytes=1024 * 1024, backupCount=5, encoding='utf-8')
 | |
|     ch = logging.StreamHandler()
 | |
|     logging.basicConfig(level=logging.INFO, handlers=[handler, ch],
 | |
|                         format="%(asctime)s %(levelname)s %(name)s(%(lineno)s) [%(threadName)s - %(thread)d] - %("
 | |
|                                "message)s")
 | |
| 
 | |
| 
 | |
| def path_requests_run(service, network, equipment):
 | |
|     # Build the network once using the default power defined in SI in eqpt config
 | |
|     # TODO power density: db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by
 | |
|     # spacing, f_min and f_max
 | |
|     p_db = equipment['SI']['default'].power_dbm
 | |
| 
 | |
|     p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,
 | |
|                                              equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
 | |
|     build_network(network, equipment, p_db, p_total_db)
 | |
|     oms_list = build_oms_list(network, equipment)
 | |
|     rqs = requests_from_json(service, equipment)
 | |
| 
 | |
|     # check that request ids are unique. Non unique ids, may
 | |
|     # mess the computation: better to stop the computation
 | |
|     all_ids = [r.request_id for r in rqs]
 | |
|     if len(all_ids) != len(set(all_ids)):
 | |
|         for item in list(set(all_ids)):
 | |
|             all_ids.remove(item)
 | |
|         msg = f'Requests id {all_ids} are not unique'
 | |
|         _logger.critical(msg)
 | |
|         raise ValueError('Requests id ' + all_ids + ' are not unique')
 | |
|     rqs = correct_json_route_list(network, rqs)
 | |
| 
 | |
|     # pths = compute_path(network, equipment, rqs)
 | |
|     dsjn = disjunctions_from_json(service)
 | |
| 
 | |
|     # need to warn or correct in case of wrong disjunction form
 | |
|     # disjunction must not be repeated with same or different ids
 | |
|     dsjn = deduplicate_disjunctions(dsjn)
 | |
| 
 | |
|     rqs, dsjn = requests_aggregation(rqs, dsjn)
 | |
|     # TODO export novel set of aggregated demands in a json file
 | |
| 
 | |
|     _logger.info(f'{ansi_escapes.blue}The following services have been requested:{ansi_escapes.reset}' + str(rqs))
 | |
| 
 | |
|     _logger.info(f'{ansi_escapes.blue}Computing all paths with constraints{ansi_escapes.reset}')
 | |
|     pths = compute_path_dsjctn(network, equipment, rqs, dsjn)
 | |
| 
 | |
|     _logger.info(f'{ansi_escapes.blue}Propagating on selected path{ansi_escapes.reset}')
 | |
|     propagatedpths, reversed_pths, reversed_propagatedpths = compute_path_with_disjunction(network, equipment, rqs,
 | |
|                                                                                            pths)
 | |
|     # Note that deepcopy used in compute_path_with_disjunction returns
 | |
|     # a list of nodes which are not belonging to network (they are copies of the node objects).
 | |
|     # so there can not be propagation on these nodes.
 | |
| 
 | |
|     pth_assign_spectrum(pths, rqs, oms_list, reversed_pths)
 | |
|     return propagatedpths, reversed_propagatedpths, rqs
 | |
| 
 | |
| 
 | |
| def common_error_handler(exception):
 | |
|     """
 | |
| 
 | |
|     :type exception: Exception
 | |
| 
 | |
|     """
 | |
|     status_code = 500
 | |
|     if not isinstance(exception, werkzeug.exceptions.HTTPException):
 | |
|         exception = werkzeug.exceptions.InternalServerError()
 | |
|         exception.description = "Something went wrong on our side."
 | |
| 
 | |
|     response = {
 | |
|         'message': exception.name,
 | |
|         'description': exception.description,
 | |
|         'code': exception.code
 | |
|     }
 | |
| 
 | |
|     return werkzeug.Response(response=json.dumps(response), status=status_code, mimetype='application/json')
 | |
| 
 | |
| 
 | |
| def bad_request_handler(exception):
 | |
|     response = {
 | |
|         'message': 'bad request',
 | |
|         'description': _reaesc.sub('', str(exception)),
 | |
|         'code': 400
 | |
|     }
 | |
|     return werkzeug.Response(response=json.dumps(response), status=400, mimetype='application/json')
 | |
| 
 | |
| 
 | |
| def _init_app():
 | |
|     app.register_error_handler(KeyError, bad_request_handler)
 | |
|     app.register_error_handler(TypeError, bad_request_handler)
 | |
|     app.register_error_handler(ValueError, bad_request_handler)
 | |
|     app.register_error_handler(exceptions.ConfigurationError, bad_request_handler)
 | |
|     app.register_error_handler(exceptions.DisjunctionError, bad_request_handler)
 | |
|     app.register_error_handler(exceptions.EquipmentConfigError, bad_request_handler)
 | |
|     app.register_error_handler(exceptions.NetworkTopologyError, bad_request_handler)
 | |
|     app.register_error_handler(exceptions.ServiceError, bad_request_handler)
 | |
|     app.register_error_handler(exceptions.SpectrumError, bad_request_handler)
 | |
|     app.register_error_handler(exceptions.ParametersError, bad_request_handler)
 | |
|     app.register_error_handler(AssertionError, bad_request_handler)
 | |
|     app.register_error_handler(InternalServerError, common_error_handler)
 | |
|     for error_code in werkzeug.exceptions.default_exceptions:
 | |
|         app.register_error_handler(error_code, common_error_handler)
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     _init_logger()
 | |
|     _init_app()
 | |
|     app.run(host='0.0.0.0', port=8080)
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     main()
 |