Commit 6e4b217d authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Device component - ACTN Driver:

- Migrated RestApiClient to RestConfClient
- Multiple code polishing and alignment
parent bb63515b
Loading
Loading
Loading
Loading
+12 −16
Original line number Diff line number Diff line
@@ -21,19 +21,22 @@ from device.service.driver_api._Driver import _Driver, RESOURCE_ENDPOINTS, RESOU
from .handlers.EthtServiceHandler import EthtServiceHandler
from .handlers.OsuTunnelHandler import OsuTunnelHandler
from .handlers.NetworkTopologyHandler import NetworkTopologyHandler
from .handlers.RestApiClient import RestApiClient
from .Tools import get_etht_services, get_osu_tunnels, parse_resource_key


LOGGER = logging.getLogger(__name__)


ALL_RESOURCE_KEYS = [
    RESOURCE_ENDPOINTS,
    RESOURCE_SERVICES,
]


DRIVER_NAME = 'ietf_actn'
METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME})


class IetfActnDriver(_Driver):
    def __init__(self, address: str, port: int, **settings) -> None:
        super().__init__(DRIVER_NAME, address, port, **settings)
@@ -41,23 +44,20 @@ class IetfActnDriver(_Driver):
        self.__started = threading.Event()
        self.__terminate = threading.Event()

        self._rest_api_client = RestApiClient(address, port, settings=settings)

        restconf_settings = copy.deepcopy(settings)
        restconf_settings.pop('base_url', None)
        restconf_settings.pop('import_topology', None)
        restconf_settings['logger'] = logging.getLogger(__name__ + '.RestConfClient')
        self._rest_conf_client = RestConfClient(address, port=port, **restconf_settings)

        self._handler_etht_service = EthtServiceHandler(self._rest_api_client)
        self._handler_etht_service = EthtServiceHandler(self._rest_conf_client)
        self._handler_net_topology = NetworkTopologyHandler(self._rest_conf_client, **settings)
        self._handler_osu_tunnel = OsuTunnelHandler(self._rest_api_client)
        self._handler_osu_tunnel = OsuTunnelHandler(self._rest_conf_client)

    def Connect(self) -> bool:
        with self.__lock:
            if self.__started.is_set(): return True
            try:
                self._rest_api_client.get('Check Credentials', '')
                self._rest_conf_client._discover_base_url()
            except requests.exceptions.Timeout:
                LOGGER.exception('Timeout exception checking connectivity')
                return False
@@ -81,15 +81,13 @@ class IetfActnDriver(_Driver):
    @metered_subclass_method(METRICS_POOL)
    def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]:
        chk_type('resources', resource_keys, list)
        results = []
        results = list()
        with self.__lock:
            if len(resource_keys) == 0: resource_keys = ALL_RESOURCE_KEYS
            for i, resource_key in enumerate(resource_keys):
                chk_string('resource_key[#{:d}]'.format(i), resource_key, allow_empty=False)

                try:
                    _results = list()

                    if resource_key == RESOURCE_ENDPOINTS:
                        # Add mgmt endpoint by default
                        #resource_key = '/endpoints/endpoint[mgmt]'
@@ -97,17 +95,15 @@ class IetfActnDriver(_Driver):
                        #results.append((resource_key, resource_value))
                        results.extend(self._handler_net_topology.get())
                    elif resource_key == RESOURCE_SERVICES:
                        get_osu_tunnels(self._handler_osu_tunnel, _results)
                        get_etht_services(self._handler_etht_service, _results)
                        get_osu_tunnels(self._handler_osu_tunnel, results)
                        get_etht_services(self._handler_etht_service, results)
                    else:
                        # check if resource key is for a specific OSU tunnel or ETHT service, and get them accordingly
                        osu_tunnel_name, etht_service_name = parse_resource_key(resource_key)
                        if osu_tunnel_name is not None:
                            get_osu_tunnels(self._handler_osu_tunnel, _results, osu_tunnel_name=osu_tunnel_name)
                            get_osu_tunnels(self._handler_osu_tunnel, results, osu_tunnel_name=osu_tunnel_name)
                        if etht_service_name is not None:
                            get_etht_services(self._handler_etht_service, _results, etht_service_name=etht_service_name)

                    results.extend(_results)
                            get_etht_services(self._handler_etht_service, results, etht_service_name=etht_service_name)
                except Exception as e:
                    MSG = 'Error processing resource_key: {:s}'
                    LOGGER.exception(MSG.format(str(resource_key)))
+16 −27
Original line number Diff line number Diff line
@@ -14,10 +14,12 @@

import enum, logging
from typing import Dict, List, Optional, Tuple, Union
from .RestApiClient import HTTP_STATUS_CREATED, HTTP_STATUS_NO_CONTENT, HTTP_STATUS_OK, RestApiClient
from common.tools.client.RestConfClient import RestConfClient


LOGGER = logging.getLogger(__name__)


class BandwidthProfileTypeEnum(enum.Enum):
    MEF_10_BWP = 'ietf-eth-tran-types:mef-10-bwp'

@@ -106,36 +108,20 @@ def compose_etht_service(
        'optimizations': compose_optimizations(),
    }]}}


class EthtServiceHandler:
    def __init__(self, rest_api_client : RestApiClient) -> None:
        self._rest_api_client = rest_api_client
        self._object_name  = 'EthtService'
    def __init__(self, rest_conf_client : RestConfClient) -> None:
        self._rest_conf_client = rest_conf_client
        self._subpath_root = '/ietf-eth-tran-service:etht-svc'
        self._subpath_item = self._subpath_root + '/etht-svc-instances="{etht_service_name:s}"'
        self._subpath_item = self._subpath_root + '/etht-svc-instances={etht_service_name:s}'

    def _rest_api_get(self, etht_service_name : Optional[str] = None) -> Union[Dict, List]:

    def get(self, etht_service_name : Optional[str] = None) -> Union[Dict, List]:
        if etht_service_name is None:
            subpath_url = self._subpath_root
        else:
            subpath_url = self._subpath_item.format(etht_service_name=etht_service_name)
        return self._rest_api_client.get(
            self._object_name, subpath_url, expected_http_status={HTTP_STATUS_OK}
        )

    def _rest_api_update(self, data : Dict) -> bool:
        return self._rest_api_client.update(
            self._object_name, self._subpath_root, data, expected_http_status={HTTP_STATUS_CREATED}
        )

    def _rest_api_delete(self, etht_service_name : str) -> bool:
        if etht_service_name is None: raise Exception('etht_service_name is None')
        subpath_url = self._subpath_item.format(etht_service_name=etht_service_name)
        return self._rest_api_client.delete(
            self._object_name, subpath_url, expected_http_status={HTTP_STATUS_NO_CONTENT}
        )

    def get(self, etht_service_name : Optional[str] = None) -> Union[Dict, List]:
        data = self._rest_api_get(etht_service_name=etht_service_name)
        data = self._rest_conf_client.get(subpath_url)

        if not isinstance(data, dict): raise ValueError('data should be a dict')
        if 'ietf-eth-tran-service:etht-svc' not in data:
@@ -192,6 +178,7 @@ class EthtServiceHandler:

        return etht_services


    def update(self, parameters : Dict) -> bool:
        name              = parameters['name'           ]
        service_type      = parameters['service_type'   ]
@@ -214,8 +201,10 @@ class EthtServiceHandler:
            src_node_id, src_tp_id, src_vlan_tag, dst_node_id, dst_tp_id, dst_vlan_tag,
            src_static_routes=src_static_routes, dst_static_routes=dst_static_routes
        )
        return self._rest_conf_client.post(self._subpath_root, body=data) is not None

        return self._rest_api_update(data)

    def delete(self, etht_service_name : str) -> bool:
        return self._rest_api_delete(etht_service_name)
    def delete(self, etht_service_name : str) -> None:
        if etht_service_name is None: raise Exception('etht_service_name is None')
        subpath_url = self._subpath_item.format(etht_service_name=etht_service_name)
        return self._rest_conf_client.delete(subpath_url)
+0 −1
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ LOGGER = logging.getLogger(__name__)
class NetworkTopologyHandler:
    def __init__(self, rest_conf_client : RestConfClient, **settings) -> None:
        self._rest_conf_client = rest_conf_client
        self._object_name  = 'NetworkTopology'
        self._subpath_root = '/ietf-network:networks'
        self._subpath_item = self._subpath_root + '/network={network_id:s}'

+15 −25
Original line number Diff line number Diff line
@@ -14,10 +14,12 @@

import enum, logging
from typing import Dict, List, Optional, Union
from .RestApiClient import HTTP_STATUS_CREATED, HTTP_STATUS_NO_CONTENT, HTTP_STATUS_OK, RestApiClient
from common.tools.client.RestConfClient import RestConfClient


LOGGER = logging.getLogger(__name__)


class EndpointProtectionRoleEnum(enum.Enum):
    WORK = 'work'

@@ -80,36 +82,21 @@ def compose_osu_tunnel(
        'protection': compose_osu_tunnel_protection(),
    }]}


class OsuTunnelHandler:
    def __init__(self, rest_api_client : RestApiClient) -> None:
        self._rest_api_client = rest_api_client
        self._object_name  = 'OsuTunnel'
    def __init__(self, rest_conf_client : RestConfClient) -> None:
        self._rest_conf_client = rest_conf_client
        self._subpath_root = '/ietf-te:te/tunnels'
        self._subpath_item = self._subpath_root + '/tunnel="{osu_tunnel_name:s}"'
        self._subpath_item = self._subpath_root + '/tunnel={osu_tunnel_name:s}'


    def _rest_api_get(self, osu_tunnel_name : Optional[str] = None) -> Union[Dict, List]:
    def get(self, osu_tunnel_name : Optional[str] = None) -> Union[Dict, List]:
        if osu_tunnel_name is None:
            subpath_url = self._subpath_root
        else:
            subpath_url = self._subpath_item.format(osu_tunnel_name=osu_tunnel_name)
        return self._rest_api_client.get(
            self._object_name, subpath_url, expected_http_status={HTTP_STATUS_OK}
        )

    def _rest_api_update(self, data : Dict) -> bool:
        return self._rest_api_client.update(
            self._object_name, self._subpath_root, data, expected_http_status={HTTP_STATUS_CREATED}
        )

    def _rest_api_delete(self, osu_tunnel_name : str) -> bool:
        if osu_tunnel_name is None: raise Exception('osu_tunnel_name is None')
        subpath_url = self._subpath_item.format(osu_tunnel_name=osu_tunnel_name)
        return self._rest_api_client.delete(
            self._object_name, subpath_url, expected_http_status={HTTP_STATUS_NO_CONTENT}
        )

    def get(self, osu_tunnel_name : Optional[str] = None) -> Union[Dict, List]:
        data = self._rest_api_get(osu_tunnel_name=osu_tunnel_name)
        data = self._rest_conf_client.get(subpath_url)

        if not isinstance(data, dict): raise ValueError('data should be a dict')
        if 'ietf-te:tunnel' not in data: raise ValueError('data does not contain key "ietf-te:tunnel"')
@@ -147,6 +134,7 @@ class OsuTunnelHandler:

        return osu_tunnels


    def update(self, parameters : Dict) -> bool:
        name                 = parameters['name'                ]

@@ -169,8 +157,10 @@ class OsuTunnelHandler:
            name, src_node_id, src_tp_id, src_ttp_channel_name, dst_node_id, dst_tp_id, dst_ttp_channel_name,
            odu_type, osuflex_number, delay, bidirectional=bidirectional
        )
        return self._rest_conf_client.post(self._subpath_root, body=data) is not None

        return self._rest_api_update(data)

    def delete(self, osu_tunnel_name : str) -> bool:
        return self._rest_api_delete(osu_tunnel_name)
        if osu_tunnel_name is None: raise Exception('osu_tunnel_name is None')
        subpath_url = self._subpath_item.format(osu_tunnel_name=osu_tunnel_name)
        return self._rest_conf_client.delete(subpath_url)