Skip to content
Snippets Groups Projects
routes.py 7.4 KiB
Newer Older
# 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.
longllu's avatar
longllu committed

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
import base64, json, logging #, re
from flask import jsonify, redirect, render_template, Blueprint, flash, session, url_for, request
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
from common.proto.context_pb2 import ContextList, Empty, TopologyId, TopologyList
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
from common.tools.descriptor.Loader import DescriptorLoader, compose_notifications
longllu's avatar
longllu committed
from common.tools.grpc.Tools import grpc_message_to_json_string
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
from common.tools.object_factory.Context import json_context_id
from common.tools.object_factory.Topology import json_topology_id
from context.client.ContextClient import ContextClient
from device.client.DeviceClient import DeviceClient
longllu's avatar
longllu committed
from service.client.ServiceClient import ServiceClient
longllu's avatar
longllu committed
from slice.client.SliceClient import SliceClient
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
from webui.service.main.forms import ContextTopologyForm, DescriptorForm
longllu's avatar
longllu committed

main = Blueprint('main', __name__)
longllu's avatar
longllu committed

context_client = ContextClient()
device_client = DeviceClient()
longllu's avatar
longllu committed
service_client = ServiceClient()
longllu's avatar
longllu committed
slice_client = SliceClient()

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
LOGGER = logging.getLogger(__name__)
longllu's avatar
longllu committed

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
DESCRIPTOR_LOADER_NUM_WORKERS = 10

def process_descriptors(descriptors):
    try:
        descriptors_file = request.files[descriptors.name]
        descriptors_data = descriptors_file.read()
        descriptors = json.loads(descriptors_data)
    except Exception as e: # pylint: disable=broad-except
        flash(f'Unable to load descriptor file: {str(e)}', 'danger')
        return
longllu's avatar
longllu committed

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    descriptor_loader = DescriptorLoader(descriptors, num_workers=DESCRIPTOR_LOADER_NUM_WORKERS)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    results = descriptor_loader.process()
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    for message,level in compose_notifications(results):
Pablo Armingol's avatar
Pablo Armingol committed
        if level == 'error': LOGGER.warning('ERROR message={:s}'.format(str(message)))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        flash(message, level)
longllu's avatar
longllu committed

@main.route('/', methods=['GET', 'POST'])
def home():
    context_client.connect()
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    context_topology_form = ContextTopologyForm()
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    context_topology_form.context_topology.choices.append(('', 'Select...'))
longllu's avatar
longllu committed

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    contexts : ContextList = context_client.ListContexts(Empty())
    for context_ in contexts.contexts:
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        #context_uuid : str = context_.context_id.context_uuid.uuid
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        context_name : str = context_.name
        topologies : TopologyList = context_client.ListTopologies(context_.context_id)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        for topology_ in topologies.topologies:
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            #topology_uuid : str = topology_.topology_id.topology_uuid.uuid
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            topology_name : str = topology_.name
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            raw_values = context_name, topology_name
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            b64_values = [base64.b64encode(v.encode('utf-8')).decode('utf-8') for v in raw_values]
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            context_topology_uuid = ','.join(b64_values)
            context_topology_name  = 'Context({:s}):Topology({:s})'.format(context_name, topology_name)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            context_topology_entry = (context_topology_uuid, context_topology_name)
            context_topology_form.context_topology.choices.append(context_topology_entry)
longllu's avatar
longllu committed

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    if context_topology_form.validate_on_submit():
        context_topology_uuid = context_topology_form.context_topology.data
        if len(context_topology_uuid) > 0:
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            b64_values = context_topology_uuid.split(',')
            raw_values = [base64.b64decode(v.encode('utf-8')).decode('utf-8') for v in b64_values]
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            context_name, topology_name = raw_values
            #session.clear()
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            session['context_topology_uuid'] = context_topology_uuid
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            session['context_uuid'] = context_name
            #session['context_name'] = context_name
            session['topology_uuid'] = topology_name
            #session['topology_name'] = topology_name
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            MSG = f'Context({context_name})/Topology({topology_name}) successfully selected.'
            flash(MSG, 'success')
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed

            context_client.close()
            device_client.close()

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            return redirect(url_for('main.home'))

            #match = re.match('ctx\[([^\]]+)\]\/topo\[([^\]]+)\]', context_topology_uuid)
            #if match is not None:
            #    session['context_topology_uuid'] = context_topology_uuid = match.group(0)
            #    session['context_uuid'] = context_uuid = match.group(1)
            #    session['topology_uuid'] = topology_uuid = match.group(2)
            #    MSG = f'Context({context_uuid})/Topology({topology_uuid}) successfully selected.'
            #    flash(MSG, 'success')
            #    return redirect(url_for('main.home'))
longllu's avatar
longllu committed

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    if 'context_topology_uuid' in session:
        context_topology_form.context_topology.data = session['context_topology_uuid']
longllu's avatar
longllu committed

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    descriptor_form = DescriptorForm()
    try:
        if descriptor_form.validate_on_submit():
            process_descriptors(descriptor_form.descriptors)
            return redirect(url_for("main.home"))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    except Exception as e: # pylint: disable=broad-except
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        LOGGER.exception('Descriptor load failed')
        flash(f'Descriptor load failed: `{str(e)}`', 'danger')
    finally:
        context_client.close()
        device_client.close()
longllu's avatar
longllu committed

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    return render_template(
        'main/home.html', context_topology_form=context_topology_form, descriptor_form=descriptor_form)
longllu's avatar
longllu committed

@main.route('/topology', methods=['GET'])
def topology():
    context_client.connect()
    try:
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        if 'context_uuid' not in session or 'topology_uuid' not in session:
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            return jsonify({'devices': [], 'links': []})

        context_uuid = session['context_uuid']
        topology_uuid = session['topology_uuid']

        json_topo_id = json_topology_id(topology_uuid, context_id=json_context_id(context_uuid))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        response = context_client.GetTopologyDetails(TopologyId(**json_topo_id))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed

        devices = []
        for device in response.devices:
            devices.append({
                'id': device.device_id.device_uuid.uuid,
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
                'name': device.name,
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
                'type': device.device_type,
            })
longllu's avatar
longllu committed

longllu's avatar
longllu committed
        links = []
        for link in response.links:
            if len(link.link_endpoint_ids) != 2:
                str_link = grpc_message_to_json_string(link)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
                LOGGER.warning('Unexpected link with len(endpoints) != 2: {:s}'.format(str_link))
longllu's avatar
longllu committed
                continue
            links.append({
                'id': link.link_id.link_uuid.uuid,
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
                'name': link.name,
longllu's avatar
longllu committed
                'source': link.link_endpoint_ids[0].device_id.device_uuid.uuid,
                'target': link.link_endpoint_ids[1].device_id.device_uuid.uuid,
            })
longllu's avatar
longllu committed

        return jsonify({'devices': devices, 'links': links})
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    except: # pylint: disable=bare-except
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        LOGGER.exception('Error retrieving topology')
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        return jsonify({'devices': [], 'links': []})
longllu's avatar
longllu committed

@main.get('/about')
def about():
    return render_template('main/about.html')
longllu's avatar
longllu committed

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
@main.get('/debug')
def debug():
    return render_template('main/debug.html')
longllu's avatar
longllu committed

@main.get('/resetsession')
def reset_session():
    session.clear()
longllu's avatar
longllu committed
    return redirect(url_for("main.home"))