Commit e1958317 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Merge branch 'feat/106-implement-optical-component' into 'develop'

Resolve "Implement Optical component"

Closes #106

See merge request !192
parents c5b1bbeb ff3fb583
Loading
Loading
Loading
Loading
+79 −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.

FROM python:3.9-slim

# Install dependencies
RUN apt-get --yes --quiet --quiet update && \
    apt-get --yes --quiet --quiet install wget g++ && \
    rm -rf /var/lib/apt/lists/*

# Set Python to show logs as they occur
ENV PYTHONUNBUFFERED=0

# Download the gRPC health probe
# RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \
#     wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \
#     chmod +x /bin/grpc_health_probe




# 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



COPY common_requirements.in common_requirements.in
RUN pip-compile --quiet --output-file=common_requirements.txt common_requirements.in
RUN python3 -m pip install -r common_requirements.txt

RUN mkdir -p /var/teraflow/opticalcontroller

WORKDIR /var/teraflow/opticalcontroller/common
COPY src/common/. ./
RUN rm -rf proto


# Create proto sub-folder, copy .proto files, and generate Python code
RUN mkdir -p /var/teraflow/opticalcontroller/common/proto
WORKDIR /var/teraflow/opticalcontroller/common/proto
RUN touch __init__.py
COPY proto/*.proto ./
RUN python3 -m grpc_tools.protoc -I=. --python_out=. --grpc_python_out=. *.proto
RUN rm *.proto
RUN find . -type f -exec sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' {} \;

# Create component sub-folder, get specific Python packages



WORKDIR /var/teraflow/opticalcontroller
COPY src/opticalcontroller/requirements.in requirements.in
RUN pip-compile --quiet --output-file=requirements.txt requirements.in
RUN python3 -m pip install -r requirements.txt

# Add component files into working directory
WORKDIR /var/teraflow/

COPY src/context/. context/

COPY src/opticalcontroller/. opticalcontroller/
COPY src/context/. opticalcontroller/context/

# Start the service
WORKDIR /var/teraflow/opticalcontroller
ENTRYPOINT ["python", "OpticalController.py"]
+246 −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.

from flask import Flask
from flask import render_template
from flask_restplus import Resource, Api

from tools import *
from variables import *
from RSA import RSA
import time
import logging


rsa = None
LOGGER = logging.getLogger(__name__)

app = Flask(__name__)
api = Api(app, version='1.0', title='Optical controller API',
          description='Rest API to configure OC Optical devices in TFS')
# app.config.from_object('config')
# appbuilder = AppBuilder(app, indexview=MyIndexView)
optical = api.namespace('OpticalTFS', description='TFS Optical APIs')


@app.route('/index')
def index():
    return render_template('index.html')


#@optical.route('/AddLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>')
@optical.route('/AddLightpath/<string:src>/<string:dst>/<int:bitrate>')
@optical.response(200, 'Success')
@optical.response(404, 'Error, not found')
class AddLightpath(Resource):
    @staticmethod
    def put(src, dst, bitrate, bidir=1):

        LOGGER.info("INFO: New Lightpath request from {} to {} with rate {} ".format(src, dst, bitrate))
        t0 = time.time()*1000.0
        if debug:
            rsa.g.printGraph()

        if rsa is not None:
            flow_id = rsa.rsa_computation(src, dst, bitrate, bidir)
            if rsa.db_flows[flow_id]["op-mode"] == 0:
                return 'No path found', 404
            t1 = time.time()*1000.0
            elapsed = t1 - t0
            LOGGER.info("INFO: time elapsed = {} ms".format(elapsed))
            return rsa.db_flows[flow_id], 200
        else:
            return "Error", 404


#@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>')
@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>',
               defaults={"bidir": 1, "band": None})
@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>',
               defaults={"band": None})
@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>/<int:band>',)
@optical.response(200, 'Success')
@optical.response(404, 'Error, not found')
class AddFlexLightpath(Resource):
    @staticmethod
    def put(src, dst, bitrate,bidir=1, band=None):
        
        print("INFO: New FlexLightpath request from {} to {} with rate {} ".format(src, dst, bitrate))
        LOGGER.info("INFO: New FlexLightpath request from {} to {} with rate {} ".format(src, dst, bitrate))
        t0 = time.time()*1000.0
        if debug:
            rsa.g.printGraph()

        if rsa is not None:
            flow_id, optical_band_id = rsa.rsa_fs_computation(src, dst, bitrate, bidir, band)
            print (f"flow_id {flow_id} and optical_band_id {optical_band_id} ")
            if flow_id is not None:
                if rsa.db_flows[flow_id]["op-mode"] == 0:
                    return 'No path found', 404
                t1 = time.time() * 1000.0
                elapsed = t1 - t0
                print("INFO: time elapsed = {} ms".format(elapsed))

                return rsa.db_flows[flow_id], 200
            else:
                if len(rsa.optical_bands[optical_band_id]["flows"]) == 0:
                    return 'No path found', 404
                else:
                    t1 = time.time() * 1000.0
                    elapsed = t1 - t0
                    LOGGER.info("INFO: time elapsed = {} ms".format(elapsed))

                    return rsa.optical_bands[optical_band_id], 200
        else:
            return "Error", 404

@optical.route('/DelFlexLightpath/<int:flow_id>/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>')
@optical.response(200, 'Success')
@optical.response(404, 'Error, not found')
class DelLightpath(Resource):
    @staticmethod
    def delete(flow_id, src, dst, bitrate, o_band_id):
        if flow_id in rsa.db_flows.keys():
            flow = rsa.db_flows[flow_id]
            bidir = flow["bidir"]
            match1 = flow["src"] == src and flow["dst"] == dst and flow["bitrate"] == bitrate
            if bidir:
                match2 = flow["src"] == dst and flow["dst"] == src and flow["bitrate"] == bitrate
                if match1 or match2:
                    ob_id = flow["parent_opt_band"]
                    rsa.del_flow(flow, ob_id)
                    rsa.db_flows[flow_id]["is_active"] = False
                    rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id)
                    if rsa.optical_bands[ob_id]["reverse_optical_band_id"] != 0:
                        rev_ob_id = rsa.optical_bands[ob_id]["reverse_optical_band_id"]
                        rsa.optical_bands[rev_ob_id]["served_lightpaths"].remove(flow_id)

                    if debug:
                       LOGGER.info(links_dict)
                    return "flow {} deleted".format(flow_id), 200
                else:
                    return "flow {} not matching".format(flow_id), 404
            else:
                if match1:
                    ob_id = flow["parent_opt_band"]
                    rsa.del_flow(flow, ob_id)
                    rsa.db_flows[flow_id]["is_active"] = False
                    rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id)
                    if debug:
                       LOGGER.info(links_dict)
                    return "flow {} deleted".format(flow_id), 200
                else:
                    return "flow {} not matching".format(flow_id), 404
        else:
            return "flow id {} does not exist".format(flow_id), 404



@optical.route('/DelLightpath/<int:flow_id>/<string:src>/<string:dst>/<int:bitrate>')
@optical.response(200, 'Success')
@optical.response(404, 'Error, not found')
class DelLightpath(Resource):
    @staticmethod
    def delete(flow_id, src, dst, bitrate):
        if flow_id in rsa.db_flows.keys():
            flow = rsa.db_flows[flow_id]
            match1 = flow["src"] == src and flow["dst"] == dst and flow["bitrate"] == bitrate
            match2 = flow["src"] == dst and flow["dst"] == src and flow["bitrate"] == bitrate
            if match1 or match2:
                rsa.del_flow(flow)
                rsa.db_flows[flow_id]["is_active"] = False
                if debug:
                   LOGGER.info(links_dict)
                return "flow {} deleted".format(flow_id), 200
            else:
                return "flow {} not matching".format(flow_id), 404
        else:
            return "flow id {} does not exist".format(flow_id), 404


@optical.route('/GetLightpaths')
@optical.response(200, 'Success')
@optical.response(404, 'Error, not found')
class GetFlows(Resource):
    @staticmethod
    def get():
        try:
            if debug:
               LOGGER.info(rsa.db_flows)
            return rsa.db_flows, 200
        except:
            return "Error", 404

@optical.route('/GetOpticalBands')
@optical.response(200, 'Success')
@optical.response(404, 'Error, not found')
class GetBands(Resource):
    @staticmethod
    def get():
        print("Getting ")
        LOGGER.info("Getting")
        try:
            if debug:
               LOGGER.info(rsa.optical_bands)
            return rsa.optical_bands, 200
        except:
            return "Error", 404


@optical.route('/GetOpticalBand/<string:ob_id>')
@optical.response(200, 'Success')
@optical.response(404, 'Error, not found')
class GetBand(Resource):
    @staticmethod
    def get(ob_id):
        for ob_idx in rsa.optical_bands.keys():
            if str(ob_idx) == str(ob_id):
                if debug:
                   LOGGER.info(rsa.optical_bands[ob_id])
                return rsa.optical_bands[ob_idx], 200
        return {}, 404


@optical.route('/GetLinks')
@optical.response(200, 'Success')
@optical.response(404, 'Error, not found')
class GetFlows(Resource):
    @staticmethod
    def get():
        global links_dict
        try:
            if debug:
               LOGGER.info(links_dict)
            return links_dict, 200
        except:
            return "Error", 404


if __name__ == '__main__':
    

    # Start metrics server

    LOGGER.info('Starting...')



    nodes_dict, links_dict = readTopologyData(nodes_json, topology_json)

    topologies,links=  getTopology()
    print ("topologies{} and devices {}".format(topologies,links))
    rsa = RSA(nodes_dict, links_dict)
    LOGGER.info(rsa.init_link_slots(testing))

    app.run(host='0.0.0.0', port=5022,debug=True)
+17 −0
Original line number Diff line number Diff line
# optical-controller
This a framework to implement the optical controller for the RMSA algorithm.
#create a venv
python -m venv venv

in linux
source venv/Scripts/activate

in windows
venv\Scripts\activate

pip install -r requirements_opt.txt

python OpticalController.py
![Reference Architecture](images/topo.png)

+927 −0

File added.

Preview size limit exceeded, changes collapsed.

+13 −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.
Loading