X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=blobdiff_plain;f=RO-SDN-dpb%2Fosm_rosdn_dpb%2Fwimconn_dpb.py;h=e08cdfdf7cf3cd247c8b41bdce837eb735f75609;hp=dc717e57b58621a304f3bf2f44246df9c9f52638;hb=80135b928ab442c38898750b4751480205b4affc;hpb=e493e9b91720e5116e00b4c06cf66c767bccce2f diff --git a/RO-SDN-dpb/osm_rosdn_dpb/wimconn_dpb.py b/RO-SDN-dpb/osm_rosdn_dpb/wimconn_dpb.py index dc717e57..e08cdfdf 100755 --- a/RO-SDN-dpb/osm_rosdn_dpb/wimconn_dpb.py +++ b/RO-SDN-dpb/osm_rosdn_dpb/wimconn_dpb.py @@ -30,17 +30,20 @@ import logging import paramiko import requests import struct + # import sys from osm_ro_plugin.sdnconn import SdnConnectorBase, SdnConnectorError -class DpbSshInterface(): +class DpbSshInterface: """ Communicate with the DPB via SSH """ __LOGGER_NAME_EXT = ".ssh" __FUNCTION_MAP_POS = 1 - def __init__(self, username, password, wim_url, wim_port, network, auth_data, logger_name): + def __init__( + self, username, password, wim_url, wim_port, network, auth_data, logger_name + ): self.logger = logging.getLogger(logger_name + self.__LOGGER_NAME_EXT) self.__username = username self.__password = password @@ -62,41 +65,44 @@ class DpbSshInterface(): """post request to dpb via ssh notes: - - session_id need only be unique per ssh session, thus is currently safe if + - session_id need only be unique per ssh session, thus is currently safe if ro is restarted """ self._check_connection() + if data is None: data = {} - url_ext_info = url_params.split('/') + + url_ext_info = url_params.split("/") + for i in range(0, len(url_ext_info)): if url_ext_info[i] == "service": - data["service-id"] = int(url_ext_info[i+1]) + data["service-id"] = int(url_ext_info[i + 1]) + data["type"] = function[self.__FUNCTION_MAP_POS] data = { "session": self.__session_id, - "content": data + "content": data, } self.__session_id += 1 try: data = json.dumps(data).encode("utf-8") - data_packed = struct.pack( - ">I" + str(len(data)) + "s", len(data), data) + data_packed = struct.pack(">I" + str(len(data)) + "s", len(data), data) self.__stdin.write(data_packed) self.logger.debug("Data sent to DPB via SSH") except Exception as e: - raise SdnConnectorError( - "Failed to write via SSH | text: {}".format(e), 500) + raise SdnConnectorError("Failed to write via SSH | text: {}".format(e), 500) try: data_len = struct.unpack(">I", self.__stdout.read(4))[0] - data = struct.unpack(str(data_len) + "s", - self.__stdout.read(data_len))[0] + data = struct.unpack(str(data_len) + "s", self.__stdout.read(data_len))[0] + return json.loads(data).get("content", {}) except Exception as e: raise SdnConnectorError( - "Could not get response from WIM | text: {}".format(e), 500) + "Could not get response from WIM | text: {}".format(e), 500 + ) def get(self, function, url_params=""): raise SdnConnectorError("SSH Get not implemented", 500) @@ -104,69 +110,87 @@ class DpbSshInterface(): def __create_client(self): ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + return ssh_client def __connect(self): private_key = None password = None + if self.__auth_data.get("auth_type", "PASS") == "KEY": private_key = self.__build_private_key_obj() + if self.__auth_data.get("auth_type", "PASS") == "PASS": password = self.__password try: - self.__ssh_client.connect(hostname=self.__url, - port=self.__port, - username=self.__username, - password=password, - pkey=private_key, - look_for_keys=False, - compress=False) + self.__ssh_client.connect( + hostname=self.__url, + port=self.__port, + username=self.__username, + password=password, + pkey=private_key, + look_for_keys=False, + compress=False, + ) stdin, stdout, stderr = self.__ssh_client.exec_command( - command=self.__network) + command=self.__network + ) except paramiko.BadHostKeyException as e: raise SdnConnectorError( - "Could not add SSH host key | text: {}".format(e), 500) + "Could not add SSH host key | text: {}".format(e), 500 + ) except paramiko.AuthenticationException as e: raise SdnConnectorError( - "Could not authorize SSH connection | text: {}".format(e), 400) + "Could not authorize SSH connection | text: {}".format(e), 400 + ) except paramiko.SSHException as e: raise SdnConnectorError( - "Could not establish the SSH connection | text: {}".format(e), 500) + "Could not establish the SSH connection | text: {}".format(e), 500 + ) except Exception as e: raise SdnConnectorError( - "Unknown error occurred when connecting via SSH | text: {}".format(e), 500) + "Unknown error occurred when connecting via SSH | text: {}".format(e), + 500, + ) try: data_len = struct.unpack(">I", stdout.read(4))[0] - data = json.loads(struct.unpack( - str(data_len) + "s", stdout.read(data_len))[0]) + data = json.loads( + struct.unpack(str(data_len) + "s", stdout.read(data_len))[0] + ) except Exception as e: raise SdnConnectorError( - "Failed to get response from DPB | text: {}".format(e), 500) + "Failed to get response from DPB | text: {}".format(e), 500 + ) + if "error" in data: - raise SdnConnectorError( - data.get("msg", data.get("error", "ERROR")), 500) + raise SdnConnectorError(data.get("msg", data.get("error", "ERROR")), 500) + self.logger.info("SSH connection to DPB established OK") + return stdin, stdout def __build_private_key_obj(self): try: - with open(self.__auth_data.get("key_file"), 'r') as key_file: + with open(self.__auth_data.get("key_file"), "r") as key_file: if self.__auth_data.get("key_type") == "RSA": - return paramiko.RSAKey.from_private_key(key_file, - password=self.__auth_data.get("key_pass", None)) + return paramiko.RSAKey.from_private_key( + key_file, password=self.__auth_data.get("key_pass", None) + ) elif self.__auth_data.get("key_type") == "ECDSA": - return paramiko.ECDSAKey.from_private_key(key_file, - password=self.__auth_data.get("key_pass", None)) + return paramiko.ECDSAKey.from_private_key( + key_file, password=self.__auth_data.get("key_pass", None) + ) else: raise SdnConnectorError("Key type not supported", 400) except Exception as e: raise SdnConnectorError( - "Could not load private SSH key | text: {}".format(e), 500) + "Could not load private SSH key | text: {}".format(e), 500 + ) -class DpbRestInterface(): +class DpbRestInterface: """ Communicate with the DPB via the REST API """ __LOGGER_NAME_EXT = ".rest" @@ -175,31 +199,34 @@ class DpbRestInterface(): def __init__(self, wim_url, wim_port, network, logger_name): self.logger = logging.getLogger(logger_name + self.__LOGGER_NAME_EXT) self.__base_url = "http://{}:{}/network/{}".format( - wim_url, str(wim_port), network) + wim_url, str(wim_port), network + ) self.logger.info("REST defined OK") def post(self, function, url_params="", data=None, get_response=True): - url = self.__base_url + url_params + \ - "/" + function[self.__FUNCTION_MAP_POS] + url = self.__base_url + url_params + "/" + function[self.__FUNCTION_MAP_POS] + try: self.logger.info(data) response = requests.post(url, json=data) + if response.status_code != 200: raise SdnConnectorError( - "REST request failed (status code: {})".format(response.status_code)) + "REST request failed (status code: {})".format(response.status_code) + ) + if get_response: return response.json() except Exception as e: - raise SdnConnectorError( - "REST request failed | text: {}".format(e), 500) + raise SdnConnectorError("REST request failed | text: {}".format(e), 500) def get(self, function, url_params=""): url = self.__base_url + url_params + function[self.__FUNCTION_MAP_POS] + try: return requests.get(url) except Exception as e: - raise SdnConnectorError( - "REST request failed | text: {}".format(e), 500) + raise SdnConnectorError("REST request failed | text: {}".format(e), 500) class DpbConnector(SdnConnectorBase): @@ -210,10 +237,7 @@ class DpbConnector(SdnConnectorBase): __SUPPORTED_CONNECTION_TYPES = ["REST", "SSH"] __SUPPORTED_SSH_AUTH_TYPES = ["KEY", "PASS"] __SUPPORTED_SSH_KEY_TYPES = ["ECDSA", "RSA"] - __STATUS_MAP = { - "ACTIVE": "ACTIVE", - "ACTIVATING": "BUILD", - "FAILED": "ERROR"} + __STATUS_MAP = {"ACTIVE": "ACTIVE", "ACTIVATING": "BUILD", "FAILED": "ERROR"} __ACTIONS_MAP = { "CREATE": ("create-service", "new-service"), "DEFINE": ("define", "define-service"), @@ -222,7 +246,7 @@ class DpbConnector(SdnConnectorBase): "DEACTIVATE": ("deactivate", "deactivate-service"), "CHECK": ("await-status", "await-service-status"), "GET": ("services", "NOT IMPLEMENTED"), - "RESET": ("reset", "NOT IMPLEMENTED") + "RESET": ("reset", "NOT IMPLEMENTED"), } def __init__(self, wim, wim_account, config): @@ -237,137 +261,201 @@ class DpbConnector(SdnConnectorBase): self.__password = self.__account.get("passwd", "") self.__username = self.__account.get("user", "") self.__network = self.__cli_config.get("network", "") - self.__connection_type = self.__cli_config.get( - "connection_type", "REST") + self.__connection_type = self.__cli_config.get("connection_type", "REST") self.__port = self.__cli_config.get( - "port", (80 if self.__connection_type == "REST" else 22)) + "port", (80 if self.__connection_type == "REST" else 22) + ) self.__ssh_auth = self.__cli_config.get("ssh_auth", None) if self.__connection_type == "SSH": - interface = DpbSshInterface(self.__username, - self.__password, - self.__url, - self.__port, - self.__network, - self.__ssh_auth, - self.__LOGGER_NAME) + interface = DpbSshInterface( + self.__username, + self.__password, + self.__url, + self.__port, + self.__network, + self.__ssh_auth, + self.__LOGGER_NAME, + ) elif self.__connection_type == "REST": - interface = DpbRestInterface(self.__url, - self.__port, - self.__network, - self.__LOGGER_NAME) + interface = DpbRestInterface( + self.__url, self.__port, self.__network, self.__LOGGER_NAME + ) else: raise SdnConnectorError( - "Connection type not supported (must be SSH or REST)", 400) + "Connection type not supported (must be SSH or REST)", 400 + ) + self.__post = interface.post self.__get = interface.get self.logger.info("DPB WimConn Init OK") def create_connectivity_service(self, service_type, connection_points, **kwargs): self.logger.info("Creating a connectivity service") + try: response = self.__post(self.__ACTIONS_MAP.get("CREATE")) + if "service-id" in response: service_id = int(response.get("service-id")) self.logger.debug("created service id {}".format(service_id)) else: raise SdnConnectorError( - "Invalid create service response (could be an issue with the DPB)", 500) + "Invalid create service response (could be an issue with the DPB)", + 500, + ) + data = {"segment": []} + for point in connection_points: - data["segment"].append({ - "terminal-name": point.get("service_endpoint_id"), - "label": int((point.get("service_endpoint_encapsulation_info")).get("vlan")), - "ingress-bw": 10.0, - "egress-bw": 10.0}) + data["segment"].append( + { + "terminal-name": point.get("service_endpoint_id"), + "label": int( + (point.get("service_endpoint_encapsulation_info")).get( + "vlan" + ) + ), + "ingress-bw": 10.0, + "egress-bw": 10.0, + } + ) # "ingress-bw": (bandwidth.get(point.get("service_endpoint_id"))).get("ingress"), # "egress-bw": (bandwidth.get(point.get("service_endpoint_id"))).get("egress")} - self.__post(self.__ACTIONS_MAP.get("DEFINE"), - "/service/"+str(service_id), data, get_response=False) - self.__post(self.__ACTIONS_MAP.get("ACTIVATE"), - "/service/"+str(service_id), get_response=False) - self.logger.debug( - "Created connectivity service id:{}".format(service_id)) + self.__post( + self.__ACTIONS_MAP.get("DEFINE"), + "/service/" + str(service_id), + data, + get_response=False, + ) + self.__post( + self.__ACTIONS_MAP.get("ACTIVATE"), + "/service/" + str(service_id), + get_response=False, + ) + self.logger.debug("Created connectivity service id:{}".format(service_id)) + return (str(service_id), None) except Exception as e: raise SdnConnectorError( - "Connectivity service could not be made | text: {}".format(e), 500) + "Connectivity service could not be made | text: {}".format(e), 500 + ) def get_connectivity_service_status(self, service_uuid, conn_info=None): self.logger.info( - "Checking connectivity service status id:{}".format(service_uuid)) - data = { - "timeout-millis": 10000, - "acceptable": ["ACTIVE", "FAILED"] - } + "Checking connectivity service status id:{}".format(service_uuid) + ) + data = {"timeout-millis": 10000, "acceptable": ["ACTIVE", "FAILED"]} + try: - response = self.__post(self.__ACTIONS_MAP.get( - "CHECK"), "/service/"+service_uuid, data) + response = self.__post( + self.__ACTIONS_MAP.get("CHECK"), + "/service/" + service_uuid, + data, + ) + if "status" in response: status = response.get("status", None) self.logger.info("CHECKED CONNECTIVITY SERVICE STATUS") + return {"wim_status": self.__STATUS_MAP.get(status)} else: raise SdnConnectorError( - "Invalid status check response (could be an issue with the DPB)", 500) + "Invalid status check response (could be an issue with the DPB)", + 500, + ) except Exception as e: raise SdnConnectorError( - "Failed to check service status | text: {}".format(e), 500) + "Failed to check service status | text: {}".format(e), 500 + ) def delete_connectivity_service(self, service_uuid, conn_info=None): - self.logger.info( - "Deleting connectivity service id: {}".format(service_uuid)) + self.logger.info("Deleting connectivity service id: {}".format(service_uuid)) + try: - self.__post(self.__ACTIONS_MAP.get("RELEASE"), - "/service/"+service_uuid, get_response=False) + self.__post( + self.__ACTIONS_MAP.get("RELEASE"), + "/service/" + service_uuid, + get_response=False, + ) except Exception as e: raise SdnConnectorError( - "Could not delete service id:{} (could be an issue with the DPB): {}".format(service_uuid, e), 500) - self.logger.debug( - "Deleted connectivity service id:{}".format(service_uuid)) + "Could not delete service id:{} (could be an issue with the DPB): {}".format( + service_uuid, e + ), + 500, + ) + + self.logger.debug("Deleted connectivity service id:{}".format(service_uuid)) + return None - def edit_connectivity_service(self, service_uuid, conn_info=None, connection_points=None, **kwargs): - self.logger.info( - "Editing connectivity service id: {}".format(service_uuid)) - data = { - "timeout-millis": 10000, - "acceptable": ["DORMANT"] - } + def edit_connectivity_service( + self, service_uuid, conn_info=None, connection_points=None, **kwargs + ): + self.logger.info("Editing connectivity service id: {}".format(service_uuid)) + data = {"timeout-millis": 10000, "acceptable": ["DORMANT"]} + try: - self.__post(self.__ACTIONS_MAP.get("RESET"), - "/service/"+service_uuid, get_response=False) - response = self.__post(self.__ACTIONS_MAP.get( - "CHECK"), "/service/"+service_uuid, data) + self.__post( + self.__ACTIONS_MAP.get("RESET"), + "/service/" + service_uuid, + get_response=False, + ) + response = self.__post( + self.__ACTIONS_MAP.get("CHECK"), + "/service/" + service_uuid, + data, + ) + if "status" in response: - self.logger.debug( - "Connectivity service {} reset".format(service_uuid)) + self.logger.debug("Connectivity service {} reset".format(service_uuid)) else: raise SdnConnectorError( - "Invalid status check response (could be an issue with the DPB)", 500) + "Invalid status check response (could be an issue with the DPB)", + 500, + ) except Exception as e: - raise SdnConnectorError( - "Failed to reset service | text: {}".format(e), 500) + raise SdnConnectorError("Failed to reset service | text: {}".format(e), 500) + try: data = {"segment": []} + for point in connection_points: - data["segment"].append({ - "terminal-name": point.get("service_endpoint_id"), - "label": int((point.get("service_endpoint_encapsulation_info")).get("vlan")), - "ingress-bw": 10.0, - "egress-bw": 10.0}) + data["segment"].append( + { + "terminal-name": point.get("service_endpoint_id"), + "label": int( + (point.get("service_endpoint_encapsulation_info")).get( + "vlan" + ) + ), + "ingress-bw": 10.0, + "egress-bw": 10.0, + } + ) # "ingress-bw": (bandwidth.get(point.get("service_endpoint_id"))).get("ingress"), # "egress-bw": (bandwidth.get(point.get("service_endpoint_id"))).get("egress")} - self.__post(self.__ACTIONS_MAP.get("DEFINE"), "/service/" + - str(service_uuid), data, get_response=False) - self.__post(self.__ACTIONS_MAP.get("ACTIVATE"), - "/service/"+str(service_uuid), get_response=False) + + self.__post( + self.__ACTIONS_MAP.get("DEFINE"), + "/service/" + str(service_uuid), + data, + get_response=False, + ) + self.__post( + self.__ACTIONS_MAP.get("ACTIVATE"), + "/service/" + str(service_uuid), + get_response=False, + ) except Exception as e: raise SdnConnectorError( - "Failed to edit connectivity service | text: {}".format(e), 500) - self.logger.debug( - "Edited connectivity service {}".format(service_uuid)) + "Failed to edit connectivity service | text: {}".format(e), 500 + ) + + self.logger.debug("Edited connectivity service {}".format(service_uuid)) + return conn_info def __check_service(self, serv_type, points, kwargs):