Commit 5e603368 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Merge branch 'feat/device-microwave' into 'develop'

First version of DeviceDriver for MicroWave devices

See merge request teraflow-h2020/controller!101
parents 5ebb9dcb 6bad5475
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
#!/bin/bash
# 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.


PROJECTDIR=`pwd`

cd $PROJECTDIR/src
RCFILE=$PROJECTDIR/coverage/.coveragerc

# Run unitary tests and analyze coverage of code at same time

# Useful flags for pytest:
#-o log_cli=true -o log_file=device.log -o log_file_level=DEBUG

coverage run --rcfile=$RCFILE --append -m pytest -s --log-level=INFO --verbose \
    device/tests/test_unitary_microwave.py
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ from enum import Enum
class DeviceTypeEnum(Enum):
    EMULATED_OPTICAL_LINE_SYSTEM = 'emu-optical-line-system'
    EMULATED_PACKET_ROUTER       = 'emu-packet-router'
    MICROVAWE_RADIO_SYSTEM       = 'microwave-radio-system'
    OPTICAL_ROADM                = 'optical-roadm'
    OPTICAL_TRANDPONDER          = 'optical-trandponder'
    OPTICAL_LINE_SYSTEM          = 'optical-line-system'
+12 −0
Original line number Diff line number Diff line
@@ -32,6 +32,10 @@ DEVICE_PR_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG]
DEVICE_TAPI_TYPE    = DeviceTypeEnum.OPTICAL_LINE_SYSTEM.value
DEVICE_TAPI_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API]

# check which enum type and value assign to microwave device
DEVICE_MICROWAVE_TYPE    = DeviceTypeEnum.MICROVAWE_RADIO_SYSTEM.value
DEVICE_MICROWAVE_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY]

DEVICE_P4_TYPE      = DeviceTypeEnum.P4_SWITCH.value
DEVICE_P4_DRIVERS   = [DeviceDriverEnum.DEVICEDRIVER_P4]

@@ -81,6 +85,14 @@ def json_device_tapi_disabled(
    return json_device(
        device_uuid, DEVICE_TAPI_TYPE, DEVICE_DISABLED, endpoints=endpoints, config_rules=config_rules, drivers=drivers)

def json_device_microwave_disabled(
        device_uuid : str, endpoints : List[Dict] = [], config_rules : List[Dict] = [],
        drivers : List[Dict] = DEVICE_MICROWAVE_DRIVERS
    ):
    return json_device(
        device_uuid, DEVICE_MICROWAVE_TYPE, DEVICE_DISABLED, endpoints=endpoints, config_rules=config_rules,
        drivers=drivers)

def json_device_p4_disabled(
        device_uuid : str, endpoints : List[Dict] = [], config_rules : List[Dict] = [],
        drivers : List[Dict] = DEVICE_P4_DRIVERS
+7 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ from .emulated.EmulatedDriver import EmulatedDriver
from .openconfig.OpenConfigDriver import OpenConfigDriver
from .transport_api.TransportApiDriver import TransportApiDriver
from .p4.p4_driver import P4Driver
from .microwave.IETFApiDriver import IETFApiDriver

DRIVERS = [
    (EmulatedDriver, [
@@ -51,4 +52,10 @@ DRIVERS = [
            FilterFieldEnum.DRIVER     : ORM_DeviceDriverEnum.P4,
        }
    ]),
    (IETFApiDriver, [
        {
            FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.MICROVAWE_RADIO_SYSTEM,
            FilterFieldEnum.DRIVER     : ORM_DeviceDriverEnum.IETF_NETWORK_TOPOLOGY,
        }
    ]),
]
+110 −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.

import logging, requests, threading
from typing import Any, Iterator, List, Optional, Tuple, Union
from common.type_checkers.Checkers import chk_string, chk_type
from device.service.driver_api._Driver import _Driver
from . import ALL_RESOURCE_KEYS
from .Tools import create_connectivity_service, find_key, config_getter, delete_connectivity_service

LOGGER = logging.getLogger(__name__)

class IETFApiDriver(_Driver):
    def __init__(self, address: str, port: int, **settings) -> None:    # pylint: disable=super-init-not-called
        self.__lock = threading.Lock()
        self.__started = threading.Event()
        self.__terminate = threading.Event()
        self.__ietf_root = 'https://' + address + ':' + str(port)
        self.__timeout = int(settings.get('timeout', 120))

    def Connect(self) -> bool:
        url = self.__ietf_root + '/nmswebs/restconf/data/ietf-network:networks'
        with self.__lock:
            if self.__started.is_set(): return True
            try:
                requests.get(url, timeout=self.__timeout, verify=False)
            except requests.exceptions.Timeout:
                LOGGER.exception('Timeout connecting {:s}'.format(str(self.__ietf_root)))
                return False
            except Exception:  # pylint: disable=broad-except
                LOGGER.exception('Exception connecting {:s}'.format(str(self.__ietf_root)))
                return False
            else:
                self.__started.set()
                return True

    def Disconnect(self) -> bool:
        with self.__lock:
            self.__terminate.set()
            return True

    def GetInitialConfig(self) -> List[Tuple[str, Any]]:
        with self.__lock:
            return []

    def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]:
        chk_type('resources', resource_keys, list)
        results = []
        with self.__lock:
            if len(resource_keys) == 0: resource_keys = ALL_RESOURCE_KEYS
            for i, resource_key in enumerate(resource_keys):
                str_resource_name = 'resource_key[#{:d}]'.format(i)
                chk_string(str_resource_name, resource_key, allow_empty=False)
                results.extend(config_getter(self.__ietf_root, resource_key, self.__timeout))
        return results

    def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
        results = []
        if len(resources) == 0:
            return results
        with self.__lock:
            for resource in resources:
                LOGGER.info('resource = {:s}'.format(str(resource)))

                node_id_src = find_key(resource, 'node_id_src')
                tp_id_src = find_key(resource, 'tp_id_src')
                node_id_dst = find_key(resource, 'node_id_dst')
                tp_id_dst = find_key(resource, 'tp_id_dst')
                vlan_id = find_key(resource, 'vlan_id')
                uuid = find_key(resource, 'uuid')

                data = create_connectivity_service(
                    self.__ietf_root, self.__timeout, uuid, node_id_src, tp_id_src, node_id_dst, tp_id_dst, vlan_id)
                results.extend(data)
        return results

    def DeleteConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
        results = []
        if len(resources) == 0: return results
        with self.__lock:
            for resource in resources:
                LOGGER.info('resource = {:s}'.format(str(resource)))
                uuid = find_key(resource, 'uuid')
                results.extend(delete_connectivity_service(self.__ietf_root, self.__timeout, uuid))
        return results

    def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
        # TODO: IETF API Driver does not support monitoring by now
        return [False for _ in subscriptions]

    def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
        # TODO: IETF API Driver does not support monitoring by now
        return [False for _ in subscriptions]

    def GetState(
        self, blocking=False, terminate : Optional[threading.Event] = None
    ) -> Iterator[Tuple[float, str, Any]]:
        # TODO: IETF API Driver does not support monitoring by now
        return []
Loading