diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py b/src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py new file mode 100644 index 0000000000000000000000000000000000000000..c20dde1b9958fb92e4c6f026fbfe55f9ba348ba1 --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py @@ -0,0 +1,150 @@ +# 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()) diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/README.md b/src/tests/tools/mock_ietf_actn_sdn_ctrl/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a12ae907e792f98413903b6637738c392506be4a --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/README.md @@ -0,0 +1,53 @@ +# 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. diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/run.sh b/src/tests/tools/mock_ietf_actn_sdn_ctrl/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..2697e538ec69a99da4c0fae898748ff496b5d28f --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/run.sh @@ -0,0 +1,16 @@ +#!/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 diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/ietf_actn_deploy.sh b/src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/ietf_actn_deploy.sh new file mode 100755 index 0000000000000000000000000000000000000000..665d337c94b0d4ec1378b1c3fffaa637fe26cd8a --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/ietf_actn_deploy.sh @@ -0,0 +1,36 @@ +# 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+" diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/network_descriptors.json b/src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/network_descriptors.json new file mode 100644 index 0000000000000000000000000000000000000000..25fa940a49c07fb6708b6e6f303d0661ef1268c7 --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/network_descriptors.json @@ -0,0 +1,117 @@ +{ + "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 diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/service_descriptor.json b/src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/service_descriptor.json new file mode 100644 index 0000000000000000000000000000000000000000..2d4ed3eaf1834f24ba966fbcaac523ca9a3afb9a --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/service_descriptor.json @@ -0,0 +1,25 @@ +{ + "services": [ + { + "service_id": { + "context_id": {"context_uuid": {"uuid": "admin"}}, + "service_uuid": {"uuid": "mw-svc"} + }, + "service_type": 2, + "service_status": {"service_status": 1}, + "service_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "EXT"}}, + {"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "EXT"}} + ], + "service_constraints": [ + {"sla_capacity": {"capacity_gbps": 10.0}}, + {"sla_latency": {"e2e_latency_ms": 15.2}} + ], + "service_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "/settings", "resource_value": { + "vlan_id": 121 + }}} + ]} + } + ] +} diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/Dockerfile b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..70fc81e5408d49ae332132612d0f86c1d5901e38 --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/Dockerfile @@ -0,0 +1,35 @@ +# 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. + +FROM python:3.9-slim + +# Set Python to show logs as they occur +ENV PYTHONUNBUFFERED=0 + +# Get generic Python packages +RUN python3 -m pip install --upgrade pip +RUN python3 -m pip install --upgrade setuptools wheel +RUN python3 -m pip install --upgrade pip-tools + +# Create component sub-folders, and copy content +RUN mkdir -p /var/teraflow/mock_mw_sdn_ctrl +WORKDIR /var/teraflow/mock_mw_sdn_ctrl +COPY . . + +# Get specific Python packages +RUN pip-compile --quiet --output-file=requirements.txt requirements.in +RUN python3 -m pip install -r requirements.txt + +# Start the service +ENTRYPOINT ["python", "MockMWSdnCtrl.py"] diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/build.sh b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..4df315cec178cef13eaa059a739bc22efc011d4d --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +docker build -t mock-mw-sdn-ctrl:test -f Dockerfile . +docker tag mock-mw-sdn-ctrl:test localhost:32000/tfs/mock-mw-sdn-ctrl:test +docker push localhost:32000/tfs/mock-mw-sdn-ctrl:test diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/deploy.sh b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/deploy.sh new file mode 100755 index 0000000000000000000000000000000000000000..ded232e5c50f8cd5ed448ec0193f58c43626f4ad --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/deploy.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +kubectl delete namespace mocks +kubectl --namespace mocks apply -f mock-mw-sdn-ctrl.yaml diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/mock-mw-sdn-ctrl.yaml b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/mock-mw-sdn-ctrl.yaml new file mode 100644 index 0000000000000000000000000000000000000000..05b89f949e940ae55ad592b9cc0e82a6eea2e343 --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/mock-mw-sdn-ctrl.yaml @@ -0,0 +1,46 @@ +kind: Namespace +apiVersion: v1 +metadata: + name: mocks +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mock-mw-sdn-ctrl +spec: + selector: + matchLabels: + app: mock-mw-sdn-ctrl + replicas: 1 + template: + metadata: + labels: + app: mock-mw-sdn-ctrl + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: localhost:32000/tfs/mock-mw-sdn-ctrl:test + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8443 + resources: + requests: + cpu: 250m + memory: 512Mi + limits: + cpu: 700m + memory: 1024Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: mock-mw-sdn-ctrl +spec: + type: ClusterIP + selector: + app: mock-mw-sdn-ctrl + ports: + - name: https + port: 8443 + targetPort: 8443 diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/requirements.in b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/requirements.in new file mode 100644 index 0000000000000000000000000000000000000000..f4bc191062c8385b2eeb003832b284313305c795 --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ssl_not_working/requirements.in @@ -0,0 +1,21 @@ +# 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. + +cryptography==39.0.1 +pyopenssl==23.0.0 +Flask==2.1.3 +Flask-HTTPAuth==4.5.0 +Flask-RESTful==0.3.9 +jsonschema==4.4.0 +requests==2.27.1 diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/test_ietf_actn.py b/src/tests/tools/mock_ietf_actn_sdn_ctrl/test_ietf_actn.py new file mode 100644 index 0000000000000000000000000000000000000000..0329d30ad234398200c0fe29aac46f72f5a2e924 --- /dev/null +++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/test_ietf_actn.py @@ -0,0 +1,84 @@ +import json, logging, requests +from requests.auth import HTTPBasicAuth +from typing import Optional + +LOGGER = logging.getLogger(__name__) + +HTTP_OK_CODES = { + 200, # OK + 201, # Created + 202, # Accepted + 204, # No Content +} + +def create_connectivity_service( + root_url, uuid, node_id_src, tp_id_src, node_id_dst, tp_id_dst, vlan_id, + auth : Optional[HTTPBasicAuth] = None, timeout : Optional[int] = None +): + + url = '{:s}/nmswebs/restconf/data/ietf-eth-tran-service:etht-svc'.format(root_url) + headers = {'content-type': 'application/json'} + data = { + 'etht-svc-instances': [ + { + 'etht-svc-name': uuid, + 'etht-svc-type': 'ietf-eth-tran-types:p2p-svc', + 'etht-svc-end-points': [ + { + 'etht-svc-access-points': [ + {'access-node-id': node_id_src, 'access-ltp-id': tp_id_src, 'access-point-id': '1'} + ], + 'outer-tag': {'vlan-value': vlan_id, 'tag-type': 'ietf-eth-tran-types:classify-c-vlan'}, + 'etht-svc-end-point-name': '{:s}:{:s}'.format(str(node_id_src), str(tp_id_src)), + 'service-classification-type': 'ietf-eth-tran-types:vlan-classification' + }, + { + 'etht-svc-access-points': [ + {'access-node-id': node_id_dst, 'access-ltp-id': tp_id_dst, 'access-point-id': '2'} + ], + 'outer-tag': {'vlan-value': vlan_id, 'tag-type': 'ietf-eth-tran-types:classify-c-vlan'}, + 'etht-svc-end-point-name': '{:s}:{:s}'.format(str(node_id_dst), str(tp_id_dst)), + 'service-classification-type': 'ietf-eth-tran-types:vlan-classification' + } + ] + } + ] + } + results = [] + try: + LOGGER.info('Connectivity service {:s}: {:s}'.format(str(uuid), str(data))) + response = requests.post( + url=url, data=json.dumps(data), timeout=timeout, headers=headers, verify=False, auth=auth) + LOGGER.info('Microwave Driver response: {:s}'.format(str(response))) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception creating ConnectivityService(uuid={:s}, data={:s})'.format(str(uuid), str(data))) + results.append(e) + else: + if response.status_code not in HTTP_OK_CODES: + msg = 'Could not create ConnectivityService(uuid={:s}, data={:s}). status_code={:s} reply={:s}' + LOGGER.error(msg.format(str(uuid), str(data), str(response.status_code), str(response))) + results.append(response.status_code in HTTP_OK_CODES) + return results + +def delete_connectivity_service(root_url, uuid, auth : Optional[HTTPBasicAuth] = None, timeout : Optional[int] = None): + url = '{:s}/nmswebs/restconf/data/ietf-eth-tran-service:etht-svc/etht-svc-instances={:s}' + url = url.format(root_url, uuid) + results = [] + try: + response = requests.delete(url=url, timeout=timeout, verify=False, auth=auth) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception deleting ConnectivityService(uuid={:s})'.format(str(uuid))) + results.append(e) + else: + if response.status_code not in HTTP_OK_CODES: + msg = 'Could not delete ConnectivityService(uuid={:s}). status_code={:s} reply={:s}' + LOGGER.error(msg.format(str(uuid), str(response.status_code), str(response))) + results.append(response.status_code in HTTP_OK_CODES) + return results + +if __name__ == '__main__': + ROOT_URL = 'https://127.0.0.1:8443' + SERVICE_UUID = 'my-service' + + create_connectivity_service(ROOT_URL, SERVICE_UUID, '172.18.0.1', '1', '172.18.0.2', '2', 300) + delete_connectivity_service(ROOT_URL, SERVICE_UUID)