Fixing bug 1437
[osm/RO.git] / RO-SDN-arista_cloudvision / osm_rosdn_arista_cloudvision / wimconn_arista.py
index 37f4c58..e72a082 100644 (file)
@@ -26,7 +26,7 @@
 #
 # This work has been performed in the context of Arista Telefonica OSM PoC.
 ##
 #
 # This work has been performed in the context of Arista Telefonica OSM PoC.
 ##
-from osm_ro.wim.sdnconn import SdnConnectorBase, SdnConnectorError
+from osm_ro_plugin.sdnconn import SdnConnectorBase, SdnConnectorError
 import re
 import socket
 # Required by compare function
 import re
 import socket
 # Required by compare function
@@ -38,11 +38,10 @@ import difflib
 import logging
 import uuid
 from enum import Enum
 import logging
 import uuid
 from enum import Enum
-from requests import RequestException
-
+from requests import RequestException, ConnectionError, ConnectTimeout, Timeout
 from cvprac.cvp_client import CvpClient
 from cvprac.cvp_api import CvpApi
 from cvprac.cvp_client import CvpClient
 from cvprac.cvp_api import CvpApi
-from cvprac.cvp_client_errors import CvpLoginError,  CvpSessionLogOutError, CvpApiError
+from cvprac.cvp_client_errors import CvpLoginError, CvpSessionLogOutError, CvpApiError
 from cvprac import __version__ as cvprac_version
 
 from osm_rosdn_arista_cloudvision.aristaConfigLet import AristaSDNConfigLet
 from cvprac import __version__ as cvprac_version
 
 from osm_rosdn_arista_cloudvision.aristaConfigLet import AristaSDNConfigLet
@@ -50,15 +49,16 @@ from osm_rosdn_arista_cloudvision.aristaTask import AristaCVPTask
 
 
 class SdnError(Enum):
 
 
 class SdnError(Enum):
-    UNREACHABLE = 'Unable to reach the WIM.',
+    UNREACHABLE = 'Unable to reach the WIM url, connect error.',
+    TIMEOUT = 'Unable to reach the WIM url, timeout.',
     VLAN_INCONSISTENT = \
         'VLAN value inconsistent between the connection points',
     VLAN_NOT_PROVIDED = 'VLAN value not provided',
     CONNECTION_POINTS_SIZE = \
         'Unexpected number of connection points: 2 expected.',
     ENCAPSULATION_TYPE = \
     VLAN_INCONSISTENT = \
         'VLAN value inconsistent between the connection points',
     VLAN_NOT_PROVIDED = 'VLAN value not provided',
     CONNECTION_POINTS_SIZE = \
         'Unexpected number of connection points: 2 expected.',
     ENCAPSULATION_TYPE = \
-        'Unexpected service_endpoint_encapsulation_type. \
-         Only "dotq1" is accepted.',
+        'Unexpected service_endpoint_encapsulation_type. \
+        'Only "dotq1" is accepted.',
     BANDWIDTH = 'Unable to get the bandwidth.',
     STATUS = 'Unable to get the status for the service.',
     DELETE = 'Unable to delete service.',
     BANDWIDTH = 'Unable to get the bandwidth.',
     STATUS = 'Unable to get the status for the service.',
     DELETE = 'Unable to delete service.',
@@ -103,7 +103,7 @@ class AristaSdnConnector(SdnConnectorBase):
     __ELINE_num_connection_points = 2
     __supported_service_types = ["ELINE", "ELAN"]
     __supported_encapsulation_types = ["dot1q"]
     __ELINE_num_connection_points = 2
     __supported_service_types = ["ELINE", "ELAN"]
     __supported_encapsulation_types = ["dot1q"]
-    __WIM_LOGGER = 'openmano.sdnconn.arista'
+    __WIM_LOGGER = 'ro.sdn.arista'
     __SERVICE_ENDPOINT_MAPPING = 'service_endpoint_mapping'
     __ENCAPSULATION_TYPE_PARAM = "service_endpoint_encapsulation_type"
     __ENCAPSULATION_INFO_PARAM = "service_endpoint_encapsulation_info"
     __SERVICE_ENDPOINT_MAPPING = 'service_endpoint_mapping'
     __ENCAPSULATION_TYPE_PARAM = "service_endpoint_encapsulation_type"
     __ENCAPSULATION_INFO_PARAM = "service_endpoint_encapsulation_info"
@@ -135,7 +135,6 @@ class AristaSdnConnector(SdnConnectorBase):
     _VLAN_MLAG = "VLAN-MLAG"
     _VXLAN_MLAG = "VXLAN-MLAG"
 
     _VLAN_MLAG = "VLAN-MLAG"
     _VXLAN_MLAG = "VXLAN-MLAG"
 
-
     def __init__(self, wim, wim_account, config=None, logger=None):
         """
 
     def __init__(self, wim, wim_account, config=None, logger=None):
         """
 
@@ -145,19 +144,19 @@ class AristaSdnConnector(SdnConnectorBase):
         :param config: (dict or None): Particular information of plugin. These keys if present have a common meaning:
             'mapping_not_needed': (bool) False by default or if missing, indicates that mapping is not needed.
             'service_endpoint_mapping': (list) provides the internal endpoint mapping. The meaning is:
         :param config: (dict or None): Particular information of plugin. These keys if present have a common meaning:
             'mapping_not_needed': (bool) False by default or if missing, indicates that mapping is not needed.
             'service_endpoint_mapping': (list) provides the internal endpoint mapping. The meaning is:
-                KEY                    meaning for WIM                 meaning for SDN assist
+                KEY                     meaning for WIM                meaning for SDN assist
                 --------                --------                    --------
                 --------                --------                    --------
-                device_id                      pop_switch_dpid                 compute_id
-                device_interface_id            pop_switch_port                 compute_pci_address
-                service_endpoint_id        wan_service_endpoint_id     SDN_service_endpoint_id
-                service_mapping_info   wan_service_mapping_info    SDN_service_mapping_info
-                    contains extra information if needed. Text in Yaml format
-                switch_dpid                    wan_switch_dpid                 SDN_switch_dpid
-                switch_port                    wan_switch_port                 SDN_switch_port
+                device_id               pop_switch_dpid             compute_id
+                device_interface_id     pop_switch_port             compute_pci_address
+                service_endpoint_id     wan_service_endpoint_id     SDN_service_endpoint_id
+                service_mapping_info    wan_service_mapping_info    SDN_service_mapping_info
+                contains extra information if needed. Text in Yaml format
+                switch_dpid             wan_switch_dpid             SDN_switch_dpid
+                switch_port             wan_switch_port             SDN_switch_port
                 datacenter_id           vim_account                 vim_account
                 id: (internal, do not use)
                 wim_id: (internal, do not use)
                 datacenter_id           vim_account                 vim_account
                 id: (internal, do not use)
                 wim_id: (internal, do not use)
-        :param logger (logging.Logger): optional logger object. If none is passed 'openmano.sdn.sdnconn' is used.
+        :param logger (logging.Logger): optional logger object. If none is passed 'ro.sdn.sdnconn' is used.
         """
         self.__regex = re.compile(
             r'^(?:http|ftp)s?://'  # http:// or https://
         """
         self.__regex = re.compile(
             r'^(?:http|ftp)s?://'  # http:// or https://
@@ -189,14 +188,20 @@ class AristaSdnConnector(SdnConnectorBase):
         try:
             self.__load_topology()
             self.__load_switches()
         try:
             self.__load_topology()
             self.__load_switches()
+        except (ConnectTimeout, Timeout) as ct:
+            raise SdnConnectorError(message=SdnError.TIMEOUT + " " + str(ct), http_code=408)
+        except ConnectionError as ce:
+            raise SdnConnectorError(message=SdnError.UNREACHABLE + " " + str(ce), http_code=404)
         except SdnConnectorError as sc:
             raise sc
         except SdnConnectorError as sc:
             raise sc
+        except CvpLoginError as le:
+            raise SdnConnectorError(message=le.msg, http_code=500) from le
         except Exception as e:
         except Exception as e:
-            raise SdnConnectorError(message="Unable to load switches from CVP",
+            raise SdnConnectorError(message="Unable to load switches from CVP" + " " + str(e),
                                     http_code=500) from e
         self.logger.debug("Using topology {} in Arista Leaf switches: {}".format(
                                     http_code=500) from e
         self.logger.debug("Using topology {} in Arista Leaf switches: {}".format(
-                self.topology,
-                self.delete_keys_from_dict(self.switches, ('passwd',))))
+            self.topology,
+            self.delete_keys_from_dict(self.switches, ('passwd',))))
         self.clC = AristaSDNConfigLet(self.topology)
 
     def __load_topology(self):
         self.clC = AristaSDNConfigLet(self.topology)
 
     def __load_topology(self):
@@ -255,7 +260,7 @@ class AristaSdnConnector(SdnConnectorBase):
                     self.switches[cs].update(cs_content)
 
         # Load the rest of the data
                     self.switches[cs].update(cs_content)
 
         # Load the rest of the data
-        if self.client == None:
+        if self.client is None:
             self.client = self.__connect()
         self.__load_inventory()
         if not self.switches:
             self.client = self.__connect()
         self.__load_inventory()
         if not self.switches:
@@ -348,19 +353,19 @@ class AristaSdnConnector(SdnConnectorBase):
         for testing the access to CloudVision API
         """
         try:
         for testing the access to CloudVision API
         """
         try:
-            if self.client == None:
+            if self.client is None:
                 self.client = self.__connect()
             result = self.client.api.get_cvp_info()
             self.logger.debug(result)
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
                 self.client = self.__connect()
             result = self.client.api.get_cvp_info()
             self.logger.debug(result)
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
-            raise SdnConnectorError(message=SdnError.UNAUTHORIZED,
+            raise SdnConnectorError(message=SdnError.UNAUTHORIZED + " " + str(e),
                                     http_code=401) from e
         except Exception as ex:
             self.client = None
             self.logger.error(str(ex))
                                     http_code=401) from e
         except Exception as ex:
             self.client = None
             self.logger.error(str(ex))
-            raise SdnConnectorError(message=SdnError.INTERNAL_ERROR,
+            raise SdnConnectorError(message=SdnError.INTERNAL_ERROR + " " + str(ex),
                                     http_code=500) from ex
 
     def get_connectivity_service_status(self, service_uuid, conn_info=None):
                                     http_code=500) from ex
 
     def get_connectivity_service_status(self, service_uuid, conn_info=None):
@@ -406,7 +411,7 @@ class AristaSdnConnector(SdnConnectorBase):
                                         http_code=500)
 
             self.__get_Connection()
                                         http_code=500)
 
             self.__get_Connection()
-            if conn_info == None:
+            if conn_info is None:
                 raise SdnConnectorError(message='No connection information for service UUID {}'.format(service_uuid),
                                         http_code=500)
 
                 raise SdnConnectorError(message='No connection information for service UUID {}'.format(service_uuid),
                                         http_code=500)
 
@@ -464,12 +469,12 @@ class AristaSdnConnector(SdnConnectorBase):
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
-            raise SdnConnectorError(message=SdnError.UNAUTHORIZED,
+            raise SdnConnectorError(message=SdnError.UNAUTHORIZED + " " + str(e),
                                     http_code=401) from e
         except Exception as ex:
             self.client = None
             self.logger.error(str(ex), exc_info=True)
                                     http_code=401) from e
         except Exception as ex:
             self.client = None
             self.logger.error(str(ex), exc_info=True)
-            raise SdnConnectorError(message=str(ex),
+            raise SdnConnectorError(message=str(ex) + " " + str(ex),
                                     http_code=500) from ex
 
     def create_connectivity_service(self, service_type, connection_points,
                                     http_code=500) from ex
 
     def create_connectivity_service(self, service_type, connection_points,
@@ -535,20 +540,20 @@ class AristaSdnConnector(SdnConnectorBase):
             self.logger.info("Service with uuid {} created.".
                              format(service_uuid))
             s_uid, s_connInf = self.__processConnection(
             self.logger.info("Service with uuid {} created.".
                              format(service_uuid))
             s_uid, s_connInf = self.__processConnection(
-                                        service_uuid,
-                                        service_type,
-                                        connection_points,
-                                        kwargs)
+                service_uuid,
+                service_type,
+                connection_points,
+                kwargs)
             try:
                 self.__addMetadata(s_uid, service_type, s_connInf['vlan_id'])
             try:
                 self.__addMetadata(s_uid, service_type, s_connInf['vlan_id'])
-            except Exception as e:
+            except Exception:
                 pass
 
             return (s_uid, s_connInf)
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
                 pass
 
             return (s_uid, s_connInf)
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
-            raise SdnConnectorError(message=SdnError.UNAUTHORIZED,
+            raise SdnConnectorError(message=SdnError.UNAUTHORIZED + " " + str(e),
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
@@ -626,8 +631,9 @@ class AristaSdnConnector(SdnConnectorBase):
                 processed_connection_points += switches
                 for switch in switches:
                     if not interface:
                 processed_connection_points += switches
                 for switch in switches:
                     if not interface:
-                        raise SdnConnectorError(message="Connection point switch port empty for switch_dpid {}".format(switch_id),
-                                                http_code=406)
+                        raise SdnConnectorError(
+                            message="Connection point switch port empty for switch_dpid {}".format(switch_id),
+                            http_code=406)
                     # it should be only one switch where the mac is attached
                     if encap_type == 'dot1q':
                         # SRIOV configLet for Leaf switch mac's attached to
                     # it should be only one switch where the mac is attached
                     if encap_type == 'dot1q':
                         # SRIOV configLet for Leaf switch mac's attached to
@@ -686,7 +692,10 @@ class AristaSdnConnector(SdnConnectorBase):
                         for p in self.switches:
                             if self.switches[p]['mlagPeerDevice'] == s:
                                 if cls_cp.get(p):
                         for p in self.switches:
                             if self.switches[p]['mlagPeerDevice'] == s:
                                 if cls_cp.get(p):
-                                    cl_config = str(cl_vlan)
+                                    if self.topology == self._VXLAN_MLAG:
+                                        cl_config = str(cl_vlan) + str(cl_bgp[s])
+                                    else:
+                                        cl_config = str(cl_vlan)
                 else:
                     cl_config = str(cl_vlan) + str(cl_bgp[s]) + str(cls_cp[s])
 
                 else:
                     cl_config = str(cl_vlan) + str(cl_bgp[s]) + str(cls_cp[s])
 
@@ -737,7 +746,7 @@ class AristaSdnConnector(SdnConnectorBase):
                 if not (cls_perSw.get(s) and cls_perSw[s][0].get('config')):
                     # when there is no configuration, means that there is no interface
                     # in the switch to be connected, so the configLet has to be removed from CloudVision
                 if not (cls_perSw.get(s) and cls_perSw[s][0].get('config')):
                     # when there is no configuration, means that there is no interface
                     # in the switch to be connected, so the configLet has to be removed from CloudVision
-                    # after removing the ConfigLet fron the switch if it was already there
+                    # after removing the ConfigLet from the switch if it was already there
 
                     # get config let name and key
                     cl = cls_perSw[s]
 
                     # get config let name and key
                     cl = cls_perSw[s]
@@ -760,9 +769,9 @@ class AristaSdnConnector(SdnConnectorBase):
                         continue
                     cl = cls_perSw[s]
                 res = self.__device_modify(
                         continue
                     cl = cls_perSw[s]
                 res = self.__device_modify(
-                                           device_to_update=s,
-                                           new_configlets=cl,
-                                           delete=toDelete_in_cvp)
+                    device_to_update=s,
+                    new_configlets=cl,
+                    delete=toDelete_in_cvp)
                 if "errorMessage" in str(res):
                     raise Exception(str(res))
                 self.logger.info("Device {} modify result {}".format(s, res))
                 if "errorMessage" in str(res):
                     raise Exception(str(res))
                 self.logger.info("Device {} modify result {}".format(s, res))
@@ -773,10 +782,10 @@ class AristaSdnConnector(SdnConnectorBase):
                                                        t_id,
                                                        self.__SEPARATOR)
                         self.client.api.add_note_to_configlet(
                                                        t_id,
                                                        self.__SEPARATOR)
                         self.client.api.add_note_to_configlet(
-                                cls_perSw[s][0]['key'],
-                                note_msg)
+                            cls_perSw[s][0]['key'],
+                            note_msg)
                         cls_perSw[s][0]['note'] = note_msg
                         cls_perSw[s][0]['note'] = note_msg
-                    tasks = { t_id : {'workOrderId': t_id} }
+                    tasks = {t_id: {'workOrderId': t_id}}
                     self.__exec_task(tasks, self.__EXC_TASK_EXEC_WAIT)
                 # with just one configLet assigned to a device,
                 # delete all if there are errors in next loops
                     self.__exec_task(tasks, self.__EXC_TASK_EXEC_WAIT)
                 # with just one configLet assigned to a device,
                 # delete all if there are errors in next loops
@@ -793,7 +802,7 @@ class AristaSdnConnector(SdnConnectorBase):
                                           allLeafModified)
             except Exception as e:
                 self.logger.error("Exception rolling back in updating  connection: {}".
                                           allLeafModified)
             except Exception as e:
                 self.logger.error("Exception rolling back in updating  connection: {}".
-                                 format(e), exc_info=True)
+                                  format(e), exc_info=True)
             raise ex
 
     def __rollbackConnection(self,
             raise ex
 
     def __rollbackConnection(self,
@@ -824,7 +833,7 @@ class AristaSdnConnector(SdnConnectorBase):
                 self.__configlet_modify(cls_perSw[s], delete=True)
 
     def __exec_task(self, tasks, tout=10):
                 self.__configlet_modify(cls_perSw[s], delete=True)
 
     def __exec_task(self, tasks, tout=10):
-        if self.taskC == None:
+        if self.taskC is None:
             self.__connect()
         data = self.taskC.update_all_tasks(tasks).values()
         self.taskC.task_action(data, tout, 'executed')
             self.__connect()
         data = self.taskC.update_all_tasks(tasks).values()
         self.taskC.task_action(data, tout, 'executed')
@@ -833,15 +842,14 @@ class AristaSdnConnector(SdnConnectorBase):
         """ Updates the devices (switches) adding or removing the configLet,
         the tasks Id's associated to the change are returned
         """
         """ Updates the devices (switches) adding or removing the configLet,
         the tasks Id's associated to the change are returned
         """
-        self.logger.info('Enter in __device_modify delete: {}'.format(
-                            delete))
+        self.logger.info('Enter in __device_modify delete: {}'.format(delete))
         updated = []
         changed = False
         # Task Ids that have been identified during device actions
         newTasks = []
 
         if (len(new_configlets) == 0 or
         updated = []
         changed = False
         # Task Ids that have been identified during device actions
         newTasks = []
 
         if (len(new_configlets) == 0 or
-                device_to_update == None or
+                device_to_update is None or
                 len(device_to_update) == 0):
             data = {'updated': updated, 'tasks': newTasks}
             return [changed, data]
                 len(device_to_update) == 0):
             data = {'updated': updated, 'tasks': newTasks}
             return [changed, data]
@@ -857,14 +865,14 @@ class AristaSdnConnector(SdnConnectorBase):
             if try_device['hostname'] not in device_to_update:
                 continue
             dev_cvp_configlets = self.client.api.get_configlets_by_device_id(
             if try_device['hostname'] not in device_to_update:
                 continue
             dev_cvp_configlets = self.client.api.get_configlets_by_device_id(
-                                    try_device['systemMacAddress'])
+                try_device['systemMacAddress'])
             # self.logger.debug(dev_cvp_configlets)
             try_device['deviceSpecificConfiglets'] = []
             for cvp_configlet in dev_cvp_configlets:
                 if int(cvp_configlet['containerCount']) == 0:
                     try_device['deviceSpecificConfiglets'].append(
             # self.logger.debug(dev_cvp_configlets)
             try_device['deviceSpecificConfiglets'] = []
             for cvp_configlet in dev_cvp_configlets:
                 if int(cvp_configlet['containerCount']) == 0:
                     try_device['deviceSpecificConfiglets'].append(
-                                {'name': cvp_configlet['name'],
-                                 'key': cvp_configlet['key']})
+                        {'name': cvp_configlet['name'],
+                         'key': cvp_configlet['key']})
             # self.logger.debug(device)
             device = try_device
             break
             # self.logger.debug(device)
             device = try_device
             break
@@ -900,42 +908,41 @@ class AristaSdnConnector(SdnConnectorBase):
         try:
             if delete and len(cl_toDel) > 0:
                 r = self.client.api.remove_configlets_from_device(
         try:
             if delete and len(cl_toDel) > 0:
                 r = self.client.api.remove_configlets_from_device(
-                                                    'OSM',
-                                                    up_device['device'],
-                                                    cl_toDel,
-                                                    create_task=True)
+                    'OSM',
+                    up_device['device'],
+                    cl_toDel,
+                    create_task=True)
                 dev_action = r
                 self.logger.debug("remove_configlets_from_device {} {}".format(dev_action, cl_toDel))
             elif len(cl_toAdd) > 0:
                 r = self.client.api.apply_configlets_to_device(
                 dev_action = r
                 self.logger.debug("remove_configlets_from_device {} {}".format(dev_action, cl_toDel))
             elif len(cl_toAdd) > 0:
                 r = self.client.api.apply_configlets_to_device(
-                                                    'OSM',
-                                                    up_device['device'],
-                                                    cl_toAdd,
-                                                    create_task=True)
+                    'OSM',
+                    up_device['device'],
+                    cl_toAdd,
+                    create_task=True)
                 dev_action = r
                 self.logger.debug("apply_configlets_to_device {} {}".format(dev_action, cl_toAdd))
 
         except Exception as error:
             errorMessage = str(error)
             msg = "errorMessage: Device {} Configlets couldnot be updated: {}".format(
                 dev_action = r
                 self.logger.debug("apply_configlets_to_device {} {}".format(dev_action, cl_toAdd))
 
         except Exception as error:
             errorMessage = str(error)
             msg = "errorMessage: Device {} Configlets couldnot be updated: {}".format(
-                  up_device['hostname'], errorMessage)
+                up_device['hostname'], errorMessage)
             raise SdnConnectorError(msg) from error
         else:
             if "errorMessage" in str(dev_action):
                 m = "Device {} Configlets update fail: {}".format(
             raise SdnConnectorError(msg) from error
         else:
             if "errorMessage" in str(dev_action):
                 m = "Device {} Configlets update fail: {}".format(
-                            up_device['name'], dev_action['errorMessage'])
+                    up_device['name'], dev_action['errorMessage'])
                 raise SdnConnectorError(m)
             else:
                 changed = True
                 if 'taskIds' in str(dev_action):
                     # Fix 1030 SDN-ARISTA Key error note when deploy a NS
                     if not dev_action['data']['taskIds']:
                 raise SdnConnectorError(m)
             else:
                 changed = True
                 if 'taskIds' in str(dev_action):
                     # Fix 1030 SDN-ARISTA Key error note when deploy a NS
                     if not dev_action['data']['taskIds']:
-                        raise SdnConnectorError("No taskIds found: Device {} Configlets couldnot be updated".format(
-                                        up_device['hostname']))
+                        raise SdnConnectorError("No taskIds found: Device {} Configlets could not be updated".format(
+                            up_device['hostname']))
                     for taskId in dev_action['data']['taskIds']:
                     for taskId in dev_action['data']['taskIds']:
-                        updated.append({up_device['hostname']:
-                            "Configlets-{}".format(
-                                taskId)})
+                        updated.append({
+                            up_device['hostname']: "Configlets-{}".format(taskId)})
                         newTasks.append(taskId)
                 else:
                     updated.append({up_device['hostname']:
                         newTasks.append(taskId)
                 else:
                     updated.append({up_device['hostname']:
@@ -951,7 +958,7 @@ class AristaSdnConnector(SdnConnectorBase):
         :return: data: dict of module actions and taskIDs
         '''
         self.logger.info('Enter in __configlet_modify delete:{}'.format(
         :return: data: dict of module actions and taskIDs
         '''
         self.logger.info('Enter in __configlet_modify delete:{}'.format(
-                            delete))
+            delete))
 
         # Compare configlets against cvp_facts-configlets
         changed = False
 
         # Compare configlets against cvp_facts-configlets
         changed = False
@@ -1006,27 +1013,27 @@ class AristaSdnConnector(SdnConnectorBase):
                 if to_delete:
                     operation = 'delete'
                     resp = self.client.api.delete_configlet(
                 if to_delete:
                     operation = 'delete'
                     resp = self.client.api.delete_configlet(
-                                    configlet['data']['name'],
-                                    configlet['data']['key'])
+                        configlet['data']['name'],
+                        configlet['data']['key'])
                 elif to_update:
                     operation = 'update'
                     resp = self.client.api.update_configlet(
                 elif to_update:
                     operation = 'update'
                     resp = self.client.api.update_configlet(
-                                    configlet['config'],
-                                    configlet['data']['key'],
-                                    configlet['data']['name'],
-                                    wait_task_ids=True)
+                        configlet['config'],
+                        configlet['data']['key'],
+                        configlet['data']['name'],
+                        wait_task_ids=True)
                 elif to_create:
                     operation = 'create'
                     resp = self.client.api.add_configlet(
                 elif to_create:
                     operation = 'create'
                     resp = self.client.api.add_configlet(
-                                    configlet['name'],
-                                    configlet['config'])
+                        configlet['name'],
+                        configlet['config'])
                 else:
                     operation = 'checked'
                     resp = 'checked'
             except Exception as error:
                 errorMessage = str(error).split(':')[-1]
                 message = "Configlet {} cannot be {}: {}".format(
                 else:
                     operation = 'checked'
                     resp = 'checked'
             except Exception as error:
                 errorMessage = str(error).split(':')[-1]
                 message = "Configlet {} cannot be {}: {}".format(
-                            cl['name'], operation, errorMessage)
+                    cl['name'], operation, errorMessage)
                 if to_delete:
                     deleted.append({configlet['name']: message})
                 elif to_update:
                 if to_delete:
                     deleted.append({configlet['name']: message})
                 elif to_update:
@@ -1039,7 +1046,7 @@ class AristaSdnConnector(SdnConnectorBase):
             else:
                 if "error" in str(resp).lower():
                     message = "Configlet {} cannot be deleted: {}".format(
             else:
                 if "error" in str(resp).lower():
                     message = "Configlet {} cannot be deleted: {}".format(
-                            cl['name'], resp['errorMessage'])
+                        cl['name'], resp['errorMessage'])
                     if to_delete:
                         deleted.append({configlet['name']: message})
                     elif to_update:
                     if to_delete:
                         deleted.append({configlet['name']: message})
                     elif to_update:
@@ -1073,7 +1080,7 @@ class AristaSdnConnector(SdnConnectorBase):
             if len(configlet) > 0:
                 configlet['devices'] = []
                 applied_devices = self.client.api.get_applied_devices(
             if len(configlet) > 0:
                 configlet['devices'] = []
                 applied_devices = self.client.api.get_applied_devices(
-                                configlet['name'])
+                    configlet['name'])
                 for device in applied_devices['data']:
                     configlet['devices'].append(device['hostName'])
 
                 for device in applied_devices['data']:
                     configlet['devices'].append(device['hostName'])
 
@@ -1113,7 +1120,7 @@ class AristaSdnConnector(SdnConnectorBase):
                                         http_code=500)
 
             self.__get_Connection()
                                         http_code=500)
 
             self.__get_Connection()
-            if conn_info == None:
+            if conn_info is None:
                 raise SdnConnectorError(message='No connection information for service UUID {}'.format(service_uuid),
                                         http_code=500)
             c_info = None
                 raise SdnConnectorError(message='No connection information for service UUID {}'.format(service_uuid),
                                         http_code=500)
             c_info = None
@@ -1143,7 +1150,7 @@ class AristaSdnConnector(SdnConnectorBase):
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
-            raise SdnConnectorError(message=SdnError.UNAUTHORIZED,
+            raise SdnConnectorError(message=SdnError.UNAUTHORIZED + " " + str(e),
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
@@ -1152,7 +1159,7 @@ class AristaSdnConnector(SdnConnectorBase):
             self.logger.error(ex)
             if self.raiseException:
                 raise ex
             self.logger.error(ex)
             if self.raiseException:
                 raise ex
-            raise SdnConnectorError(message=SdnError.INTERNAL_ERROR,
+            raise SdnConnectorError(message=SdnError.INTERNAL_ERROR + " " + str(ex),
                                     http_code=500) from ex
 
     def __addMetadata(self, service_uuid, service_type, vlan_id):
                                     http_code=500) from ex
 
     def __addMetadata(self, service_uuid, service_type, vlan_id):
@@ -1246,7 +1253,7 @@ class AristaSdnConnector(SdnConnectorBase):
                 raise SdnConnectorError(message='Unable to perform operation, missing or empty connection information',
                                         http_code=500)
 
                 raise SdnConnectorError(message='Unable to perform operation, missing or empty connection information',
                                         http_code=500)
 
-            if connection_points == None:
+            if connection_points is None:
                 return None
 
             self.__get_Connection()
                 return None
 
             self.__get_Connection()
@@ -1261,17 +1268,17 @@ class AristaSdnConnector(SdnConnectorBase):
                                  kwargs=kwargs)
 
             s_uid, s_connInf = self.__processConnection(
                                  kwargs=kwargs)
 
             s_uid, s_connInf = self.__processConnection(
-                                                        service_uuid,
-                                                        service_type,
-                                                        connection_points,
-                                                        kwargs)
+                service_uuid,
+                service_type,
+                connection_points,
+                kwargs)
             self.logger.info("Service with uuid {} configuration updated".
                              format(s_uid))
             return s_connInf
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
             self.logger.info("Service with uuid {} configuration updated".
                              format(s_uid))
             return s_connInf
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
-            raise SdnConnectorError(message=SdnError.UNAUTHORIZED,
+            raise SdnConnectorError(message=SdnError.UNAUTHORIZED + " " + str(e),
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
@@ -1281,8 +1288,8 @@ class AristaSdnConnector(SdnConnectorBase):
                 # TODO check if there are pending task, and cancel them before restoring
                 self.__updateConnection(cls_currentPerSw)
             except Exception as e:
                 # TODO check if there are pending task, and cancel them before restoring
                 self.__updateConnection(cls_currentPerSw)
             except Exception as e:
-                self.logger.error("Unable to restore configuration in service {} after an error in the configuration updated: {}".
-                                  format(service_uuid, str(e)))
+                self.logger.error("Unable to restore configuration in service {} after an error in the configuration"
+                                  " updated: {}".format(service_uuid, str(e)))
             if self.raiseException:
                 raise ex
             raise SdnConnectorError(message=str(ex),
             if self.raiseException:
                 raise ex
             raise SdnConnectorError(message=str(ex),
@@ -1307,7 +1314,7 @@ class AristaSdnConnector(SdnConnectorBase):
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
-            raise SdnConnectorError(message=SdnError.UNAUTHORIZED,
+            raise SdnConnectorError(message=SdnError.UNAUTHORIZED + " " + str(e),
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
@@ -1316,7 +1323,7 @@ class AristaSdnConnector(SdnConnectorBase):
             self.logger.error(ex)
             if self.raiseException:
                 raise ex
             self.logger.error(ex)
             if self.raiseException:
                 raise ex
-            raise SdnConnectorError(message=SdnError.INTERNAL_ERROR,
+            raise SdnConnectorError(message=SdnError.INTERNAL_ERROR + " " + str(ex),
                                     http_code=500) from ex
 
     def get_all_active_connectivity_services(self):
                                     http_code=500) from ex
 
     def get_all_active_connectivity_services(self):
@@ -1342,7 +1349,7 @@ class AristaSdnConnector(SdnConnectorBase):
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
         except CvpLoginError as e:
             self.logger.info(str(e))
             self.client = None
-            raise SdnConnectorError(message=SdnError.UNAUTHORIZED,
+            raise SdnConnectorError(message=SdnError.UNAUTHORIZED + " " + str(e),
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
                                     http_code=401) from e
         except SdnConnectorError as sde:
             raise sde
@@ -1442,7 +1449,7 @@ class AristaSdnConnector(SdnConnectorBase):
             invoking the version retrival as test
         """
         try:
             invoking the version retrival as test
         """
         try:
-            if self.client == None:
+            if self.client is None:
                 self.client = self.__connect()
             self.client.api.get_cvp_info()
         except (CvpSessionLogOutError, RequestException) as e:
                 self.client = self.__connect()
             self.client.api.get_cvp_info()
         except (CvpSessionLogOutError, RequestException) as e:
@@ -1482,11 +1489,11 @@ class AristaSdnConnector(SdnConnectorBase):
           Score - 1.0 if the sequences are identical, and
                   0.0 if they have nothing in common.
         unified diff list
           Score - 1.0 if the sequences are identical, and
                   0.0 if they have nothing in common.
         unified diff list
-          Code Meaning
-          '- ' line unique to sequence 1
-          '+ ' line unique to sequence 2
-          '  ' line common to both sequences
-          '? ' line not present in either input sequence
+          Code    Meaning
+          '- '    line unique to sequence 1
+          '+ '    line unique to sequence 2
+          '  '    line common to both sequences
+          '? '    line not present in either input sequence
         """
         fromlines = fromText.splitlines(1)
         tolines = toText.splitlines(1)
         """
         fromlines = fromText.splitlines(1)
         tolines = toText.splitlines(1)
@@ -1518,20 +1525,33 @@ class AristaSdnConnector(SdnConnectorBase):
     def __get_interface_ip(self, device_id, interface):
         url = '/api/v1/rest/{}/Sysdb/ip/config/ipIntfConfig/{}/'.format(device_id, interface)
         self.logger.debug('get_interface_ip: URL {}'.format(url))
     def __get_interface_ip(self, device_id, interface):
         url = '/api/v1/rest/{}/Sysdb/ip/config/ipIntfConfig/{}/'.format(device_id, interface)
         self.logger.debug('get_interface_ip: URL {}'.format(url))
+        data = None
         try:
             data = self.client.get(url, timeout=self.__API_REQUEST_TOUT)
         try:
             data = self.client.get(url, timeout=self.__API_REQUEST_TOUT)
-            return data['notifications'][0]['updates']['addrWithMask']['value'].split('/')[0]
-        except Exception:
-            raise SdnConnectorError("Invalid response from url {}: data {}".format(url, data))
+            if data['notifications']:
+                for notification in data['notifications']:
+                    for update in notification['updates']:
+                        if update == 'addrWithMask':
+                            return notification['updates'][update]['value']
+        except Exception as e:
+            raise SdnConnectorError("Invalid response from url {}: data {} - {}".format(url, data, str(e)))
+        raise SdnConnectorError("Unable to get ip for interface {} in device {}, data {}".
+                                format(interface, device_id, data))
 
     def __get_device_ASN(self, device_id):
         url = '/api/v1/rest/{}/Sysdb/routing/bgp/config/'.format(device_id)
         self.logger.debug('get_device_ASN: URL {}'.format(url))
 
     def __get_device_ASN(self, device_id):
         url = '/api/v1/rest/{}/Sysdb/routing/bgp/config/'.format(device_id)
         self.logger.debug('get_device_ASN: URL {}'.format(url))
+        data = None
         try:
             data = self.client.get(url, timeout=self.__API_REQUEST_TOUT)
         try:
             data = self.client.get(url, timeout=self.__API_REQUEST_TOUT)
-            return data['notifications'][0]['updates']['asNumber']['value']['value']['int']
-        except Exception:
-            raise SdnConnectorError("Invalid response from url {}: data {}".format(url, data))
+            if data['notifications']:
+                for notification in data['notifications']:
+                    for update in notification['updates']:
+                        if update == 'asNumber':
+                            return notification['updates'][update]['value']['value']['int']
+        except Exception as e:
+            raise SdnConnectorError("Invalid response from url {}: data {} - {}".format(url, data, str(e)))
+        raise SdnConnectorError("Unable to get AS in device {}, data {}".format(device_id, data))
 
     def __get_peer_MLAG(self, device_id):
         peer = None
 
     def __get_peer_MLAG(self, device_id):
         peer = None
@@ -1569,8 +1589,9 @@ class AristaSdnConnector(SdnConnectorBase):
                                 break
                         if found:
                             break
                                 break
                         if found:
                             break
-            if peer == None:
-                self.logger.error('No Peer device found for device {} with MLAG address {}'.format(device_id, mlagSystemId))
+            if peer is None:
+                self.logger.error('No Peer device found for device {} with MLAG address {}'.format(device_id,
+                                                                                                   mlagSystemId))
             else:
                 self.logger.debug('Peer MLAG for device {} - value {}'.format(device_id, peer))
             return peer
             else:
                 self.logger.debug('Peer MLAG for device {} - value {}'.format(device_id, peer))
             return peer
@@ -1612,7 +1633,7 @@ class AristaSdnConnector(SdnConnectorBase):
         return True
 
     def delete_keys_from_dict(self, dict_del, lst_keys):
         return True
 
     def delete_keys_from_dict(self, dict_del, lst_keys):
-        if dict_del == None:
+        if dict_del is None:
             return dict_del
         dict_copy = {k: v for k, v in dict_del.items() if k not in lst_keys}
         for k, v in dict_copy.items():
             return dict_del
         dict_copy = {k: v for k, v in dict_del.items() if k not in lst_keys}
         for k, v in dict_copy.items():