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_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
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 = \
- '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.',
_VLAN_MLAG = "VLAN-MLAG"
_VXLAN_MLAG = "VXLAN-MLAG"
-
def __init__(self, wim, wim_account, config=None, logger=None):
"""
: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)
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 CvpLoginError as le:
+ raise SdnConnectorError(message=le.msg, http_code=500) from le
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(
- 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.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:
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
- 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))
- 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)
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)
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)
- 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,
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'])
- except Exception as e:
+ except Exception:
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
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
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])
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]
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))
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
- 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
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,
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')
""" 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
- device_to_update == None or
+ device_to_update is None or
len(device_to_update) == 0):
data = {'updated': updated, 'tasks': newTasks}
return [changed, data]
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(
- {'name': cvp_configlet['name'],
- 'key': cvp_configlet['key']})
+ {'name': cvp_configlet['name'],
+ 'key': cvp_configlet['key']})
# self.logger.debug(device)
device = try_device
break
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(
- '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(
- 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(
- 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("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']:
- 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']:
: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
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(
- 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(
- 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(
- cl['name'], operation, errorMessage)
+ cl['name'], operation, errorMessage)
if to_delete:
deleted.append({configlet['name']: message})
elif to_update:
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 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'])
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
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
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):
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()
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
- raise SdnConnectorError(message=SdnError.UNAUTHORIZED,
+ raise SdnConnectorError(message=SdnError.UNAUTHORIZED + " " + str(e),
http_code=401) from e
except SdnConnectorError as sde:
raise sde
# 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),
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
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):
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
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:
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)
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)
- 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))
+ data = None
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
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
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():