Skip to content
Snippets Groups Projects
Commit 7e2ca0af authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Device component - IETF L2VPN Driver:

- added pseudocode
- backup WORK IN PROGRESS
parent 13d9c046
No related branches found
No related tags found
2 merge requests!142Release TeraFlowSDN 2.1,!71OFC'23 + IETF L2VPN Device Driver + Device Controllers + Multiple small improvements
...@@ -12,17 +12,21 @@ ...@@ -12,17 +12,21 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import logging, requests, threading import logging, threading
from requests.auth import HTTPBasicAuth
from typing import Any, Iterator, List, Optional, Tuple, Union from typing import Any, Iterator, List, Optional, Tuple, Union
from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method
from common.type_checkers.Checkers import chk_string, chk_type from common.type_checkers.Checkers import chk_string, chk_type
from device.service.driver_api._Driver import _Driver from device.service.driver_api._Driver import _Driver, RESOURCE_ENDPOINTS, RESOURCE_SERVICES
from . import ALL_RESOURCE_KEYS from .Tools import find_key
from .Tools import create_connectivity_service, find_key, config_getter, delete_connectivity_service from .WimconnectorIETFL2VPN import WimconnectorIETFL2VPN
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
ALL_RESOURCE_KEYS = [
RESOURCE_ENDPOINTS,
RESOURCE_SERVICES,
]
METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': 'ietf_l2vpn'}) METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': 'ietf_l2vpn'})
class IetfL2VpnDriver(_Driver): class IetfL2VpnDriver(_Driver):
...@@ -32,20 +36,17 @@ class IetfL2VpnDriver(_Driver): ...@@ -32,20 +36,17 @@ class IetfL2VpnDriver(_Driver):
self.__terminate = threading.Event() self.__terminate = threading.Event()
username = settings.get('username') username = settings.get('username')
password = settings.get('password') password = settings.get('password')
self.__auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None
scheme = settings.get('scheme', 'http') scheme = settings.get('scheme', 'http')
self.__tapi_root = '{:s}://{:s}:{:d}'.format(scheme, address, int(port)) wim = {'wim_url': '{:s}://{:s}:{:d}'.format(scheme, address, int(port))}
self.__timeout = int(settings.get('timeout', 120)) wim_account = {'user': username, 'password': password}
config = {'mapping_not_needed': False, 'service_endpoint_mapping': mapping}
self.wim = WimconnectorIETFL2VPN(wim, wim_account, config=config)
self.conn_info = {} # internal database emulating OSM storage provided to WIM Connectors
def Connect(self) -> bool: def Connect(self) -> bool:
url = self.__tapi_root + '/restconf/data/tapi-common:context'
with self.__lock: with self.__lock:
if self.__started.is_set(): return True
try: try:
requests.get(url, timeout=self.__timeout, verify=False, auth=self.__auth) self.wim.check_credentials()
except requests.exceptions.Timeout:
LOGGER.exception('Timeout connecting {:s}'.format(str(self.__tapi_root)))
return False
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
LOGGER.exception('Exception connecting {:s}'.format(str(self.__tapi_root))) LOGGER.exception('Exception connecting {:s}'.format(str(self.__tapi_root)))
return False return False
...@@ -68,36 +69,53 @@ class IetfL2VpnDriver(_Driver): ...@@ -68,36 +69,53 @@ class IetfL2VpnDriver(_Driver):
chk_type('resources', resource_keys, list) chk_type('resources', resource_keys, list)
results = [] results = []
with self.__lock: with self.__lock:
self.wim.check_credentials()
if len(resource_keys) == 0: resource_keys = ALL_RESOURCE_KEYS if len(resource_keys) == 0: resource_keys = ALL_RESOURCE_KEYS
for i, resource_key in enumerate(resource_keys): for i, resource_key in enumerate(resource_keys):
str_resource_name = 'resource_key[#{:d}]'.format(i) str_resource_name = 'resource_key[#{:d}]'.format(i)
chk_string(str_resource_name, resource_key, allow_empty=False) chk_string(str_resource_name, resource_key, allow_empty=False)
results.extend(config_getter(
self.__tapi_root, resource_key, timeout=self.__timeout, auth=self.__auth)) if resource_key == RESOURCE_ENDPOINTS:
# return endpoints through debug-api and list-devices method
endpoints = self.debug_api.get_endpoints()
for endpoint in endpoints: results.append(process_endpoint(endpoint))
elif resource_key == RESOURCE_SERVICES:
# return all services through
services = self.wim.get_all_active_connectivity_services()
for service in services: results.append(process_service(service))
else:
# assume single-service retrieval
service = self.wim.get_connectivity_service()
results.append(process_service(service))
return results return results
@metered_subclass_method(METRICS_POOL) @metered_subclass_method(METRICS_POOL)
def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
results = [] results = []
if len(resources) == 0: if len(resources) == 0: return results
return results
with self.__lock: with self.__lock:
self.wim.check_credentials()
for resource in resources: for resource in resources:
LOGGER.info('resource = {:s}'.format(str(resource))) LOGGER.info('resource = {:s}'.format(str(resource)))
input_sip = find_key(resource, 'input_sip')
output_sip = find_key(resource, 'output_sip')
uuid = find_key(resource, 'uuid') uuid = find_key(resource, 'uuid')
capacity_value = find_key(resource, 'capacity_value') #input_sip = find_key(resource, 'input_sip')
capacity_unit = find_key(resource, 'capacity_unit') #output_sip = find_key(resource, 'output_sip')
layer_protocol_name = find_key(resource, 'layer_protocol_name') #capacity_value = find_key(resource, 'capacity_value')
layer_protocol_qualifier = find_key(resource, 'layer_protocol_qualifier') #capacity_unit = find_key(resource, 'capacity_unit')
direction = find_key(resource, 'direction') #layer_protocol_name = find_key(resource, 'layer_protocol_name')
#layer_protocol_qualifier = find_key(resource, 'layer_protocol_qualifier')
data = create_connectivity_service( #direction = find_key(resource, 'direction')
self.__tapi_root, uuid, input_sip, output_sip, direction, capacity_value, capacity_unit,
layer_protocol_name, layer_protocol_qualifier, timeout=self.__timeout, auth=self.__auth) result = self.wim.get_connectivity_service_status(
results.extend(data) service_uuid, conn_info=conn_info)
if service_exists(result):
result = self.wim.create_connectivity_service(
service_type, connection_points)
else:
result = self.wim.edit_connectivity_service(
service_uuid, conn_info=conn_info, connection_points=connection_points)
results.extend(process_result(result))
return results return results
@metered_subclass_method(METRICS_POOL) @metered_subclass_method(METRICS_POOL)
...@@ -105,25 +123,33 @@ class IetfL2VpnDriver(_Driver): ...@@ -105,25 +123,33 @@ class IetfL2VpnDriver(_Driver):
results = [] results = []
if len(resources) == 0: return results if len(resources) == 0: return results
with self.__lock: with self.__lock:
self.wim.check_credentials()
for resource in resources: for resource in resources:
LOGGER.info('resource = {:s}'.format(str(resource))) LOGGER.info('resource = {:s}'.format(str(resource)))
uuid = find_key(resource, 'uuid') uuid = find_key(resource, 'uuid')
results.extend(delete_connectivity_service(
self.__tapi_root, uuid, timeout=self.__timeout, auth=self.__auth)) result = self.wim.get_connectivity_service_status(
service_uuid, conn_info=conn_info)
if service_exists(result):
result = self.wim.delete_connectivity_service(
service_uuid, conn_info=conn_info)
else:
result = False
results.append(process_result(result))
return results return results
@metered_subclass_method(METRICS_POOL) @metered_subclass_method(METRICS_POOL)
def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
# TODO: TAPI does not support monitoring by now # TODO: IETF L2VPN does not support monitoring by now
return [False for _ in subscriptions] return [False for _ in subscriptions]
@metered_subclass_method(METRICS_POOL) @metered_subclass_method(METRICS_POOL)
def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
# TODO: TAPI does not support monitoring by now # TODO: IETF L2VPN does not support monitoring by now
return [False for _ in subscriptions] return [False for _ in subscriptions]
def GetState( def GetState(
self, blocking=False, terminate : Optional[threading.Event] = None self, blocking=False, terminate : Optional[threading.Event] = None
) -> Iterator[Tuple[float, str, Any]]: ) -> Iterator[Tuple[float, str, Any]]:
# TODO: TAPI does not support monitoring by now # TODO: IETF L2VPN does not support monitoring by now
return [] return []
# 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.
import logging
from .WimconnectorIETFL2VPN import WimconnectorIETFL2VPN
LOGGER = logging.getLogger(__name__)
class MockOSM:
def __init__(self, url, mapping, username, password):
wim = {'wim_url': url}
wim_account = {'user': username, 'password': password}
config = {'mapping_not_needed': False, 'service_endpoint_mapping': mapping}
self.wim = WimconnectorIETFL2VPN(wim, wim_account, config=config)
self.conn_info = {} # internal database emulating OSM storage provided to WIM Connectors
def create_connectivity_service(self, service_type, connection_points):
LOGGER.info('[create_connectivity_service] service_type={:s}'.format(str(service_type)))
LOGGER.info('[create_connectivity_service] connection_points={:s}'.format(str(connection_points)))
self.wim.check_credentials()
result = self.wim.create_connectivity_service(service_type, connection_points)
LOGGER.info('[create_connectivity_service] result={:s}'.format(str(result)))
service_uuid, conn_info = result
self.conn_info[service_uuid] = conn_info
return service_uuid
def get_connectivity_service_status(self, service_uuid):
LOGGER.info('[get_connectivity_service] service_uuid={:s}'.format(str(service_uuid)))
conn_info = self.conn_info.get(service_uuid)
if conn_info is None: raise Exception('ServiceId({:s}) not found'.format(str(service_uuid)))
LOGGER.info('[get_connectivity_service] conn_info={:s}'.format(str(conn_info)))
self.wim.check_credentials()
result = self.wim.get_connectivity_service_status(service_uuid, conn_info=conn_info)
LOGGER.info('[get_connectivity_service] result={:s}'.format(str(result)))
return result
def edit_connectivity_service(self, service_uuid, connection_points):
LOGGER.info('[edit_connectivity_service] service_uuid={:s}'.format(str(service_uuid)))
LOGGER.info('[edit_connectivity_service] connection_points={:s}'.format(str(connection_points)))
conn_info = self.conn_info.get(service_uuid)
if conn_info is None: raise Exception('ServiceId({:s}) not found'.format(str(service_uuid)))
LOGGER.info('[edit_connectivity_service] conn_info={:s}'.format(str(conn_info)))
self.wim.edit_connectivity_service(service_uuid, conn_info=conn_info, connection_points=connection_points)
def delete_connectivity_service(self, service_uuid):
LOGGER.info('[delete_connectivity_service] service_uuid={:s}'.format(str(service_uuid)))
conn_info = self.conn_info.get(service_uuid)
if conn_info is None: raise Exception('ServiceId({:s}) not found'.format(str(service_uuid)))
LOGGER.info('[delete_connectivity_service] conn_info={:s}'.format(str(conn_info)))
self.wim.check_credentials()
self.wim.delete_connectivity_service(service_uuid, conn_info=conn_info)
...@@ -55,9 +55,9 @@ class WimconnectorIETFL2VPN(SdnConnectorBase): ...@@ -55,9 +55,9 @@ class WimconnectorIETFL2VPN(SdnConnectorBase):
m["service_endpoint_id"]: m for m in self.service_endpoint_mapping m["service_endpoint_id"]: m for m in self.service_endpoint_mapping
} }
self.user = wim_account.get("user") self.user = wim_account.get("user")
self.passwd = wim_account.get("password") # replace "passwordd" -> "password" self.passwd = wim_account.get("password")
if self.user and self.passwd is not None: if self.user is not None and self.passwd is not None:
self.auth = (self.user, self.passwd) self.auth = (self.user, self.passwd)
else: else:
self.auth = None self.auth = None
......
...@@ -11,17 +11,3 @@ ...@@ -11,17 +11,3 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES
ALL_RESOURCE_KEYS = [
RESOURCE_ENDPOINTS,
RESOURCE_INTERFACES,
RESOURCE_NETWORK_INSTANCES,
]
RESOURCE_KEY_MAPPINGS = {
RESOURCE_ENDPOINTS : 'component',
RESOURCE_INTERFACES : 'interface',
RESOURCE_NETWORK_INSTANCES: 'network_instance',
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment