Loading deploy/tfs.sh +7 −7 Original line number Diff line number Diff line Loading @@ -212,24 +212,24 @@ for COMPONENT in $TFS_COMPONENTS; do BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}.log" if [ "$COMPONENT" == "ztp" ] || [ "$COMPONENT" == "policy" ]; then $DOCKER_BUILD -t "$COMPONENT:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/Dockerfile ./src/"$COMPONENT"/ > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/Dockerfile ./src/"$COMPONENT"/ > "$BUILD_LOG" elif [ "$COMPONENT" == "pathcomp" ]; then BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-frontend.log" $DOCKER_BUILD -t "$COMPONENT-frontend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/frontend/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT-frontend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/frontend/Dockerfile . > "$BUILD_LOG" BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-backend.log" $DOCKER_BUILD -t "$COMPONENT-backend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/backend/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT-backend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/backend/Dockerfile . > "$BUILD_LOG" # next command is redundant, but helpful to keep cache updated between rebuilds IMAGE_NAME="$COMPONENT-backend:$TFS_IMAGE_TAG-builder" $DOCKER_BUILD -t "$IMAGE_NAME" --target builder -f ./src/"$COMPONENT"/backend/Dockerfile . >> "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$IMAGE_NAME" --target builder -f ./src/"$COMPONENT"/backend/Dockerfile . >> "$BUILD_LOG" elif [ "$COMPONENT" == "dlt" ]; then BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-connector.log" $DOCKER_BUILD -t "$COMPONENT-connector:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/connector/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT-connector:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/connector/Dockerfile . > "$BUILD_LOG" BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-gateway.log" $DOCKER_BUILD -t "$COMPONENT-gateway:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/gateway/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT-gateway:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/gateway/Dockerfile . > "$BUILD_LOG" else $DOCKER_BUILD -t "$COMPONENT:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/Dockerfile . > "$BUILD_LOG" fi echo " Pushing Docker image to '$TFS_REGISTRY_IMAGES'..." Loading my_deploy.sh +4 −2 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/" # Set the list of components, separated by spaces, you want to build images for, and deploy. export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_generator" export TFS_COMPONENTS="context device pathcomp service slice nbi webui app" # export load_generator # Uncomment to activate Monitoring #export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" Loading Loading @@ -109,7 +111,7 @@ export CRDB_DEPLOY_MODE="single" export CRDB_DROP_DATABASE_IF_EXISTS="" # Disable flag for re-deploying CockroachDB from scratch. export CRDB_REDEPLOY="" export CRDB_REDEPLOY="YES" # ----- NATS ------------------------------------------------------------------- Loading src/common/DeviceTypes.py +1 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ class DeviceTypeEnum(Enum): PACKET_ROUTER = 'packet-router' PACKET_SWITCH = 'packet-switch' XR_CONSTELLATION = 'xr-constellation' QKD_NODE = 'qkd-node' # ETSI TeraFlowSDN controller TERAFLOWSDN_CONTROLLER = 'teraflowsdn' src/context/proto 0 → 120000 +1 −0 Original line number Diff line number Diff line ../../proto/src/python No newline at end of file src/device/service/driver_api/driver_api/qkd_api.py 0 → 100644 +246 −0 Original line number Diff line number Diff line import sys import os import grpc import json from flask import Flask, jsonify, request, abort from common.proto.context_pb2 import Empty, ContextId, TopologyId, Uuid from common.proto.context_pb2_grpc import ContextServiceStub from device.service.driver_api.DriverInstanceCache import DriverInstanceCache, get_driver from device.service.driver_api.DriverFactory import DriverFactory from device.service.driver_api.FilterFields import FilterFieldEnum from device.service.driver_api._Driver import _Driver from device.service.drivers.qkd.QKDDriver2 import QKDDriver app = Flask(__name__) # Add the directory containing the driver_api module to the system path sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))) # Initialize the DriverFactory and DriverInstanceCache drivers_list = [ (QKDDriver, [{'filter_field1': 'value1', 'filter_field2': 'value2'}]) ] driver_factory = DriverFactory(drivers_list) driver_instance_cache = DriverInstanceCache(driver_factory) def get_context_topology_info(): try: # Establish a gRPC channel channel = grpc.insecure_channel('10.152.183.77:1010') # Update with the correct IP and port stub = ContextServiceStub(channel) # Retrieve the context information context_list = stub.ListContexts(Empty()) contexts_info = [] for context in context_list.contexts: context_info = { 'context_id': context.context_id.context_uuid.uuid, 'context_name': context.name, 'topologies': [] } # Retrieve topology information for each context topology_list = stub.ListTopologies(context.context_id) for topology in topology_list.topologies: topology_info = { 'topology_id': topology.topology_id.topology_uuid.uuid, 'topology_name': topology.name, 'devices': [] } # Retrieve detailed topology information topology_details = stub.GetTopologyDetails(topology.topology_id) for device in topology_details.devices: device_info = { 'device_id': device.device_id.device_uuid.uuid, 'device_name': device.name, 'device_type': device.device_type, 'status': device.device_operational_status, 'drivers': [driver for driver in device.device_drivers], 'endpoints': [{ 'uuid': endpoint.endpoint_id.endpoint_uuid.uuid, 'name': endpoint.name, 'type': endpoint.endpoint_type, 'location': endpoint.endpoint_location } for endpoint in device.device_endpoints], 'configurations': [{ 'key': config.custom.resource_key, 'value': config.custom.resource_value } for config in device.device_config.config_rules], 'interfaces': [{ 'id': interface.qkdi_id, 'enabled': interface.enabled, 'name': interface.name, 'att_point': interface.qkdi_att_point, 'capabilities': interface.qkdi_capabilities } for interface in device.qkd_interfaces.qkd_interface], 'applications': [{ 'app_id': app.app_id, 'app_qos': app.app_qos, 'app_statistics': app.app_statistics, 'backing_qkdl_id': app.backing_qkdl_id, 'client_app_id': app.client_app_id } for app in device.qkd_applications.qkd_app] } topology_info['devices'].append(device_info) context_info['topologies'].append(topology_info) contexts_info.append(context_info) return contexts_info except grpc.RpcError as e: app.logger.error(f"gRPC error: {e}") abort(502, description=f"gRPC error: {e.details()}") except Exception as e: app.logger.error(f"Error retrieving context topology info: {e}") abort(500, description="Internal Server Error") def get_detailed_device_info(): try: context_info = get_context_topology_info() detailed_info = [] for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: detailed_info.append({ 'device_info': device, 'driver_info': get_device_driver_info(driver) }) return detailed_info except Exception as e: app.logger.error(f"Error retrieving detailed device info: {e}") abort(500, description="Internal Server Error") def get_driver_instance(device): device_uuid = device['device_id'] driver_filter_fields = { FilterFieldEnum.DEVICE_TYPE: device['device_type'], FilterFieldEnum.DRIVER: device['drivers'], } connect_rules = {config['key']: config['value'] for config in device['configurations']} address = connect_rules.get('_connect/address', '127.0.0.1') port = int(connect_rules.get('_connect/port', '0')) settings = json.loads(connect_rules.get('_connect/settings', '{}')) try: driver = driver_instance_cache.get( device_uuid, filter_fields=driver_filter_fields, address=address, port=port, settings=settings) if os.getenv('QKD_API_URL'): # Assume real QKD system if QKD_API_URL is set if not driver.Connect(): raise Exception("Failed to connect to real QKD system") else: driver.Connect() return driver except Exception as e: app.logger.error(f"Failed to get driver instance for device {device_uuid}: {e}") return None def get_device_driver_info(driver: _Driver): try: return { 'initial_config': driver.GetInitialConfig(), 'running_config': driver.GetConfig(), 'subscriptions': list(driver.GetState(blocking=False)) } except Exception as e: app.logger.error(f"Failed to retrieve driver information: {e}") return {'error': str(e)} @app.route('/qkd/devices', methods=['GET']) def retrieve_qkd_devices(): try: context_info = get_context_topology_info() return jsonify(context_info), 200 except Exception as e: app.logger.error(f"Error retrieving QKD devices: {e}") return jsonify({'error': 'Internal Server Error'}), 500 @app.route('/qkd/capabilities', methods=['GET']) def get_qkd_capabilities(): try: context_info = get_context_topology_info() for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: capabilities = driver.get_qkd_capabilities() return jsonify(capabilities), 200 abort(404, description="No capabilities found") except Exception as e: app.logger.error(f"Error retrieving QKD capabilities: {e}") return jsonify({'error': 'Internal Server Error'}), 500 @app.route('/qkd/interfaces', methods=['GET']) def get_qkd_interfaces(): try: context_info = get_context_topology_info() for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: interfaces = driver.get_qkd_interfaces() return jsonify(interfaces), 200 abort(404, description="No interfaces found") except Exception as e: app.logger.error(f"Error retrieving QKD interfaces: {e}") return jsonify({'error': 'Internal Server Error'}), 500 @app.route('/qkd/links', methods=['GET']) def get_qkd_links(): try: context_info = get_context_topology_info() for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: links = driver.get_qkd_links() return jsonify(links), 200 abort(404, description="No links found") except Exception as e: app.logger.error(f"Error retrieving QKD links: {e}") return jsonify({'error': 'Internal Server Error'}), 500 @app.route('/qkd/applications', methods=['GET']) def get_qkd_applications(): try: context_info = get_context_topology_info() for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: applications = driver.get_qkd_applications() return jsonify(applications), 200 abort(404, description="No applications found") except Exception as e: app.logger.error(f"Error retrieving QKD applications: {e}") return jsonify({'error': 'Internal Server Error'}), 500 if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000) Loading
deploy/tfs.sh +7 −7 Original line number Diff line number Diff line Loading @@ -212,24 +212,24 @@ for COMPONENT in $TFS_COMPONENTS; do BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}.log" if [ "$COMPONENT" == "ztp" ] || [ "$COMPONENT" == "policy" ]; then $DOCKER_BUILD -t "$COMPONENT:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/Dockerfile ./src/"$COMPONENT"/ > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/Dockerfile ./src/"$COMPONENT"/ > "$BUILD_LOG" elif [ "$COMPONENT" == "pathcomp" ]; then BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-frontend.log" $DOCKER_BUILD -t "$COMPONENT-frontend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/frontend/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT-frontend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/frontend/Dockerfile . > "$BUILD_LOG" BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-backend.log" $DOCKER_BUILD -t "$COMPONENT-backend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/backend/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT-backend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/backend/Dockerfile . > "$BUILD_LOG" # next command is redundant, but helpful to keep cache updated between rebuilds IMAGE_NAME="$COMPONENT-backend:$TFS_IMAGE_TAG-builder" $DOCKER_BUILD -t "$IMAGE_NAME" --target builder -f ./src/"$COMPONENT"/backend/Dockerfile . >> "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$IMAGE_NAME" --target builder -f ./src/"$COMPONENT"/backend/Dockerfile . >> "$BUILD_LOG" elif [ "$COMPONENT" == "dlt" ]; then BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-connector.log" $DOCKER_BUILD -t "$COMPONENT-connector:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/connector/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT-connector:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/connector/Dockerfile . > "$BUILD_LOG" BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-gateway.log" $DOCKER_BUILD -t "$COMPONENT-gateway:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/gateway/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT-gateway:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/gateway/Dockerfile . > "$BUILD_LOG" else $DOCKER_BUILD -t "$COMPONENT:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/Dockerfile . > "$BUILD_LOG" $DOCKER_BUILD --network=host -t "$COMPONENT:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/Dockerfile . > "$BUILD_LOG" fi echo " Pushing Docker image to '$TFS_REGISTRY_IMAGES'..." Loading
my_deploy.sh +4 −2 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/" # Set the list of components, separated by spaces, you want to build images for, and deploy. export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_generator" export TFS_COMPONENTS="context device pathcomp service slice nbi webui app" # export load_generator # Uncomment to activate Monitoring #export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" Loading Loading @@ -109,7 +111,7 @@ export CRDB_DEPLOY_MODE="single" export CRDB_DROP_DATABASE_IF_EXISTS="" # Disable flag for re-deploying CockroachDB from scratch. export CRDB_REDEPLOY="" export CRDB_REDEPLOY="YES" # ----- NATS ------------------------------------------------------------------- Loading
src/common/DeviceTypes.py +1 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ class DeviceTypeEnum(Enum): PACKET_ROUTER = 'packet-router' PACKET_SWITCH = 'packet-switch' XR_CONSTELLATION = 'xr-constellation' QKD_NODE = 'qkd-node' # ETSI TeraFlowSDN controller TERAFLOWSDN_CONTROLLER = 'teraflowsdn'
src/context/proto 0 → 120000 +1 −0 Original line number Diff line number Diff line ../../proto/src/python No newline at end of file
src/device/service/driver_api/driver_api/qkd_api.py 0 → 100644 +246 −0 Original line number Diff line number Diff line import sys import os import grpc import json from flask import Flask, jsonify, request, abort from common.proto.context_pb2 import Empty, ContextId, TopologyId, Uuid from common.proto.context_pb2_grpc import ContextServiceStub from device.service.driver_api.DriverInstanceCache import DriverInstanceCache, get_driver from device.service.driver_api.DriverFactory import DriverFactory from device.service.driver_api.FilterFields import FilterFieldEnum from device.service.driver_api._Driver import _Driver from device.service.drivers.qkd.QKDDriver2 import QKDDriver app = Flask(__name__) # Add the directory containing the driver_api module to the system path sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))) # Initialize the DriverFactory and DriverInstanceCache drivers_list = [ (QKDDriver, [{'filter_field1': 'value1', 'filter_field2': 'value2'}]) ] driver_factory = DriverFactory(drivers_list) driver_instance_cache = DriverInstanceCache(driver_factory) def get_context_topology_info(): try: # Establish a gRPC channel channel = grpc.insecure_channel('10.152.183.77:1010') # Update with the correct IP and port stub = ContextServiceStub(channel) # Retrieve the context information context_list = stub.ListContexts(Empty()) contexts_info = [] for context in context_list.contexts: context_info = { 'context_id': context.context_id.context_uuid.uuid, 'context_name': context.name, 'topologies': [] } # Retrieve topology information for each context topology_list = stub.ListTopologies(context.context_id) for topology in topology_list.topologies: topology_info = { 'topology_id': topology.topology_id.topology_uuid.uuid, 'topology_name': topology.name, 'devices': [] } # Retrieve detailed topology information topology_details = stub.GetTopologyDetails(topology.topology_id) for device in topology_details.devices: device_info = { 'device_id': device.device_id.device_uuid.uuid, 'device_name': device.name, 'device_type': device.device_type, 'status': device.device_operational_status, 'drivers': [driver for driver in device.device_drivers], 'endpoints': [{ 'uuid': endpoint.endpoint_id.endpoint_uuid.uuid, 'name': endpoint.name, 'type': endpoint.endpoint_type, 'location': endpoint.endpoint_location } for endpoint in device.device_endpoints], 'configurations': [{ 'key': config.custom.resource_key, 'value': config.custom.resource_value } for config in device.device_config.config_rules], 'interfaces': [{ 'id': interface.qkdi_id, 'enabled': interface.enabled, 'name': interface.name, 'att_point': interface.qkdi_att_point, 'capabilities': interface.qkdi_capabilities } for interface in device.qkd_interfaces.qkd_interface], 'applications': [{ 'app_id': app.app_id, 'app_qos': app.app_qos, 'app_statistics': app.app_statistics, 'backing_qkdl_id': app.backing_qkdl_id, 'client_app_id': app.client_app_id } for app in device.qkd_applications.qkd_app] } topology_info['devices'].append(device_info) context_info['topologies'].append(topology_info) contexts_info.append(context_info) return contexts_info except grpc.RpcError as e: app.logger.error(f"gRPC error: {e}") abort(502, description=f"gRPC error: {e.details()}") except Exception as e: app.logger.error(f"Error retrieving context topology info: {e}") abort(500, description="Internal Server Error") def get_detailed_device_info(): try: context_info = get_context_topology_info() detailed_info = [] for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: detailed_info.append({ 'device_info': device, 'driver_info': get_device_driver_info(driver) }) return detailed_info except Exception as e: app.logger.error(f"Error retrieving detailed device info: {e}") abort(500, description="Internal Server Error") def get_driver_instance(device): device_uuid = device['device_id'] driver_filter_fields = { FilterFieldEnum.DEVICE_TYPE: device['device_type'], FilterFieldEnum.DRIVER: device['drivers'], } connect_rules = {config['key']: config['value'] for config in device['configurations']} address = connect_rules.get('_connect/address', '127.0.0.1') port = int(connect_rules.get('_connect/port', '0')) settings = json.loads(connect_rules.get('_connect/settings', '{}')) try: driver = driver_instance_cache.get( device_uuid, filter_fields=driver_filter_fields, address=address, port=port, settings=settings) if os.getenv('QKD_API_URL'): # Assume real QKD system if QKD_API_URL is set if not driver.Connect(): raise Exception("Failed to connect to real QKD system") else: driver.Connect() return driver except Exception as e: app.logger.error(f"Failed to get driver instance for device {device_uuid}: {e}") return None def get_device_driver_info(driver: _Driver): try: return { 'initial_config': driver.GetInitialConfig(), 'running_config': driver.GetConfig(), 'subscriptions': list(driver.GetState(blocking=False)) } except Exception as e: app.logger.error(f"Failed to retrieve driver information: {e}") return {'error': str(e)} @app.route('/qkd/devices', methods=['GET']) def retrieve_qkd_devices(): try: context_info = get_context_topology_info() return jsonify(context_info), 200 except Exception as e: app.logger.error(f"Error retrieving QKD devices: {e}") return jsonify({'error': 'Internal Server Error'}), 500 @app.route('/qkd/capabilities', methods=['GET']) def get_qkd_capabilities(): try: context_info = get_context_topology_info() for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: capabilities = driver.get_qkd_capabilities() return jsonify(capabilities), 200 abort(404, description="No capabilities found") except Exception as e: app.logger.error(f"Error retrieving QKD capabilities: {e}") return jsonify({'error': 'Internal Server Error'}), 500 @app.route('/qkd/interfaces', methods=['GET']) def get_qkd_interfaces(): try: context_info = get_context_topology_info() for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: interfaces = driver.get_qkd_interfaces() return jsonify(interfaces), 200 abort(404, description="No interfaces found") except Exception as e: app.logger.error(f"Error retrieving QKD interfaces: {e}") return jsonify({'error': 'Internal Server Error'}), 500 @app.route('/qkd/links', methods=['GET']) def get_qkd_links(): try: context_info = get_context_topology_info() for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: links = driver.get_qkd_links() return jsonify(links), 200 abort(404, description="No links found") except Exception as e: app.logger.error(f"Error retrieving QKD links: {e}") return jsonify({'error': 'Internal Server Error'}), 500 @app.route('/qkd/applications', methods=['GET']) def get_qkd_applications(): try: context_info = get_context_topology_info() for context in context_info: if context['context_name'] == 'admin': for topology in context['topologies']: if topology['topology_name'] == 'admin': for device in topology['devices']: driver = get_driver_instance(device) if driver: applications = driver.get_qkd_applications() return jsonify(applications), 200 abort(404, description="No applications found") except Exception as e: app.logger.error(f"Error retrieving QKD applications: {e}") return jsonify({'error': 'Internal Server Error'}), 500 if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)