From b43796928c8198b8542e69b2dd06b0368c5d8799 Mon Sep 17 00:00:00 2001 From: gifrerenom <lluis.gifre@cttc.es> Date: Thu, 18 Jan 2024 16:00:25 +0000 Subject: [PATCH] Device - IETF ACTN Driver: - Minor code improvements in EthtServiceHandler, OsuTunnelHandler, and RestApiClient --- .../ietf_actn/handlers/EthtServiceHandler.py | 25 +++++++++++--- .../ietf_actn/handlers/OsuTunnelHandler.py | 27 +++++++++++---- .../ietf_actn/handlers/RestApiClient.py | 34 ++++++++++++------- 3 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/device/service/drivers/ietf_actn/handlers/EthtServiceHandler.py b/src/device/service/drivers/ietf_actn/handlers/EthtServiceHandler.py index 66734199a..ff0dadbbc 100644 --- a/src/device/service/drivers/ietf_actn/handlers/EthtServiceHandler.py +++ b/src/device/service/drivers/ietf_actn/handlers/EthtServiceHandler.py @@ -14,7 +14,7 @@ import enum, logging from typing import Dict, List, Optional, Tuple, Union -from .RestApiClient import RestApiClient +from .RestApiClient import HTTP_STATUS_CREATED, HTTP_STATUS_NO_CONTENT, HTTP_STATUS_OK, RestApiClient LOGGER = logging.getLogger(__name__) @@ -110,11 +110,26 @@ class EthtServiceHandler: def __init__(self, rest_api_client : RestApiClient) -> None: self._rest_api_client = rest_api_client self._object_name = 'EthtService' - self._subpath_url = '/ietf-eth-tran-service:etht-svc/etht-svc-instances' + self._subpath_url = '/ietf-eth-tran-service:etht-svc' + + def _rest_api_get(self, filters : List[Tuple[str, str]]) -> Union[Dict, List]: + return self._rest_api_client.get( + self._object_name, self._subpath_url, filters, 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_url, data, expected_http_status={HTTP_STATUS_CREATED} + ) + + def _rest_api_delete(self, filters : List[Tuple[str, str]]) -> bool: + return self._rest_api_client.delete( + self._object_name, self._subpath_url, filters, expected_http_status={HTTP_STATUS_NO_CONTENT} + ) def get(self, etht_service_name : Optional[str] = None) -> Union[Dict, List]: filters = [] if etht_service_name is None else [('etht-svc-name', etht_service_name)] - data = self._rest_api_client.get(self._object_name, self._subpath_url, filters) + data = self._rest_api_get(filters) if not isinstance(data, dict): return ValueError('data should be a dict') if 'ietf-eth-tran-service:etht-svc' not in data: @@ -194,8 +209,8 @@ class EthtServiceHandler: src_static_routes=src_static_routes, dst_static_routes=dst_static_routes ) - return self._rest_api_client.update(self._object_name, self._subpath_url, data) + return self._rest_api_update(data) def delete(self, etht_service_name : str) -> bool: filters = [('etht-svc-name', etht_service_name)] - return self._rest_api_client.delete(self._object_name, self._subpath_url, filters) + return self._rest_api_delete(filters) diff --git a/src/device/service/drivers/ietf_actn/handlers/OsuTunnelHandler.py b/src/device/service/drivers/ietf_actn/handlers/OsuTunnelHandler.py index 57395de4f..2cb6f46f0 100644 --- a/src/device/service/drivers/ietf_actn/handlers/OsuTunnelHandler.py +++ b/src/device/service/drivers/ietf_actn/handlers/OsuTunnelHandler.py @@ -13,8 +13,8 @@ # limitations under the License. import enum, logging -from typing import Dict, List, Optional, Union -from .RestApiClient import RestApiClient +from typing import Dict, List, Optional, Tuple, Union +from .RestApiClient import HTTP_STATUS_CREATED, HTTP_STATUS_NO_CONTENT, HTTP_STATUS_OK, RestApiClient LOGGER = logging.getLogger(__name__) @@ -84,11 +84,26 @@ class OsuTunnelHandler: def __init__(self, rest_api_client : RestApiClient) -> None: self._rest_api_client = rest_api_client self._object_name = 'OsuTunnel' - self._subpath_url = '/ietf-te:tunnel' + self._subpath_url = '/ietf-te:te/tunnels' + + def _rest_api_get(self, filters : List[Tuple[str, str]]) -> Union[Dict, List]: + return self._rest_api_client.get( + self._object_name, self._subpath_url, filters, 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_url, data, expected_http_status={HTTP_STATUS_CREATED} + ) + + def _rest_api_delete(self, filters : List[Tuple[str, str]]) -> bool: + return self._rest_api_client.delete( + self._object_name, self._subpath_url, filters, expected_http_status={HTTP_STATUS_NO_CONTENT} + ) def get(self, osu_tunnel_name : Optional[str] = None) -> Union[Dict, List]: filters = [] if osu_tunnel_name is None else [('name', osu_tunnel_name)] - data = self._rest_api_client.get(self._object_name, self._subpath_url, filters) + data = self._rest_api_get(filters) if not isinstance(data, dict): return ValueError('data should be a dict') if 'ietf-te:tunnel' not in data: return ValueError('data does not contain key "ietf-te:tunnel"') @@ -149,8 +164,8 @@ class OsuTunnelHandler: odu_type, osuflex_number, delay, bidirectional=bidirectional ) - return self._rest_api_client.update(self._object_name, self._subpath_url, data) + return self._rest_api_update(data) def delete(self, osu_tunnel_name : str) -> bool: filters = [('name', osu_tunnel_name)] - return self._rest_api_client.delete(self._object_name, self._subpath_url, filters) + return self._rest_api_delete(filters) diff --git a/src/device/service/drivers/ietf_actn/handlers/RestApiClient.py b/src/device/service/drivers/ietf_actn/handlers/RestApiClient.py index 15321f7a0..7154dfc48 100644 --- a/src/device/service/drivers/ietf_actn/handlers/RestApiClient.py +++ b/src/device/service/drivers/ietf_actn/handlers/RestApiClient.py @@ -14,20 +14,25 @@ import copy, json, logging, requests from requests.auth import HTTPBasicAuth -from typing import Any, Dict, List, Tuple, Union +from typing import Any, Dict, List, Set, Tuple, Union LOGGER = logging.getLogger(__name__) -DEFAULT_BASE_URL = '/restconf/data' -DEFAULT_SCHEMA = 'http' +DEFAULT_BASE_URL = '/restconf/v2/data' +DEFAULT_SCHEMA = 'https' DEFAULT_TIMEOUT = 120 DEFAULT_VERIFY = False +HTTP_STATUS_OK = 200 +HTTP_STATUS_CREATED = 201 +HTTP_STATUS_ACCEPTED = 202 +HTTP_STATUS_NO_CONTENT = 204 + HTTP_OK_CODES = { - 200, # OK - 201, # Created - 202, # Accepted - 204, # No Content + HTTP_STATUS_OK, + HTTP_STATUS_CREATED, + HTTP_STATUS_ACCEPTED, + HTTP_STATUS_NO_CONTENT, } class RestApiClient: @@ -44,7 +49,8 @@ class RestApiClient: self._verify = int(settings.get('verify', DEFAULT_VERIFY )) def get( - self, object_name : str, url : str, filters : List[Tuple[str, str]] + self, object_name : str, url : str, filters : List[Tuple[str, str]], + expected_http_status : Set[int] = {HTTP_STATUS_OK} ) -> Union[Dict, List]: str_filters = ''.join([ '[{:s}={:s}]'.format(filter_field, filter_value) @@ -59,7 +65,7 @@ class RestApiClient: ) LOGGER.info(' Response: {:s}'.format(str(response))) - if response.status_code in HTTP_OK_CODES: return json.loads(response.content) + if response.status_code in expected_http_status: return json.loads(response.content) MSG = 'Could not get {:s}({:s}): status_code={:s} reply={:s}' msg = MSG.format(str(object_name), str(str_filters), str(response.status_code), str(response)) @@ -67,7 +73,8 @@ class RestApiClient: return Exception(msg) def update( - self, object_name : str, url : str, data : Dict, headers : Dict[str, Any] = dict() + self, object_name : str, url : str, data : Dict, headers : Dict[str, Any] = dict(), + expected_http_status : Set[int] = HTTP_OK_CODES ) -> bool: headers = copy.deepcopy(headers) if 'content-type' not in {header_name.lower() for header_name in headers.keys()}: @@ -81,14 +88,15 @@ class RestApiClient: ) LOGGER.info(' Response: {:s}'.format(str(response))) - if response.status_code in HTTP_OK_CODES: return True + if response.status_code in expected_http_status: return True MSG = 'Could not create/update {:s}({:s}): status_code={:s} reply={:s}' LOGGER.error(MSG.format(str(object_name), str(data), str(response.status_code), str(response))) return False def delete( - self, object_name : str, url : str, filters : List[Tuple[str, str]] + self, object_name : str, url : str, filters : List[Tuple[str, str]], + expected_http_status : Set[int] = HTTP_OK_CODES ) -> bool: str_filters = ''.join([ '[{:s}={:s}]'.format(filter_field, filter_value) @@ -103,7 +111,7 @@ class RestApiClient: ) LOGGER.info(' Response: {:s}'.format(str(response))) - if response.status_code in HTTP_OK_CODES: return True + if response.status_code in expected_http_status: return True MSG = 'Could not delete {:s}({:s}): status_code={:s} reply={:s}' LOGGER.error(MSG.format(str(object_name), str(str_filters), str(response.status_code), str(response))) -- GitLab