# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from flask import Flask, request from YangValidator import YangValidator app = Flask(__name__) yang_validator = YangValidator('etsi-qkd-sdn-node', ['etsi-qkd-node-types']) nodes = { '10.0.2.10:11111': {'node': { 'qkdn_id': '00000001-0000-0000-0000-000000000000', }, 'qkdn_capabilities': { }, 'qkd_applications': { 'qkd_app': [ { 'app_id': '00000001-0001-0000-0000-000000000000', 'client_app_id': [], 'app_statistics': { 'statistics': [] }, 'app_qos': { }, 'backing_qkdl_id': [] } ] }, 'qkd_interfaces': { 'qkd_interface': [ { 'qkdi_id': '100', 'qkdi_att_point': { }, 'qkdi_capabilities': { } }, { 'qkdi_id': '101', 'qkdi_att_point': { 'device':'10.0.2.10', 'port':'1001' }, 'qkdi_capabilities': { } } ] }, 'qkd_links': { 'qkd_link': [ ] } }, '10.0.2.10:22222': {'node': { 'qkdn_id': '00000002-0000-0000-0000-000000000000', }, 'qkdn_capabilities': { }, 'qkd_applications': { 'qkd_app': [ { 'app_id': '00000002-0001-0000-0000-000000000000', 'client_app_id': [], 'app_statistics': { 'statistics': [] }, 'app_qos': { }, 'backing_qkdl_id': [] } ] }, 'qkd_interfaces': { 'qkd_interface': [ { 'qkdi_id': '200', 'qkdi_att_point': { }, 'qkdi_capabilities': { } }, { 'qkdi_id': '201', 'qkdi_att_point': { 'device':'10.0.2.10', 'port':'2001' }, 'qkdi_capabilities': { } }, { 'qkdi_id': '202', 'qkdi_att_point': { 'device':'10.0.2.10', 'port':'2002' }, 'qkdi_capabilities': { } } ] }, 'qkd_links': { 'qkd_link': [ ] } }, '10.0.2.10:33333': {'node': { 'qkdn_id': '00000003-0000-0000-0000-000000000000', }, 'qkdn_capabilities': { }, 'qkd_applications': { 'qkd_app': [ { 'app_id': '00000003-0001-0000-0000-000000000000', 'client_app_id': [], 'app_statistics': { 'statistics': [] }, 'app_qos': { }, 'backing_qkdl_id': [] } ] }, 'qkd_interfaces': { 'qkd_interface': [ { 'qkdi_id': '300', 'qkdi_att_point': { }, 'qkdi_capabilities': { } }, { 'qkdi_id': '301', 'qkdi_att_point': { 'device':'10.0.2.10', 'port':'3001' }, 'qkdi_capabilities': { } } ] }, 'qkd_links': { 'qkd_link': [ ] } } } def get_side_effect(url): steps = url.lstrip('https://').lstrip('http://').rstrip('/') ip_port, _, _, header, *steps = steps.split('/') header_splitted = header.split(':') module = header_splitted[0] assert(module == 'etsi-qkd-sdn-node') tree = {'qkd_node': nodes[ip_port]['node'].copy()} if len(header_splitted) == 1 or not header_splitted[1]: value = nodes[ip_port].copy() value.pop('node') tree['qkd_node'].update(value) return tree, tree root = header_splitted[1] assert(root == 'qkd_node') if not steps: return tree, tree endpoint, *steps = steps value = nodes[ip_port][endpoint] if not steps: return_value = {endpoint:value} tree['qkd_node'].update(return_value) return return_value, tree ''' element, *steps = steps container, key = element.split('=') # value = value[container][key] if not steps: return_value['qkd_node'][endpoint] = [value] return return_value ''' raise Exception('Url too long') def edit(from_dict, to_dict, create): for key, value in from_dict.items(): if isinstance(value, dict): if key not in to_dict and create: to_dict[key] = {} edit(from_dict[key], to_dict[key], create) elif isinstance(value, list): to_dict[key].extend(value) else: to_dict[key] = value def edit_side_effect(url, json, create): steps = url.lstrip('https://').lstrip('http://').rstrip('/') ip_port, _, _, header, *steps = steps.split('/') module, root = header.split(':') assert(module == 'etsi-qkd-sdn-node') assert(root == 'qkd_node') if not steps: edit(json, nodes[ip_port]['node']) return endpoint, *steps = steps if not steps: edit(json[endpoint], nodes[ip_port][endpoint], create) return ''' element, *steps = steps container, key = element.split('=') if not steps: if key not in nodes[ip_port][endpoint][container] and create: nodes[ip_port][endpoint][container][key] = {} edit(json, nodes[ip_port][endpoint][container][key], create) return 0 ''' raise Exception('Url too long') @app.get('/', defaults={'path': ''}) @app.get("/<string:path>") @app.get('/<path:path>') def get(path): msg, msg_validate = get_side_effect(request.base_url) print(msg_validate) yang_validator.parse_to_dict(msg_validate) return msg @app.post('/', defaults={'path': ''}) @app.post("/<string:path>") @app.post('/<path:path>') def post(path): success = True reason = '' try: edit_side_effect(request.base_url, request.json, True) except Exception as e: reason = str(e) success = False return {'success': success, 'reason': reason} @app.route('/', defaults={'path': ''}, methods=['PUT', 'PATCH']) @app.route("/<string:path>", methods=['PUT', 'PATCH']) @app.route('/<path:path>', methods=['PUT', 'PATCH']) def patch(path): success = True reason = '' try: edit_side_effect(request.base_url, request.json, False) except Exception as e: reason = str(e) success = False return {'success': success, 'reason': reason} # import json # from mock import requests # import pyangbind.lib.pybindJSON as enc # from pyangbind.lib.serialise import pybindJSONDecoder as dec # from yang.sbi.qkd.templates.etsi_qkd_sdn_node import etsi_qkd_sdn_node # module = etsi_qkd_sdn_node() # url = 'https://1.1.1.1/restconf/data/etsi-qkd-sdn-node:' # # Get node all info # z = requests.get(url).json() # var = dec.load_json(z, None, None, obj=module) # print(enc.dumps(var)) # Reset module variable because it is already filled # module = etsi_qkd_sdn_node() # # Get node basic info # node = module.qkd_node # z = requests.get(url + 'qkd_node').json() # var = dec.load_json(z, None, None, obj=node) # print(enc.dumps(var)) # # Get all apps # apps = node.qkd_applications # z = requests.get(url + 'qkd_node/qkd_applications').json() # var = dec.load_json(z, None, None, obj=apps) # print(enc.dumps(var)) # # Edit app 0 # app = apps.qkd_app['00000000-0001-0000-0000-000000000000'] # app.client_app_id = 'id_0' # requests.put(url + 'qkd_node/qkd_applications/qkd_app=00000000-0001-0000-0000-000000000000', json=json.loads(enc.dumps(app))) # # Create app 1 # app = apps.qkd_app.add('00000000-0001-0000-0000-000000000001') # requests.post(url + 'qkd_node/qkd_applications/qkd_app=00000000-0001-0000-0000-000000000001', json=json.loads(enc.dumps(app))) # # Get all apps # apps = node.qkd_applications # z = requests.get(url + 'qkd_node/qkd_applications').json() # var = dec.load_json(z, None, None, obj=apps) # print(enc.dumps(var))