Loading src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py 0 → 100644 +150 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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. # Mock MicroWave SDN controller # ----------------------------- # REST server implementing minimal support for: # - IETF YANG data model for Network Topology # Ref: https://www.rfc-editor.org/rfc/rfc8345.html # - IETF YANG data model for Transport Network Client Signals # Ref: https://www.ietf.org/archive/id/draft-ietf-ccamp-client-signal-yang-07.html # Ref: https://blog.miguelgrinberg.com/post/running-your-flask-application-over-https # Ref: https://blog.miguelgrinberg.com/post/designing-a-restful-api-using-flask-restful import functools, logging, sys, time from flask import Flask, abort, jsonify, make_response, request from flask_restful import Api, Resource BIND_ADDRESS = '0.0.0.0' BIND_PORT = 8443 BASE_URL = '/nmswebs/restconf/data' STR_ENDPOINT = 'https://{:s}:{:s}{:s}'.format(str(BIND_ADDRESS), str(BIND_PORT), str(BASE_URL)) LOG_LEVEL = logging.DEBUG NETWORK_NODES = [ {'node-id': '192.168.27.139', 'ietf-network-topology:termination-point': [ {'tp-id': '1', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '2', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '3', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '4', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '5', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '6', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '10', 'ietf-te-topology:te': {'name': 'antena' }}, ]}, {'node-id': '192.168.27.140', 'ietf-network-topology:termination-point': [ {'tp-id': '1', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '2', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '3', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '4', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '5', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '6', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '10', 'ietf-te-topology:te': {'name': 'antena' }}, ]}, {'node-id': '192.168.27.141', 'ietf-network-topology:termination-point': [ {'tp-id': '1', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '2', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '3', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '4', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '5', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '6', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '10', 'ietf-te-topology:te': {'name': 'antena' }}, ]}, {'node-id': '192.168.27.142', 'ietf-network-topology:termination-point': [ {'tp-id': '1', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '2', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '3', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '4', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '5', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '6', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '10', 'ietf-te-topology:te': {'name': 'antena' }}, ]} ] NETWORK_LINKS = [ { 'link-id' : '192.168.27.139:10--192.168.27.140:10', 'source' : {'source-node': '192.168.27.139', 'source-tp': '10'}, 'destination': {'dest-node' : '192.168.27.140', 'dest-tp' : '10'}, }, { 'link-id' : '192.168.27.141:10--192.168.27.142:10', 'source' : {'source-node': '192.168.27.141', 'source-tp': '10'}, 'destination': {'dest-node' : '192.168.27.142', 'dest-tp' : '10'}, } ] NETWORK_SERVICES = {} logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") LOGGER = logging.getLogger(__name__) logging.getLogger('werkzeug').setLevel(logging.WARNING) def log_request(logger : logging.Logger, response): timestamp = time.strftime('[%Y-%b-%d %H:%M]') logger.info('%s %s %s %s %s', timestamp, request.remote_addr, request.method, request.full_path, response.status) return response class Health(Resource): def get(self): return make_response(jsonify({}), 200) class Network(Resource): def get(self, network_uuid : str): if network_uuid != 'SIAE-ETH-TOPOLOGY': abort(400) network = {'node': NETWORK_NODES, 'ietf-network-topology:link': NETWORK_LINKS} return make_response(jsonify({'ietf-network:network': network}), 200) class Services(Resource): def get(self): services = [service for service in NETWORK_SERVICES.values()] return make_response(jsonify({'ietf-eth-tran-service:etht-svc': {'etht-svc-instances': services}}), 200) def post(self): json_request = request.get_json() if not json_request: abort(400) if not isinstance(json_request, dict): abort(400) if 'etht-svc-instances' not in json_request: abort(400) json_services = json_request['etht-svc-instances'] if not isinstance(json_services, list): abort(400) if len(json_services) != 1: abort(400) svc_data = json_services[0] etht_svc_name = svc_data['etht-svc-name'] NETWORK_SERVICES[etht_svc_name] = svc_data return make_response(jsonify({}), 201) class DelServices(Resource): def delete(self, service_uuid : str): NETWORK_SERVICES.pop(service_uuid, None) return make_response(jsonify({}), 204) def main(): LOGGER.info('Starting...') app = Flask(__name__) app.after_request(functools.partial(log_request, LOGGER)) api = Api(app, prefix=BASE_URL) api.add_resource(Health, '/ietf-network:networks') api.add_resource(Network, '/ietf-network:networks/network=<string:network_uuid>') api.add_resource(Services, '/ietf-eth-tran-service:etht-svc') api.add_resource(DelServices, '/ietf-eth-tran-service:etht-svc/etht-svc-instances=<string:service_uuid>') LOGGER.info('Listening on {:s}...'.format(str(STR_ENDPOINT))) app.run(debug=True, host=BIND_ADDRESS, port=BIND_PORT, ssl_context='adhoc') LOGGER.info('Bye') return 0 if __name__ == '__main__': sys.exit(main()) src/tests/tools/mock_ietf_actn_sdn_ctrl/README.md 0 → 100644 +53 −0 Original line number Diff line number Diff line # Mock IETF ACTN SDN Controller This REST server implements very basic support for the following YANG data models: - IETF YANG Data Model for Transport Network Client Signals (draft-ietf-ccamp-client-signal-yang-10) - Ref: https://datatracker.ietf.org/doc/draft-ietf-ccamp-client-signal-yang/ - IETF YANG Data Model for Traffic Engineering Tunnels, Label Switched Paths and Interfaces (draft-ietf-teas-yang-te-34) - Ref: https://datatracker.ietf.org/doc/draft-ietf-teas-yang-te/ The aim of this server is to enable testing the IetfActnDeviceDriver and the IetfActnServiceHandler. Follow the steps below to perform the test: ## 1. Deploy TeraFlowSDN controller and the scenario Deploy the test scenario "ietf_actn_deploy.sh": ```bash source src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/ietf_actn_deploy.sh ./deploy/all.sh ``` ## 2. Install requirements and run the Mock IETF ACTN SDN controller __NOTE__: if you run the Mock IETF ACTN SDN controller from the PyEnv used for developping on the TeraFlowSDN framework, all the requirements are already in place. Install them only if you execute it in a separate/standalone environment. Install the required dependencies as follows: ```bash pip install Flask==2.1.3 Flask-RESTful==0.3.9 ``` Run the Mock IETF ACTN SDN Controller as follows: ```bash python src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py ``` ## 3. Deploy the test descriptors Edit the descriptors to meet your environment specifications. Edit "network_descriptors.json" and change IP address and port of the IETF ACTN SDN controller of the "ACTN" device. - Set value of config rule "_connect/address" to the address of the host where the Mock IETF ACTN SDN controller is running (default="192.168.1.1"). - Set value of config rule "_connect/port" to the port where your Mock IETF ACTN SDN controller is listening on (default="8443"). Upload the "network_descriptors.json" through the TeraFlowSDN WebUI. - If not already selected, select Context(admin)/Topology(admin). - Check that a network topology with 4 routers + 1 IETF ACTN radio system are loaded. They should form 2 rings. Upload the "service_descriptor.json" through the TeraFlowSDN WebUI. - Check that 2 services have been created. - The "actn-svc" should have a connection and be supported by a sub-service. - The sub-service should also have a connection. - The R1, R3, and MW devices should have configuration rules established. # 4. Delete the IETF ACTN service Find the "mw-svc" on the WebUI, navigate to its details, and delete the service pressing the "Delete Service" button. The service, sub-service, and device configuration rules should be removed. src/tests/tools/mock_ietf_actn_sdn_ctrl/run.sh 0 → 100755 +16 −0 Original line number Diff line number Diff line #!/usr/bin/env bash # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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. python MockIetfActnSdnCtrl.py src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/ietf_actn_deploy.sh 0 → 100755 +36 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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. # Set the URL of your local Docker registry where the images will be uploaded to. export TFS_REGISTRY_IMAGE="http://localhost:32000/tfs/" # Set the list of components, separated by spaces, you want to build images for, and deploy. # Supported components are: # context device ztp policy service nbi monitoring webui # interdomain slice pathcomp dlt # dbscanserving opticalattackmitigator opticalattackdetector # l3_attackmitigator l3_centralizedattackdetector l3_distributedattackdetector export TFS_COMPONENTS="context device pathcomp service slice webui" # Set the tag you want to use for your images. export TFS_IMAGE_TAG="dev" # Set the name of the Kubernetes namespace to deploy to. export TFS_K8S_NAMESPACE="tfs" # Set additional manifest files to be applied after the deployment export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml" # Set the neew Grafana admin password export TFS_GRAFANA_PASSWORD="admin123+" src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/network_descriptors.json 0 → 100644 +117 −0 Original line number Diff line number Diff line { "contexts": [ { "context_id": {"context_uuid": {"uuid": "admin"}}, "topology_ids": [], "service_ids": [] } ], "topologies": [ { "topology_id": {"topology_uuid": {"uuid": "admin"}, "context_id": {"context_uuid": {"uuid": "admin"}}}, "device_ids": [], "link_ids": [] } ], "devices": [ { "device_id": {"device_uuid": {"uuid": "R1"}}, "device_type": "emu-packet-router", "device_drivers": [0], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ {"type": "copper", "uuid": "MW", "sample_types": []}, {"type": "copper", "uuid": "R2", "sample_types": []}, {"type": "copper", "uuid": "EXT", "sample_types": []} ]}}} ]} }, { "device_id": {"device_uuid": {"uuid": "R2"}}, "device_type": "emu-packet-router", "device_drivers": [0], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ {"type": "copper", "uuid": "MW", "sample_types": []}, {"type": "copper", "uuid": "R1", "sample_types": []}, {"type": "copper", "uuid": "EXT", "sample_types": []} ]}}} ]} }, { "device_id": {"device_uuid": {"uuid": "R3"}}, "device_type": "emu-packet-router", "device_drivers": [0], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ {"type": "copper", "uuid": "MW", "sample_types": []}, {"type": "copper", "uuid": "R4", "sample_types": []}, {"type": "copper", "uuid": "EXT", "sample_types": []} ]}}} ]} }, { "device_id": {"device_uuid": {"uuid": "R4"}}, "device_type": "emu-packet-router", "device_drivers": [0], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ {"type": "copper", "uuid": "MW", "sample_types": []}, {"type": "copper", "uuid": "R3", "sample_types": []}, {"type": "copper", "uuid": "EXT", "sample_types": []} ]}}} ]} }, { "device_id": {"device_uuid": {"uuid": "MW"}}, "device_type": "microwave-radio-system", "device_drivers": [4], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "192.168.1.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "8443"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"timeout": 120}}} ]} } ], "links": [ { "link_id": {"link_uuid": {"uuid": "R1/R2==R2/R1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "R2"}}, {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "R1"}} ] }, { "link_id": {"link_uuid": {"uuid": "R3/R4==R4/R3"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "R4"}}, {"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "R3"}} ] }, { "link_id": {"link_uuid": {"uuid": "R1/MW==MW/172.18.0.1:1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "MW"}}, {"device_id": {"device_uuid": {"uuid": "MW"}}, "endpoint_uuid": {"uuid": "172.18.0.1:1"}} ] }, { "link_id": {"link_uuid": {"uuid": "R2/MW==MW/172.18.0.2:1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "MW"}}, {"device_id": {"device_uuid": {"uuid": "MW"}}, "endpoint_uuid": {"uuid": "172.18.0.2:1"}} ] }, { "link_id": {"link_uuid": {"uuid": "R3/MW==MW/172.18.0.3:1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "MW"}}, {"device_id": {"device_uuid": {"uuid": "MW"}}, "endpoint_uuid": {"uuid": "172.18.0.3:1"}} ] }, { "link_id": {"link_uuid": {"uuid": "R4/MW==MW/172.18.0.4:1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "MW"}}, {"device_id": {"device_uuid": {"uuid": "MW"}}, "endpoint_uuid": {"uuid": "172.18.0.4:1"}} ] } ] } No newline at end of file Loading
src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py 0 → 100644 +150 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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. # Mock MicroWave SDN controller # ----------------------------- # REST server implementing minimal support for: # - IETF YANG data model for Network Topology # Ref: https://www.rfc-editor.org/rfc/rfc8345.html # - IETF YANG data model for Transport Network Client Signals # Ref: https://www.ietf.org/archive/id/draft-ietf-ccamp-client-signal-yang-07.html # Ref: https://blog.miguelgrinberg.com/post/running-your-flask-application-over-https # Ref: https://blog.miguelgrinberg.com/post/designing-a-restful-api-using-flask-restful import functools, logging, sys, time from flask import Flask, abort, jsonify, make_response, request from flask_restful import Api, Resource BIND_ADDRESS = '0.0.0.0' BIND_PORT = 8443 BASE_URL = '/nmswebs/restconf/data' STR_ENDPOINT = 'https://{:s}:{:s}{:s}'.format(str(BIND_ADDRESS), str(BIND_PORT), str(BASE_URL)) LOG_LEVEL = logging.DEBUG NETWORK_NODES = [ {'node-id': '192.168.27.139', 'ietf-network-topology:termination-point': [ {'tp-id': '1', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '2', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '3', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '4', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '5', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '6', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '10', 'ietf-te-topology:te': {'name': 'antena' }}, ]}, {'node-id': '192.168.27.140', 'ietf-network-topology:termination-point': [ {'tp-id': '1', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '2', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '3', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '4', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '5', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '6', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '10', 'ietf-te-topology:te': {'name': 'antena' }}, ]}, {'node-id': '192.168.27.141', 'ietf-network-topology:termination-point': [ {'tp-id': '1', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '2', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '3', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '4', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '5', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '6', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '10', 'ietf-te-topology:te': {'name': 'antena' }}, ]}, {'node-id': '192.168.27.142', 'ietf-network-topology:termination-point': [ {'tp-id': '1', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '2', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '3', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '4', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '5', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '6', 'ietf-te-topology:te': {'name': 'ethernet'}}, {'tp-id': '10', 'ietf-te-topology:te': {'name': 'antena' }}, ]} ] NETWORK_LINKS = [ { 'link-id' : '192.168.27.139:10--192.168.27.140:10', 'source' : {'source-node': '192.168.27.139', 'source-tp': '10'}, 'destination': {'dest-node' : '192.168.27.140', 'dest-tp' : '10'}, }, { 'link-id' : '192.168.27.141:10--192.168.27.142:10', 'source' : {'source-node': '192.168.27.141', 'source-tp': '10'}, 'destination': {'dest-node' : '192.168.27.142', 'dest-tp' : '10'}, } ] NETWORK_SERVICES = {} logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") LOGGER = logging.getLogger(__name__) logging.getLogger('werkzeug').setLevel(logging.WARNING) def log_request(logger : logging.Logger, response): timestamp = time.strftime('[%Y-%b-%d %H:%M]') logger.info('%s %s %s %s %s', timestamp, request.remote_addr, request.method, request.full_path, response.status) return response class Health(Resource): def get(self): return make_response(jsonify({}), 200) class Network(Resource): def get(self, network_uuid : str): if network_uuid != 'SIAE-ETH-TOPOLOGY': abort(400) network = {'node': NETWORK_NODES, 'ietf-network-topology:link': NETWORK_LINKS} return make_response(jsonify({'ietf-network:network': network}), 200) class Services(Resource): def get(self): services = [service for service in NETWORK_SERVICES.values()] return make_response(jsonify({'ietf-eth-tran-service:etht-svc': {'etht-svc-instances': services}}), 200) def post(self): json_request = request.get_json() if not json_request: abort(400) if not isinstance(json_request, dict): abort(400) if 'etht-svc-instances' not in json_request: abort(400) json_services = json_request['etht-svc-instances'] if not isinstance(json_services, list): abort(400) if len(json_services) != 1: abort(400) svc_data = json_services[0] etht_svc_name = svc_data['etht-svc-name'] NETWORK_SERVICES[etht_svc_name] = svc_data return make_response(jsonify({}), 201) class DelServices(Resource): def delete(self, service_uuid : str): NETWORK_SERVICES.pop(service_uuid, None) return make_response(jsonify({}), 204) def main(): LOGGER.info('Starting...') app = Flask(__name__) app.after_request(functools.partial(log_request, LOGGER)) api = Api(app, prefix=BASE_URL) api.add_resource(Health, '/ietf-network:networks') api.add_resource(Network, '/ietf-network:networks/network=<string:network_uuid>') api.add_resource(Services, '/ietf-eth-tran-service:etht-svc') api.add_resource(DelServices, '/ietf-eth-tran-service:etht-svc/etht-svc-instances=<string:service_uuid>') LOGGER.info('Listening on {:s}...'.format(str(STR_ENDPOINT))) app.run(debug=True, host=BIND_ADDRESS, port=BIND_PORT, ssl_context='adhoc') LOGGER.info('Bye') return 0 if __name__ == '__main__': sys.exit(main())
src/tests/tools/mock_ietf_actn_sdn_ctrl/README.md 0 → 100644 +53 −0 Original line number Diff line number Diff line # Mock IETF ACTN SDN Controller This REST server implements very basic support for the following YANG data models: - IETF YANG Data Model for Transport Network Client Signals (draft-ietf-ccamp-client-signal-yang-10) - Ref: https://datatracker.ietf.org/doc/draft-ietf-ccamp-client-signal-yang/ - IETF YANG Data Model for Traffic Engineering Tunnels, Label Switched Paths and Interfaces (draft-ietf-teas-yang-te-34) - Ref: https://datatracker.ietf.org/doc/draft-ietf-teas-yang-te/ The aim of this server is to enable testing the IetfActnDeviceDriver and the IetfActnServiceHandler. Follow the steps below to perform the test: ## 1. Deploy TeraFlowSDN controller and the scenario Deploy the test scenario "ietf_actn_deploy.sh": ```bash source src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/ietf_actn_deploy.sh ./deploy/all.sh ``` ## 2. Install requirements and run the Mock IETF ACTN SDN controller __NOTE__: if you run the Mock IETF ACTN SDN controller from the PyEnv used for developping on the TeraFlowSDN framework, all the requirements are already in place. Install them only if you execute it in a separate/standalone environment. Install the required dependencies as follows: ```bash pip install Flask==2.1.3 Flask-RESTful==0.3.9 ``` Run the Mock IETF ACTN SDN Controller as follows: ```bash python src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py ``` ## 3. Deploy the test descriptors Edit the descriptors to meet your environment specifications. Edit "network_descriptors.json" and change IP address and port of the IETF ACTN SDN controller of the "ACTN" device. - Set value of config rule "_connect/address" to the address of the host where the Mock IETF ACTN SDN controller is running (default="192.168.1.1"). - Set value of config rule "_connect/port" to the port where your Mock IETF ACTN SDN controller is listening on (default="8443"). Upload the "network_descriptors.json" through the TeraFlowSDN WebUI. - If not already selected, select Context(admin)/Topology(admin). - Check that a network topology with 4 routers + 1 IETF ACTN radio system are loaded. They should form 2 rings. Upload the "service_descriptor.json" through the TeraFlowSDN WebUI. - Check that 2 services have been created. - The "actn-svc" should have a connection and be supported by a sub-service. - The sub-service should also have a connection. - The R1, R3, and MW devices should have configuration rules established. # 4. Delete the IETF ACTN service Find the "mw-svc" on the WebUI, navigate to its details, and delete the service pressing the "Delete Service" button. The service, sub-service, and device configuration rules should be removed.
src/tests/tools/mock_ietf_actn_sdn_ctrl/run.sh 0 → 100755 +16 −0 Original line number Diff line number Diff line #!/usr/bin/env bash # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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. python MockIetfActnSdnCtrl.py
src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/ietf_actn_deploy.sh 0 → 100755 +36 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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. # Set the URL of your local Docker registry where the images will be uploaded to. export TFS_REGISTRY_IMAGE="http://localhost:32000/tfs/" # Set the list of components, separated by spaces, you want to build images for, and deploy. # Supported components are: # context device ztp policy service nbi monitoring webui # interdomain slice pathcomp dlt # dbscanserving opticalattackmitigator opticalattackdetector # l3_attackmitigator l3_centralizedattackdetector l3_distributedattackdetector export TFS_COMPONENTS="context device pathcomp service slice webui" # Set the tag you want to use for your images. export TFS_IMAGE_TAG="dev" # Set the name of the Kubernetes namespace to deploy to. export TFS_K8S_NAMESPACE="tfs" # Set additional manifest files to be applied after the deployment export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml" # Set the neew Grafana admin password export TFS_GRAFANA_PASSWORD="admin123+"
src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/network_descriptors.json 0 → 100644 +117 −0 Original line number Diff line number Diff line { "contexts": [ { "context_id": {"context_uuid": {"uuid": "admin"}}, "topology_ids": [], "service_ids": [] } ], "topologies": [ { "topology_id": {"topology_uuid": {"uuid": "admin"}, "context_id": {"context_uuid": {"uuid": "admin"}}}, "device_ids": [], "link_ids": [] } ], "devices": [ { "device_id": {"device_uuid": {"uuid": "R1"}}, "device_type": "emu-packet-router", "device_drivers": [0], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ {"type": "copper", "uuid": "MW", "sample_types": []}, {"type": "copper", "uuid": "R2", "sample_types": []}, {"type": "copper", "uuid": "EXT", "sample_types": []} ]}}} ]} }, { "device_id": {"device_uuid": {"uuid": "R2"}}, "device_type": "emu-packet-router", "device_drivers": [0], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ {"type": "copper", "uuid": "MW", "sample_types": []}, {"type": "copper", "uuid": "R1", "sample_types": []}, {"type": "copper", "uuid": "EXT", "sample_types": []} ]}}} ]} }, { "device_id": {"device_uuid": {"uuid": "R3"}}, "device_type": "emu-packet-router", "device_drivers": [0], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ {"type": "copper", "uuid": "MW", "sample_types": []}, {"type": "copper", "uuid": "R4", "sample_types": []}, {"type": "copper", "uuid": "EXT", "sample_types": []} ]}}} ]} }, { "device_id": {"device_uuid": {"uuid": "R4"}}, "device_type": "emu-packet-router", "device_drivers": [0], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ {"type": "copper", "uuid": "MW", "sample_types": []}, {"type": "copper", "uuid": "R3", "sample_types": []}, {"type": "copper", "uuid": "EXT", "sample_types": []} ]}}} ]} }, { "device_id": {"device_uuid": {"uuid": "MW"}}, "device_type": "microwave-radio-system", "device_drivers": [4], "device_operational_status": 2, "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "192.168.1.1"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "8443"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"timeout": 120}}} ]} } ], "links": [ { "link_id": {"link_uuid": {"uuid": "R1/R2==R2/R1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "R2"}}, {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "R1"}} ] }, { "link_id": {"link_uuid": {"uuid": "R3/R4==R4/R3"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "R4"}}, {"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "R3"}} ] }, { "link_id": {"link_uuid": {"uuid": "R1/MW==MW/172.18.0.1:1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "MW"}}, {"device_id": {"device_uuid": {"uuid": "MW"}}, "endpoint_uuid": {"uuid": "172.18.0.1:1"}} ] }, { "link_id": {"link_uuid": {"uuid": "R2/MW==MW/172.18.0.2:1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "MW"}}, {"device_id": {"device_uuid": {"uuid": "MW"}}, "endpoint_uuid": {"uuid": "172.18.0.2:1"}} ] }, { "link_id": {"link_uuid": {"uuid": "R3/MW==MW/172.18.0.3:1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "MW"}}, {"device_id": {"device_uuid": {"uuid": "MW"}}, "endpoint_uuid": {"uuid": "172.18.0.3:1"}} ] }, { "link_id": {"link_uuid": {"uuid": "R4/MW==MW/172.18.0.4:1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "MW"}}, {"device_id": {"device_uuid": {"uuid": "MW"}}, "endpoint_uuid": {"uuid": "172.18.0.4:1"}} ] } ] } No newline at end of file