Skip to content
Snippets Groups Projects
Commit 8b72fc48 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Test tools:

- Descriptors for a test topology
- Descriptiors for a test microwave service
- Implemented Mock MicroWave SDN Controller to test MicroWaveDeviceDriver
parent 42c31e2e
No related branches found
No related tags found
2 merge requests!54Release 2.0.0,!22Microwave ServiceHandler
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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, request
from flask.json import jsonify
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': '172.18.0.1', 'ietf-network-topology:termination-point': [
{'tp-id': '172.18.0.1:1', 'ietf-te-topology:te': {'name': 'ethernet'}},
{'tp-id': '172.18.0.1:2', 'ietf-te-topology:te': {'name': 'antena' }},
]},
{'node-id': '172.18.0.2', 'ietf-network-topology:termination-point': [
{'tp-id': '172.18.0.2:1', 'ietf-te-topology:te': {'name': 'ethernet'}},
{'tp-id': '172.18.0.2:2', 'ietf-te-topology:te': {'name': 'antena' }},
]},
{'node-id': '172.18.0.3', 'ietf-network-topology:termination-point': [
{'tp-id': '172.18.0.3:1', 'ietf-te-topology:te': {'name': 'ethernet'}},
{'tp-id': '172.18.0.3:2', 'ietf-te-topology:te': {'name': 'antena' }},
]},
{'node-id': '172.18.0.4', 'ietf-network-topology:termination-point': [
{'tp-id': '172.18.0.4:1', 'ietf-te-topology:te': {'name': 'ethernet'}},
{'tp-id': '172.18.0.4:2', 'ietf-te-topology:te': {'name': 'antena' }},
]}
]
NETWORK_LINKS = [
{
'source' : {'source-node': '172.18.0.1', 'source-tp': '172.18.0.1:2'},
'destination': {'dest-node' : '172.18.0.2', 'dest-tp' : '172.18.0.2:2'},
},
{
'source' : {'source-node': '172.18.0.3', 'source-tp': '172.18.0.3:2'},
'destination': {'dest-node' : '172.18.0.4', 'dest-tp' : '172.18.0.4:2'},
}
]
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 jsonify({})
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 jsonify({'ietf-network:network': network})
class Services(Resource):
def get(self):
services = [service for service in NETWORK_SERVICES.values()]
return jsonify({'ietf-eth-tran-service:etht-svc': {'etht-svc-instances': services}})
def post(self):
json_request = request.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 jsonify({}), 201
class DelServices(Resource):
def delete(self, service_uuid : str):
NETWORK_SERVICES.pop(service_uuid, None)
return 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())
# 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 automation policy service compute 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+"
{
"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.56"}},
{"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
{
"services": [
{
"service_id": {
"context_id": {"context_uuid": {"uuid": "admin"}},
"service_uuid": {"uuid": "siae-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": [
{"custom": {"constraint_type": "bandwidth[gbps]", "constraint_value": "10.0"}},
{"custom": {"constraint_type": "latency[ms]", "constraint_value": "15.2"}}
],
"service_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "/settings", "resource_value": {
"vlan_id": 121
}}}
]}
}
]
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment