| # -*- coding: utf-8 -*- |
| |
| ####################################################################################### |
| # This file is part of OSM RO module |
| # |
| # Copyright ETSI Contributors and Others. |
| # |
| # 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. |
| ####################################################################################### |
| # This work has been performed in the context of the TeraFlow Project - |
| # funded by the European Commission under Grant number 101015857 through the |
| # Horizon 2020 program. |
| # Contributors: |
| # - Lluis Gifre <lluis.gifre@cttc.es> |
| # - Ricard Vilalta <ricard.vilalta@cttc.es> |
| ####################################################################################### |
| |
| """This file contains the TransportApiClient class used by the Transport API |
| (TAPI) WIM connector to interact with the underlying WIM.""" |
| |
| import requests |
| |
| from .exceptions import ( |
| WimTapiConnectivityServiceCreateFailed, |
| WimTapiConnectivityServiceDeleteFailed, |
| WimTapiConnectivityServiceGetStatusFailed, |
| WimTapiServerNotAvailable, |
| WimTapiServerRequestFailed, |
| ) |
| from .log_messages import ( |
| LOG_MSG_CREATE_REPLY, |
| LOG_MSG_CREATE_REQUEST, |
| LOG_MSG_DELETE_REPLY, |
| LOG_MSG_DELETE_REQUEST, |
| LOG_MSG_GET_STATUS_REPLY, |
| LOG_MSG_GET_STATUS_REQUEST, |
| ) |
| from .message_composers import ( |
| compose_create_request, |
| compose_delete_request, |
| ) |
| |
| DEFAULT_TIMEOUT = 30 |
| |
| SUCCESS_HTTP_CODES = { |
| requests.codes.ok, # pylint: disable=no-member |
| requests.codes.created, # pylint: disable=no-member |
| requests.codes.accepted, # pylint: disable=no-member |
| requests.codes.no_content, # pylint: disable=no-member |
| } |
| |
| RESTCONF_DATA_URL = "{:s}/restconf/data" |
| RESTCONF_OPER_URL = "{:s}/restconf/operations" |
| |
| CONTEXT_URL = RESTCONF_DATA_URL + "/tapi-common:context" |
| CTX_SIPS_URL = CONTEXT_URL + "/service-interface-point" |
| CONN_CTX_URL = CONTEXT_URL + "/tapi-connectivity:connectivity-context" |
| CONN_SVC_URL = CONN_CTX_URL + "/connectivity-service" |
| DELETE_URL = RESTCONF_OPER_URL + "/tapi-connectivity:delete-connectivity-service" |
| |
| |
| class TransportApiClient: |
| def __init__(self, logger, wim, wim_account, config) -> None: |
| self.logger = logger |
| self.wim_url = wim["wim_url"] |
| |
| user = wim_account.get("user") |
| password = wim_account.get("password") |
| self.auth = ( |
| None |
| if user is None or user == "" or password is None or password == "" |
| else (user, password) |
| ) |
| |
| self.headers = {"Content-Type": "application/json"} |
| self.timeout = int(config.get("timeout", DEFAULT_TIMEOUT)) |
| |
| def get_root_context(self): |
| context_url = CONTEXT_URL.format(self.wim_url) |
| |
| try: |
| response = requests.get( |
| context_url, auth=self.auth, headers=self.headers, timeout=self.timeout |
| ) |
| http_code = response.status_code |
| except requests.exceptions.RequestException as e: |
| raise WimTapiServerNotAvailable(str(e)) |
| |
| if http_code != 200: |
| raise WimTapiServerRequestFailed( |
| "Unexpected status code", http_code=http_code |
| ) |
| |
| return response.json() |
| |
| def get_service_interface_points(self): |
| get_sips_url = CTX_SIPS_URL.format(self.wim_url) |
| |
| try: |
| response = requests.get( |
| get_sips_url, auth=self.auth, headers=self.headers, timeout=self.timeout |
| ) |
| http_code = response.status_code |
| except requests.exceptions.RequestException as e: |
| raise WimTapiServerNotAvailable(str(e)) |
| |
| if http_code != 200: |
| raise WimTapiServerRequestFailed( |
| "Unexpected status code", http_code=http_code |
| ) |
| |
| response = response.json() |
| response = response.get("tapi-common:service-interface-point", []) |
| return {sip["uuid"]: sip for sip in response} |
| |
| def get_service_status(self, name, service_uuid): |
| self.logger.debug(LOG_MSG_GET_STATUS_REQUEST.format(name, service_uuid)) |
| |
| try: |
| services_url = CONN_SVC_URL.format(self.wim_url) |
| response = requests.get( |
| services_url, auth=self.auth, headers=self.headers, timeout=self.timeout |
| ) |
| self.logger.debug( |
| LOG_MSG_GET_STATUS_REPLY.format( |
| name, service_uuid, response.status_code, response.text |
| ) |
| ) |
| except requests.exceptions.ConnectionError as e: |
| status_code = e.response.status_code if e.response is not None else 500 |
| content = e.response.text if e.response is not None else "" |
| raise WimTapiConnectivityServiceGetStatusFailed( |
| name, service_uuid, status_code, content |
| ) |
| |
| if response.status_code not in SUCCESS_HTTP_CODES: |
| raise WimTapiConnectivityServiceGetStatusFailed( |
| name, service_uuid, response.status_code, response.text |
| ) |
| |
| json_response = response.json() |
| connectivity_services = json_response.get( |
| "tapi-connectivity:connectivity-service", [] |
| ) |
| connectivity_service = next( |
| iter( |
| [ |
| connectivity_service |
| for connectivity_service in connectivity_services |
| if connectivity_service.get("uuid") == service_uuid |
| ] |
| ), |
| None, |
| ) |
| |
| if connectivity_service is None: |
| service_status = {"sdn_status": "ERROR"} |
| else: |
| service_status = {"sdn_status": "ACTIVE"} |
| return service_status |
| |
| def create_service( |
| self, |
| name, |
| service_uuid, |
| service_endpoints, |
| bidirectional=False, |
| requested_capacity=None, |
| vlan_constraint=None, |
| ): |
| request_create = compose_create_request( |
| service_uuid, |
| service_endpoints, |
| bidirectional=bidirectional, |
| requested_capacity=requested_capacity, |
| vlan_constraint=vlan_constraint, |
| ) |
| self.logger.debug( |
| LOG_MSG_CREATE_REQUEST.format(name, service_uuid, str(request_create)) |
| ) |
| |
| try: |
| create_url = CONN_CTX_URL.format(self.wim_url) |
| response = requests.post( |
| create_url, headers=self.headers, json=request_create, auth=self.auth |
| ) |
| self.logger.debug( |
| LOG_MSG_CREATE_REPLY.format( |
| name, service_uuid, response.status_code, response.text |
| ) |
| ) |
| except requests.exceptions.ConnectionError as e: |
| status_code = e.response.status_code if e.response is not None else 500 |
| content = e.response.text if e.response is not None else "" |
| raise WimTapiConnectivityServiceCreateFailed( |
| name, service_uuid, status_code, content |
| ) |
| |
| if response.status_code not in SUCCESS_HTTP_CODES: |
| raise WimTapiConnectivityServiceCreateFailed( |
| name, service_uuid, response.status_code, response.text |
| ) |
| |
| def delete_service(self, name, service_uuid): |
| request_delete = compose_delete_request(service_uuid) |
| self.logger.debug( |
| LOG_MSG_DELETE_REQUEST.format(name, service_uuid, str(request_delete)) |
| ) |
| |
| try: |
| delete_url = DELETE_URL.format(self.wim_url) |
| response = requests.post( |
| delete_url, headers=self.headers, json=request_delete, auth=self.auth |
| ) |
| self.logger.debug( |
| LOG_MSG_DELETE_REPLY.format( |
| name, service_uuid, response.status_code, response.text |
| ) |
| ) |
| except requests.exceptions.ConnectionError as e: |
| status_code = e.response.status_code if e.response is not None else 500 |
| content = e.response.text if e.response is not None else "" |
| raise WimTapiConnectivityServiceDeleteFailed( |
| name, service_uuid, status_code, content |
| ) |
| |
| if response.status_code not in SUCCESS_HTTP_CODES: |
| raise WimTapiConnectivityServiceDeleteFailed( |
| name, service_uuid, response.status_code, response.text |
| ) |