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
Loading
Loading
Loading
Loading
+130 −0
Original line number Diff line number Diff line
# 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())
+22 −0
Original line number Diff line number Diff line
# 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+"
+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.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
+25 −0
Original line number Diff line number Diff line
{
    "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
                }}}
            ]}
        }
    ]
}