1 # -*- coding: utf-8 -*-
3 # Copyright 2020 ETSI OSM
7 # Licensed under the Apache License, Version 2.0 (the "License"); you may
8 # not use this file except in compliance with the License. You may obtain
9 # a copy of the License at
11 # http://www.apache.org/licenses/LICENSE-2.0
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 # License for the specific language governing permissions and limitations
27 #from requests.auth import HTTPBasicAuth
28 from osm_ro
.wim
.sdnconn
import SdnConnectorBase
, SdnConnectorError
29 from osm_rosdn_juniper_contrail
.rest_lib
import Http
31 from io
import BytesIO
35 class JuniperContrail(SdnConnectorBase
):
37 Juniper Contrail SDN plugin. The plugin interacts with Juniper Contrail Controller,
38 whose API details can be found in these links:
40 - https://github.com/tonyliu0592/contrail/wiki/API-Configuration-REST
41 - https://www.juniper.net/documentation/en_US/contrail19/information-products/pathway-pages/api-guide-1910/tutorial_with_rest.html
42 - https://github.com/tonyliu0592/contrail-toolbox/blob/master/sriov/sriov
44 _WIM_LOGGER
= "openmano.sdnconn.junipercontrail"
46 def __init__(self
, wim
, wim_account
, config
=None, logger
=None):
49 :param wim: (dict). Contains among others 'wim_url'
50 :param wim_account: (dict). Contains among others 'uuid' (internal id), 'name',
51 'sdn' (True if is intended for SDN-assist or False if intended for WIM), 'user', 'password'.
52 :param config: (dict or None): Particular information of plugin. These keys if present have a common meaning:
53 'mapping_not_needed': (bool) False by default or if missing, indicates that mapping is not needed.
54 'service_endpoint_mapping': (list) provides the internal endpoint mapping. The meaning is:
55 KEY meaning for WIM meaning for SDN assist
56 -------- -------- --------
57 device_id pop_switch_dpid compute_id
58 device_interface_id pop_switch_port compute_pci_address
59 service_endpoint_id wan_service_endpoint_id SDN_service_endpoint_id
60 service_mapping_info wan_service_mapping_info SDN_service_mapping_info
61 contains extra information if needed. Text in Yaml format
62 switch_dpid wan_switch_dpid SDN_switch_dpid
63 switch_port wan_switch_port SDN_switch_port
64 datacenter_id vim_account vim_account
65 id: (internal, do not use)
66 wim_id: (internal, do not use)
67 :param logger (logging.Logger): optional logger object. If none is passed 'openmano.sdn.sdnconn' is used.
69 self
.logger
= logger
or logging
.getLogger(self
._WIM
_LOGGER
)
70 self
.logger
.debug('wim: {}, wim_account: {}, config: {}'.format(wim
, wim_account
, config
))
71 super().__init
__(wim
, wim_account
, config
, logger
)
73 self
.user
= wim_account
.get("user")
74 self
.password
= wim_account
.get("password")
76 url
= wim
.get("wim_url")
85 auth_url
= config
.get("auth_url")
86 overlay_url
= config
.get("overlay_url")
87 self
.project
= config
.get("project")
88 self
.domain
= config
.get("domain")
89 self
.asn
= config
.get("asn")
90 self
.fabric
= config
.get("fabric")
91 self
.vni_range
= config
.get("vni_range")
94 raise SdnConnectorError("'url' must be provided")
95 if not url
.startswith("http"):
97 if not url
.endswith("/"):
102 raise SdnConnectorError("'project' must be provided")
104 # TODO: Get ASN from controller config; otherwise raise ERROR for the moment
105 raise SdnConnectorError("'asn' was not provided and was not possible to obtain it")
107 # TODO: Get FABRIC from controller config; otherwise raise ERROR for the moment
108 raise SdnConnectorError("'fabric' was not provided and was not possible to obtain it")
110 self
.domain
= 'default'
111 self
.logger
.info("No domain was provided. Using 'default'")
112 if not self
.vni_range
:
113 self
.vni_range
= '1000001-2000000'
114 self
.logger
.info("No vni_range was provided. Using '1000001-2000000'")
117 if not overlay_url
.startswith("http"):
118 overlay_url
= "http://" + overlay_url
119 if not overlay_url
.endswith("/"):
120 overlay_url
= overlay_url
+ "/"
121 self
.overlay_url
= overlay_url
124 if not auth_url
.startswith("http"):
125 auth_url
= "http://" + auth_url
126 if not auth_url
.endswith("/"):
127 auth_url
= auth_url
+ "/"
128 self
.auth_url
= auth_url
131 self
.http
= Http(self
.logger
)
133 # Init http headers for all requests
134 self
.headers
= {'Content-Type': 'application/json'}
135 self
.http_header
= ['{}: {}'.format(key
, val
)
136 for (key
, val
) in list(self
.headers
.items())]
139 auth_dict
['auth'] = {}
140 auth_dict
['auth']['scope'] = {}
141 auth_dict
['auth']['scope']['project'] = {}
142 auth_dict
['auth']['scope']['project']['domain'] = {}
143 auth_dict
['auth']['scope']['project']['domain']["id"] = self
.domain
144 auth_dict
['auth']['scope']['project']['name'] = self
.project
145 auth_dict
['auth']['identity'] = {}
146 auth_dict
['auth']['identity']['methods'] = ['password']
147 auth_dict
['auth']['identity']['password'] = {}
148 auth_dict
['auth']['identity']['password']['user'] = {}
149 auth_dict
['auth']['identity']['password']['user']['name'] = self
.user
150 auth_dict
['auth']['identity']['password']['user']['password'] = self
.password
151 auth_dict
['auth']['identity']['password']['user']['domain'] = {}
152 auth_dict
['auth']['identity']['password']['user']['domain']['id'] = self
.domain
153 self
.auth_dict
= auth_dict
156 self
.logger
.info("Juniper Contrail Connector Initialized.")
159 def _get_token(self
):
160 self
.logger
.debug('Current Token:'.format(str(self
.token
)))
161 auth_url
= self
.auth_url
+ 'auth/tokens'
162 if self
.token
is None:
163 if not self
.auth_url
:
165 http_code
, resp
= self
.http
.post_cmd(url
=auth_url
, headers
=self
.http_header
,
166 postfields_dict
=self
.auth_dict
,
167 return_header
= 'x-subject-token')
169 self
.logger
.debug('Token: '.format(self
.token
))
172 self
.headers
['X-Auth-Token'] = self
.token
174 self
.headers
.pop('X-Auth-Token', None)
175 http_header
= ['{}: {}'.format(key
, val
)
176 for (key
, val
) in list(self
.headers
.items())]
179 # Aux functions for testing
184 def get_overlay_url(self
):
185 return self
.overlay_url
187 # Virtual network operations
189 def _create_virtual_network(self
, controller_url
, name
, vni
):
190 routetarget
= '{}:{}'.format(self
.asn
,vni
)
193 "virtual_network_properties": {
194 "vxlan_network_identifier": vni
,
196 "parent_type": "project",
202 "route_target_list": {
204 "target:" + routetarget
210 endpoint
= controller_url
+ 'virtual-networks'
211 http_code
, resp
= self
.http
.post_cmd(url
= endpoint
,
212 headers
= self
.http_header
,
213 postfields_dict
= vnet_dict
)
214 if http_code
not in (200, 201, 202, 204) or not resp
:
215 raise SdnConnectorError('Unexpected http status code, or empty response')
216 vnet_info
= json
.loads(resp
)
217 self
.logger
.debug("vnet_info: {}".format(vnet_info
))
218 return vnet_info
.get("virtual-network").get('uuid'), vnet_info
.get("virtual-network")
221 def _get_virtual_networks(self
, controller_url
):
223 endpoint
= controller_url
+ 'virtual-networks'
225 http_code
, resp
= self
.http
.get_cmd(url
=endpoint
, headers
=self
.http_header
)
226 if http_code
not in (200, 201, 202, 204) or not resp
:
227 raise SdnConnectorError('Unexpected http status code, or empty response')
228 vnets_info
= json
.loads(resp
)
229 self
.logger
.debug("vnets_info: {}".format(vnets_info
))
230 return vnets_info
.get('virtual-networks')
233 def _get_virtual_network(self
, controller_url
, network_id
):
235 endpoint
= controller_url
+ 'virtual-network/{}'.format(network_id
)
236 http_code
, resp
= self
.http
.get_cmd(url
=endpoint
, headers
=self
.http_header
)
237 if http_code
not in (200, 201, 202, 204) or not resp
:
240 raise SdnConnectorError('Unexpected http status code, or empty response')
241 vnet_info
= json
.loads(resp
)
242 self
.logger
.debug("vnet_info: {}".format(vnet_info
))
243 return vnet_info
.get("virtual-network")
246 def _delete_virtual_network(self
, controller_url
, network_id
):
248 endpoint
= controller_url
+ 'virtual-network/{}'.format(network_id
)
249 http_code
, _
= self
.http
.delete_cmd(url
=endpoint
, headers
=self
.http_header
)
250 if http_code
not in (200, 201, 202, 204):
251 raise SdnConnectorError('Unexpected http status code')
255 # Virtual port group operations
257 def _create_vpg(self
, controller_url
, switch_id
, switch_port
, network
, vlan
):
259 "virtual-port-group": {
263 endpoint
= controller_url
+ 'virtual-port-groups'
264 http_code
, resp
= self
.http
.post_cmd(url
= endpoint
,
265 headers
= self
.http_header
,
266 postfields_dict
= vpg_dict
)
267 if http_code
not in (200, 201, 202, 204) or not resp
:
268 raise SdnConnectorError('Unexpected http status code, or empty response')
269 vpg_info
= json
.loads(resp
)
270 self
.logger
.debug("vpg_info: {}".format(vpg_info
))
271 return vpg_info
.get("virtual-port-group").get('uuid'), vpg_info
.get("virtual-port-group")
274 def _get_vpgs(self
, controller_url
):
276 endpoint
= controller_url
+ 'virtual-port-groups'
277 http_code
, resp
= self
.http
.get_cmd(url
=endpoint
, headers
=self
.http_header
)
278 if http_code
not in (200, 201, 202, 204) or not resp
:
279 raise SdnConnectorError('Unexpected http status code, or empty response')
280 vpgs_info
= json
.loads(resp
)
281 self
.logger
.debug("vpgs_info: {}".format(vpgs_info
))
282 return vpgs_info
.get('virtual-port-groups')
285 def _get_vpg(self
, controller_url
, vpg_id
):
287 endpoint
= controller_url
+ 'virtual-port-group/{}'.format(vpg_id
)
288 http_code
, resp
= self
.http
.get_cmd(url
=endpoint
, headers
=self
.http_header
)
289 if http_code
not in (200, 201, 202, 204) or not resp
:
292 raise SdnConnectorError('Unexpected http status code, or empty response')
293 vpg_info
= json
.loads(resp
)
294 self
.logger
.debug("vpg_info: {}".format(vpg_info
))
295 return vpg_info
.get("virtual-port-group")
298 def _delete_vpg(self
, controller_url
, vpg_id
):
300 endpoint
= controller_url
+ 'virtual-port-group/{}'.format(vpg_id
)
301 http_code
, resp
= self
.http
.delete_cmd(url
=endpoint
, headers
=self
.http_header
)
302 if http_code
not in (200, 201, 202, 204):
303 raise SdnConnectorError('Unexpected http status code')
307 def check_credentials(self
):
308 """Check if the connector itself can access the SDN/WIM with the provided url (wim.wim_url),
309 user (wim_account.user), and password (wim_account.password)
312 SdnConnectorError: Issues regarding authorization, access to
313 external URLs, etc are detected.
315 self
.logger
.debug("")
318 http_code
, resp
= self
.http
.get_cmd(url
=self
.auth_url
, headers
=self
.http_header
)
319 if http_code
not in (200, 201, 202, 204) or not resp
:
320 raise SdnConnectorError('Unexpected http status code, or empty response')
321 except Exception as e
:
322 self
.logger
.error('Error checking credentials')
323 raise SdnConnectorError('Error checking credentials', http_code
=http_code
)
326 def get_connectivity_service_status(self
, service_uuid
, conn_info
=None):
327 """Monitor the status of the connectivity service established
330 service_uuid (str): UUID of the connectivity service
331 conn_info (dict or None): Information returned by the connector
332 during the service creation/edition and subsequently stored in
336 dict: JSON/YAML-serializable dict that contains a mandatory key
337 ``sdn_status`` associated with one of the following values::
339 {'sdn_status': 'ACTIVE'}
340 # The service is up and running.
342 {'sdn_status': 'INACTIVE'}
343 # The service was created, but the connector
344 # cannot determine yet if connectivity exists
345 # (ideally, the caller needs to wait and check again).
347 {'sdn_status': 'DOWN'}
348 # Connection was previously established,
349 # but an error/failure was detected.
351 {'sdn_status': 'ERROR'}
352 # An error occurred when trying to create the service/
353 # establish the connectivity.
355 {'sdn_status': 'BUILD'}
356 # Still trying to create the service, the caller
357 # needs to wait and check again.
359 Additionally ``error_msg``(**str**) and ``sdn_info``(**dict**)
360 keys can be used to provide additional status explanation or
361 new information available for the connectivity service.
363 self
.logger
.debug("")
366 http_code
, resp
= self
.http
.get_cmd(endpoint
='virtual-network/{}'.format(service_uuid
))
367 if http_code
not in (200, 201, 202, 204) or not resp
:
368 raise SdnConnectorError('Unexpected http status code, or empty response')
370 vnet_info
= json
.loads(resp
)
371 return {'sdn_status': 'ACTIVE', 'sdn_info': vnet_info
['virtual-network']}
373 return {'sdn_status': 'ERROR', 'sdn_info': 'not found'}
374 except Exception as e
:
375 self
.logger
.error('Exception getting connectivity service info: %s', e
)
376 return {'sdn_status': 'ERROR', 'error_msg': str(e
)}
379 def create_connectivity_service(self
, service_type
, connection_points
, **kwargs
):
381 Establish SDN/WAN connectivity between the endpoints
382 :param service_type: (str): ``ELINE`` (L2), ``ELAN`` (L2), ``ETREE`` (L2), ``L3``.
383 :param connection_points: (list): each point corresponds to
384 an entry point to be connected. For WIM: from the DC to the transport network.
385 For SDN: Compute/PCI to the transport network. One
386 connection point serves to identify the specific access and
387 some other service parameters, such as encapsulation type.
388 Each item of the list is a dict with:
389 "service_endpoint_id": (str)(uuid) Same meaning that for 'service_endpoint_mapping' (see __init__)
390 In case the config attribute mapping_not_needed is True, this value is not relevant. In this case
391 it will contain the string "device_id:device_interface_id"
392 "service_endpoint_encapsulation_type": None, "dot1q", ...
393 "service_endpoint_encapsulation_info": (dict) with:
394 "vlan": ..., (int, present if encapsulation is dot1q)
395 "vni": ... (int, present if encapsulation is vxlan),
396 "peers": [(ipv4_1), (ipv4_2)] (present if encapsulation is vxlan)
398 "device_id": ..., same meaning that for 'service_endpoint_mapping' (see __init__)
399 "device_interface_id": same meaning that for 'service_endpoint_mapping' (see __init__)
400 "switch_dpid": ..., present if mapping has been found for this device_id,device_interface_id
401 "switch_port": ... present if mapping has been found for this device_id,device_interface_id
402 "service_mapping_info": present if mapping has been found for this device_id,device_interface_id
403 :param kwargs: For future versions:
404 bandwidth (int): value in kilobytes
405 latency (int): value in milliseconds
406 Other QoS might be passed as keyword arguments.
407 :return: tuple: ``(service_id, conn_info)`` containing:
408 - *service_uuid* (str): UUID of the established connectivity service
409 - *conn_info* (dict or None): Information to be stored at the database (or ``None``).
410 This information will be provided to the :meth:`~.edit_connectivity_service` and :obj:`~.delete`.
411 **MUST** be JSON/YAML-serializable (plain data structures).
412 :raises: SdnConnectorException: In case of error. Nothing should be created in this case.
413 Provide the parameter http_code
415 self
.logger
.debug("create_connectivity_service, service_type: {}, connection_points: {}".
416 format(service_type
, connection_points
))
417 if service_type
.lower() != 'elan':
418 raise SdnConnectorError('Only ELAN network type is supported by Juniper Contrail.')
420 # Step 1. Check in the overlay controller the virtual network created by the VIM
421 # Best option: get network id of the VIM as param (if the VIM already created the network),
422 # and do a request to the controller of the virtual networks whose VIM network id is the provided
423 # Next best option: obtain the network by doing a request to the controller
424 # of the virtual networks using the VLAN ID of any service endpoint.
425 # 1.1 Read VLAN ID from a service endpoint
426 # 1.2 Look for virtual networks with "Provider Network" including a VLAN ID.
427 # 1.3 If more than one, ERROR
428 # Step 2. Modify the existing virtual network in the overlay controller
429 # 2.1 Add VNI (VxLAN Network Identifier - one free from the provided range)
430 # 2.2 Add RouteTarget (RT) ('ASN:VNI', ASN = Autonomous System Number, provided as param or read from controller config)
431 # Step 3. Create a virtual network in the underlay controller
432 # 3.1 Create virtual network (name, VNI, RT)
433 # If the network already existed in the overlay controller, we should use the same name
434 # name = 'osm-plugin-' + overlay_name
436 # name = 'osm-plugin-' + VNI
440 network_id
, network_info
= self
._create
_virtual
_network
(self
.url
, name
, vni
)
441 except SdnConnectorError
:
442 raise SdnConnectorError('Failed to create connectivity service {}'.format(name
))
443 except Exception as e
:
444 self
.logger
.error('Exception creating connection_service: %s', e
, exc_info
=True)
445 raise SdnConnectorError("Exception creating connectivity service: {}".format(str(e
)))
449 def edit_connectivity_service(self
, service_uuid
, conn_info
= None, connection_points
= None, **kwargs
):
450 """ Change an existing connectivity service.
452 This method's arguments and return value follow the same convention as
453 :meth:`~.create_connectivity_service`.
455 :param service_uuid: UUID of the connectivity service.
456 :param conn_info: (dict or None): Information previously returned by last call to create_connectivity_service
457 or edit_connectivity_service
458 :param connection_points: (list): If provided, the old list of connection points will be replaced.
459 :param kwargs: Same meaning that create_connectivity_service
460 :return: dict or None: Information to be updated and stored at the database.
461 When ``None`` is returned, no information should be changed.
462 When an empty dict is returned, the database record will be deleted.
463 **MUST** be JSON/YAML-serializable (plain data structures).
465 SdnConnectorException: In case of error.
467 #TODO: to be done. This comes from ONOS VPLS plugin
468 self
.logger
.debug("edit connectivity service, service_uuid: {}, conn_info: {}, "
469 "connection points: {} ".format(service_uuid
, conn_info
, connection_points
))
471 conn_info
= conn_info
or []
472 # Obtain current configuration
473 config_orig
= self
._get
_onos
_netconfig
()
474 config
= copy
.deepcopy(config_orig
)
476 # get current service data and check if it does not exists
478 for vpls
in config
.get('apps', {}).get('org.onosproject.vpls', {}).get('vpls', {}).get('vplsList', {}):
479 if vpls
['name'] == service_uuid
:
480 self
.logger
.debug("service exists")
481 curr_interfaces
= vpls
.get("interfaces", [])
482 curr_encapsulation
= vpls
.get("encapsulation")
485 raise SdnConnectorError("service uuid: {} does not exist".format(service_uuid
))
487 self
.logger
.debug("current interfaces: {}".format(curr_interfaces
))
488 self
.logger
.debug("current encapsulation: {}".format(curr_encapsulation
))
490 # new interfaces names
491 new_interfaces
= [port
['service_endpoint_id'] for port
in new_connection_points
]
493 # obtain interfaces to delete, list will contain port
494 ifs_delete
= list(set(curr_interfaces
) - set(new_interfaces
))
495 ifs_add
= list(set(new_interfaces
) - set(curr_interfaces
))
496 self
.logger
.debug("interfaces to delete: {}".format(ifs_delete
))
497 self
.logger
.debug("interfaces to add: {}".format(ifs_add
))
499 # check if some data of the interfaces that already existed has changed
500 # in that case delete it and add it again
501 ifs_remain
= list(set(new_interfaces
) & set(curr_interfaces
))
502 for port
in connection_points
:
503 if port
['service_endpoint_id'] in ifs_remain
:
504 # check if there are some changes
505 curr_port_name
, curr_vlan
= self
._get
_current
_port
_data
(config
, port
['service_endpoint_id'])
506 new_port_name
= 'of:{}/{}'.format(port
['service_endpoint_encapsulation_info']['switch_dpid'],
507 port
['service_endpoint_encapsulation_info']['switch_port'])
508 new_vlan
= port
['service_endpoint_encapsulation_info']['vlan']
509 if (curr_port_name
!= new_port_name
or curr_vlan
!= new_vlan
):
510 self
.logger
.debug("TODO: must update data interface: {}".format(port
['service_endpoint_id']))
511 ifs_delete
.append(port
['service_endpoint_id'])
512 ifs_add
.append(port
['service_endpoint_id'])
514 new_encapsulation
= self
._get
_encapsulation
(connection_points
)
517 # Delete interfaces, only will delete interfaces that are in provided conn_info
518 # because these are the ones that have been created for this service
520 for port
in config
['ports'].values():
521 for port_interface
in port
['interfaces']:
522 interface_name
= port_interface
['name']
523 self
.logger
.debug("interface name: {}".format(port_interface
['name']))
524 if interface_name
in ifs_delete
and interface_name
in conn_info
:
525 self
.logger
.debug("delete interface name: {}".format(interface_name
))
526 port
['interfaces'].remove(port_interface
)
527 conn_info
.remove(interface_name
)
530 for port
in connection_points
:
531 if port
['service_endpoint_id'] in ifs_add
:
532 created_ifz
= self
._append
_port
_to
_config
(port
, config
)
534 conn_info
.append(created_ifz
[1])
535 self
._pop
_last
_update
_time
(config
)
536 self
._post
_netconfig
(config
)
538 self
.logger
.debug("contrail config after updating interfaces: {}".format(config
))
539 self
.logger
.debug("conn_info after updating interfaces: {}".format(conn_info
))
541 # Update interfaces list in vpls service
542 for vpls
in config
.get('apps', {}).get('org.onosproject.vpls', {}).get('vpls', {}).get('vplsList', {}):
543 if vpls
['name'] == service_uuid
:
544 vpls
['interfaces'] = new_interfaces
545 vpls
['encapsulation'] = new_encapsulation
547 self
._pop
_last
_update
_time
(config
)
548 self
._post
_netconfig
(config
)
550 except Exception as e
:
551 self
.logger
.error('Exception add connection_service: %s', e
)
552 # try to rollback push original config
554 self
._post
_netconfig
(config_orig
)
555 except Exception as e2
:
556 self
.logger
.error('Exception rolling back to original config: %s', e2
)
558 if isinstance(e
, SdnConnectorError
):
561 raise SdnConnectorError("Exception create_connectivity_service: {}".format(e
))
564 def delete_connectivity_service(self
, service_uuid
, conn_info
=None):
566 Disconnect multi-site endpoints previously connected
568 :param service_uuid: The one returned by create_connectivity_service
569 :param conn_info: The one returned by last call to 'create_connectivity_service' or 'edit_connectivity_service'
570 if they do not return None
572 :raises: SdnConnectorException: In case of error. The parameter http_code must be filled
574 self
.logger
.debug("delete_connectivity_service uuid: {}".format(service_uuid
))
576 #TO DO: check if virtual port groups have to be deleted
577 self
._delete
_virtual
_network
(self
.url
, service_uuid
)
578 except SdnConnectorError
:
579 raise SdnConnectorError('Failed to delete service uuid {}'.format(service_uuid
))
580 except Exception as e
:
581 self
.logger
.error('Exception deleting connection_service: %s', e
, exc_info
=True)
582 raise SdnConnectorError("Exception deleting connectivity service: {}".format(str(e
)))
585 if __name__
== '__main__':
587 log_format
= "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)s %(funcName)s(): %(message)s"
588 log_formatter
= logging
.Formatter(log_format
, datefmt
='%Y-%m-%dT%H:%M:%S')
589 handler
= logging
.StreamHandler()
590 handler
.setFormatter(log_formatter
)
591 logger
= logging
.getLogger('openmano.sdnconn.junipercontrail')
592 #logger.setLevel(level=logging.ERROR)
593 logger
.setLevel(level
=logging
.INFO
)
594 #logger.setLevel(level=logging.DEBUG)
595 logger
.addHandler(handler
)
598 with
open('test.yaml') as f
:
599 config
= yaml
.safe_load(f
.read())
600 wim
= {'wim_url': config
.pop('wim_url')}
601 wim_account
= {'user': config
.pop('user'), 'password': config
.pop('password')}
602 logger
.info('wim: {}, wim_account: {}, config: {}'.format(wim
, wim_account
, config
))
605 juniper_contrail
= JuniperContrail(wim
=wim
, wim_account
=wim_account
, config
=config
, logger
=logger
)
608 # 0. Check credentials
609 print('0. Check credentials')
610 juniper_contrail
.check_credentials()
612 underlay_url
= juniper_contrail
.get_url()
613 overlay_url
= juniper_contrail
.get_overlay_url()
614 # 1. Read virtual networks from overlay controller
615 print('1. Read virtual networks from overlay controller')
617 vnets
= juniper_contrail
._get
_virtual
_networks
(overlay_url
)
618 logger
.debug(yaml
.safe_dump(vnets
, indent
=4, default_flow_style
=False))
620 except Exception as e
:
621 logger
.error('Exception reading virtual networks from overlay controller: %s', e
)
624 # 2. Read virtual networks from underlay controller
625 print('2. Read virtual networks from underlay controller')
626 vnets
= juniper_contrail
._get
_virtual
_networks
(underlay_url
)
627 logger
.debug(yaml
.safe_dump(vnets
, indent
=4, default_flow_style
=False))
629 # 3. Delete virtual networks gerardoX from underlay controller
630 print('3. Delete virtual networks gerardoX from underlay controller')
632 name
= vn
['fq_name'][2]
633 logger
.debug('Virtual network: {}'.format(name
))
635 name
= vn
['fq_name'][2]
636 if 'gerardo' in name
:
637 logger
.info('Virtual Network *gerardo*: {}, {}'.format(name
,vn
['uuid']))
638 if name
!= "gerardo":
639 print('Deleting Virtual Network: {}, {}'.format(name
,vn
['uuid']))
640 logger
.info('Deleting Virtual Network: {}, {}'.format(name
,vn
['uuid']))
641 juniper_contrail
._delete
_virtual
_network
(underlay_url
, vn
['uuid'])
643 # 4. Get virtual network (gerardo) from underlay controller
644 print('4. Get virtual network (gerardo) from underlay controller')
645 vnet1_info
= juniper_contrail
._get
_virtual
_network
(underlay_url
, 'c5d332f7-420a-4e2b-a7b1-b56a59f20c97')
646 print(yaml
.safe_dump(vnet1_info
, indent
=4, default_flow_style
=False))
648 # 5. Create virtual network in underlay controller
649 print('5. Create virtual network in underlay controller')
652 vnet2_id
, _
= juniper_contrail
._create
_virtual
_network
(underlay_url
, myname
, myvni
)
653 vnet2_info
= juniper_contrail
._get
_virtual
_network
(underlay_url
, vnet2_id
)
654 print(yaml
.safe_dump(vnet2_info
, indent
=4, default_flow_style
=False))
656 # 6. Delete virtual network in underlay controller
657 print('6. Delete virtual network in underlay controller')
658 juniper_contrail
._delete
_virtual
_network
(underlay_url
, vnet2_id
)
660 # 7. Read previously deleted virtual network in underlay controller
661 print('7. Read previously deleted virtual network in underlay controller')
663 vnet2_info
= juniper_contrail
._get
_virtual
_network
(underlay_url
, vnet2_id
)
665 print('FAILED. Network {} exists'.format(vnet2_id
))
667 print('OK. Network {} does not exist because it has been deleted'.format(vnet2_id
))
668 except Exception as e
:
669 logger
.info('Exception reading virtual networks from overlay controller: %s', e
)
673 #TODO: to be deleted (it comes from ONOS VPLS plugin)
674 service_type
= 'ELAN'
676 "service_endpoint_id": "switch1:ifz1",
677 "service_endpoint_encapsulation_type": "dot1q",
678 "service_endpoint_encapsulation_info": {
679 "switch_dpid": "0000000000000011",
685 "service_endpoint_id": "switch3:ifz1",
686 "service_endpoint_encapsulation_type": "dot1q",
687 "service_endpoint_encapsulation_info": {
688 "switch_dpid": "0000000000000031",
693 connection_points
= [conn_point_0
, conn_point_1
]
694 # service_uuid, created_items = juniper_contrail.create_connectivity_service(service_type, connection_points)
696 #print(created_items)
698 #juniper_contrail.delete_connectivity_service("5496dfea-27dc-457d-970d-b82bac266e5c"))
702 conn_info
= ['switch1:ifz1', 'switch3_ifz3']
703 juniper_contrail
.delete_connectivity_service("f7afc4de-556d-4b5a-8a12-12b5ef97d269", conn_info
)
706 "service_endpoint_id": "switch1:ifz1",
707 "service_endpoint_encapsulation_type": "dot1q",
708 "service_endpoint_encapsulation_info": {
709 "switch_dpid": "0000000000000011",
715 "service_endpoint_id": "switch1:ifz3",
716 "service_endpoint_encapsulation_type": "dot1q",
717 "service_endpoint_encapsulation_info": {
718 "switch_dpid": "0000000000000011",
724 "service_endpoint_id": "switch3_ifz3",
725 "service_endpoint_encapsulation_type": "dot1q",
726 "service_endpoint_encapsulation_info": {
727 "switch_dpid": "0000000000000033",
732 new_connection_points
= [conn_point_0
, conn_point_3
]
733 #conn_info = juniper_contrail.edit_connectivity_service("f7afc4de-556d-4b5a-8a12-12b5ef97d269", conn_info, new_connection_points)