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
24 from osm_ro
.wim
.sdnconn
import SdnConnectorBase
, SdnConnectorError
25 from osm_rosdn_juniper_contrail
.rest_lib
import ContrailHttp
26 from osm_rosdn_juniper_contrail
.rest_lib
import NotFound
27 from osm_rosdn_juniper_contrail
.rest_lib
import DuplicateFound
28 from osm_rosdn_juniper_contrail
.rest_lib
import HttpException
30 from osm_rosdn_juniper_contrail
.sdn_api
import UnderlayApi
33 class JuniperContrail(SdnConnectorBase
):
35 Juniper Contrail SDN plugin. The plugin interacts with Juniper Contrail Controller,
36 whose API details can be found in these links:
38 - https://github.com/tonyliu0592/contrail/wiki/API-Configuration-REST
39 - https://www.juniper.net/documentation/en_US/contrail19/information-products/pathway-pages/api-guide-1910/tutorial_with_rest.html
40 - https://github.com/tonyliu0592/contrail-toolbox/blob/master/sriov/sriov
42 _WIM_LOGGER
= "openmano.sdnconn.junipercontrail"
44 def __init__(self
, wim
, wim_account
, config
=None, logger
=None):
47 :param wim: (dict). Contains among others 'wim_url'
48 :param wim_account: (dict). Contains among others 'uuid' (internal id), 'name',
49 'sdn' (True if is intended for SDN-assist or False if intended for WIM), 'user', 'password'.
50 :param config: (dict or None): Particular information of plugin. These keys if present have a common meaning:
51 'mapping_not_needed': (bool) False by default or if missing, indicates that mapping is not needed.
52 'service_endpoint_mapping': (list) provides the internal endpoint mapping. The meaning is:
53 KEY meaning for WIM meaning for SDN assist
54 -------- -------- --------
55 device_id pop_switch_dpid compute_id
56 device_interface_id pop_switch_port compute_pci_address
57 service_endpoint_id wan_service_endpoint_id SDN_service_endpoint_id
58 service_mapping_info wan_service_mapping_info SDN_service_mapping_info
59 contains extra information if needed. Text in Yaml format
60 switch_dpid wan_switch_dpid SDN_switch_dpid
61 switch_port wan_switch_port SDN_switch_port
62 datacenter_id vim_account vim_account
63 id: (internal, do not use)
64 wim_id: (internal, do not use)
65 :param logger (logging.Logger): optional logger object. If none is passed 'openmano.sdn.sdnconn' is used.
67 self
.logger
= logger
or logging
.getLogger(self
._WIM
_LOGGER
)
68 self
.logger
.debug('wim: {}, wim_account: {}, config: {}'.format(wim
, wim_account
, config
))
69 super().__init
__(wim
, wim_account
, config
, logger
)
71 self
.user
= wim_account
.get("user")
72 self
.password
= wim_account
.get("password")
74 url
= wim
.get("wim_url") # underlay url
83 auth_url
= config
.get("auth_url")
84 self
.project
= config
.get("project")
85 self
.domain
= config
.get("domain")
86 self
.asn
= config
.get("asn")
87 self
.fabric
= config
.get("fabric")
88 self
.overlay_url
= config
.get("overlay_url")
89 self
.vni_range
= config
.get("vni_range")
92 raise SdnConnectorError("'url' must be provided")
93 if not url
.startswith("http"):
95 if not url
.endswith("/"):
99 if not self
.vni_range
:
100 self
.vni_range
= ['1000001-2000000']
101 self
.logger
.info("No vni_range was provided. Using ['1000001-2000000']")
102 self
.used_vni
= set()
105 if not auth_url
.startswith("http"):
106 auth_url
= "http://" + auth_url
107 if not auth_url
.endswith("/"):
108 auth_url
= auth_url
+ "/"
109 self
.auth_url
= auth_url
112 if not overlay_url
.startswith("http"):
113 overlay_url
= "http://" + overlay_url
114 if not overlay_url
.endswith("/"):
115 overlay_url
= overlay_url
+ "/"
116 self
.overlay_url
= overlay_url
119 raise SdnConnectorError("'project' must be provided")
121 # TODO: Get ASN from controller config; otherwise raise ERROR for the moment
122 raise SdnConnectorError("'asn' was not provided and it was not possible to obtain it")
124 # TODO: Get FABRIC from controller config; otherwise raise ERROR for the moment
125 raise SdnConnectorError("'fabric' was not provided and was not possible to obtain it")
127 self
.domain
= 'default-domain'
128 self
.logger
.info("No domain was provided. Using 'default-domain'")
130 underlay_api_config
= {
131 "auth_url": self
.auth_url
,
132 "project": self
.project
,
133 "domain": self
.domain
,
135 "fabric": self
.fabric
137 self
.underlay_api
= UnderlayApi(url
, underlay_api_config
, user
=self
.user
, password
=self
.password
, logger
=logger
)
139 self
._max
_duplicate
_retry
= 2
140 self
.logger
.info("Juniper Contrail Connector Initialized.")
142 def _generate_vni(self
):
144 Method to get unused VxLAN Network Identifier (VNI)
151 for vlanID_range
in self
.vni_range
:
153 start_vni
, end_vni
= map(int, vlanID_range
.replace(" ", "").split("-"))
154 for vni
in range(start_vni
, end_vni
+ 1):
155 if vni
not in self
.used_vni
:
157 except Exception as exp
:
158 raise SdnConnectorError("Exception {} occurred while searching a free VNI.".format(exp
))
160 raise SdnConnectorError("Unable to create the virtual network."\
161 " All VNI in VNI range {} are in use.".format(self
.vni_range
))
164 # Aux functions for testing
168 def get_overlay_url(self
):
169 return self
.overlay_url
171 def _create_port(self
, switch_id
, switch_port
, network
, vlan
):
173 1 - Look for virtual port groups for provided switch_id, switch_port using name
174 2 - It the virtual port group does not exist, create it
175 3 - Create virtual machine interface for the indicated network and vlan
177 self
.logger
.debug("create_port: switch_id: {}, switch_port: {}, network: {}, vlan: {}".format(
178 switch_id
, switch_port
, network
, vlan
))
180 # 1 - Check if the vpg exists
181 vpg_name
= self
.underlay_api
.get_vpg_name(switch_id
, switch_port
)
182 vpg
= self
.underlay_api
.get_vpg_by_name(vpg_name
)
184 # 2 - If it does not exist create it
185 vpg_id
, _
= self
.underlay_api
.create_vpg(switch_id
, switch_port
)
187 # Assign vpg_id from vpg
188 vpg_id
= vpg
.get("uuid")
191 vmi_id
, _
= self
.underlay_api
.create_vmi(switch_id
, switch_port
, network
, vlan
)
192 self
.logger
.debug("port created")
194 return vpg_id
, vmi_id
196 def _delete_port(self
, vpg_id
, vmi_id
):
197 self
.logger
.debug("delete port, vpg_id: {}, vmi_id: {}".format(vpg_id
, vmi_id
))
199 # 1 - Obtain vpg by id (if not vpg_id must have been error creating ig, nothing to be done)
201 vpg
= self
.underlay_api
.get_by_uuid("virtual-port-group", vpg_id
)
203 self
.logger
.warning("vpg: {} to be deleted not found".format(vpg_id
))
205 # 2 - Get vmi interfaces from vpg
206 vmi_list
= vpg
.get("virtual_machine_interface_refs")
208 # must have been an error during port creation when vmi is created
209 # may happen if there has been an error during creation
210 self
.logger
.warning("vpg: {} has not vmi, will delete nothing".format(vpg
))
212 num_vmis
= len(vmi_list
)
214 uuid
= vmi
.get("uuid")
216 self
.underlay_api
.delete_vmi(vmi
.get("uuid"))
217 num_vmis
= num_vmis
- 1
219 # 3 - If there are no more vmi delete the vpg
220 if not vmi_list
or num_vmis
== 0:
221 self
.underlay_api
.delete_vpg(vpg
.get("uuid"))
223 def check_credentials(self
):
224 """Check if the connector itself can access the SDN/WIM with the provided url (wim.wim_url),
225 user (wim_account.user), and password (wim_account.password)
228 SdnConnectorError: Issues regarding authorization, access to
229 external URLs, etc are detected.
231 self
.logger
.debug("")
233 resp
= self
.underlay_api
.check_auth()
235 raise SdnConnectorError('Empty response')
236 except Exception as e
:
237 self
.logger
.error('Error checking credentials')
238 raise SdnConnectorError('Error checking credentials: {}'.format(str(e
)))
240 def get_connectivity_service_status(self
, service_uuid
, conn_info
=None):
241 """Monitor the status of the connectivity service established
244 service_uuid (str): UUID of the connectivity service
245 conn_info (dict or None): Information returned by the connector
246 during the service creation/edition and subsequently stored in
250 dict: JSON/YAML-serializable dict that contains a mandatory key
251 ``sdn_status`` associated with one of the following values::
253 {'sdn_status': 'ACTIVE'}
254 # The service is up and running.
256 {'sdn_status': 'INACTIVE'}
257 # The service was created, but the connector
258 # cannot determine yet if connectivity exists
259 # (ideally, the caller needs to wait and check again).
261 {'sdn_status': 'DOWN'}
262 # Connection was previously established,
263 # but an error/failure was detected.
265 {'sdn_status': 'ERROR'}
266 # An error occurred when trying to create the service/
267 # establish the connectivity.
269 {'sdn_status': 'BUILD'}
270 # Still trying to create the service, the caller
271 # needs to wait and check again.
273 Additionally ``error_msg``(**str**) and ``sdn_info``(**dict**)
274 keys can be used to provide additional status explanation or
275 new information available for the connectivity service.
277 self
.logger
.debug("")
279 resp
= self
.http
.get_cmd(endpoint
='virtual-network/{}'.format(service_uuid
))
281 raise SdnConnectorError('Empty response')
283 vnet_info
= json
.loads(resp
)
285 # Check if conn_info reports error
286 if conn_info
.get("sdn_status") == "ERROR":
287 return {'sdn_status': 'ACTIVE', 'sdn_info': "conn_info indicates pending error"}
289 return {'sdn_status': 'ACTIVE', 'sdn_info': vnet_info
['virtual-network']}
291 return {'sdn_status': 'ERROR', 'sdn_info': 'not found'}
292 except SdnConnectorError
:
294 except HttpException
as e
:
295 self
.logger
.error("Error getting connectivity service: {}".format(e
))
296 raise SdnConnectorError("Exception deleting connectivity service: {}".format(str(e
)))
297 except Exception as e
:
298 self
.logger
.error('Exception getting connectivity service info: %s', e
, exc_info
=True)
299 return {'sdn_status': 'ERROR', 'error_msg': str(e
)}
302 def create_connectivity_service(self
, service_type
, connection_points
, **kwargs
):
304 Establish SDN/WAN connectivity between the endpoints
305 :param service_type: (str): ``ELINE`` (L2), ``ELAN`` (L2), ``ETREE`` (L2), ``L3``.
306 :param connection_points: (list): each point corresponds to
307 an entry point to be connected. For WIM: from the DC to the transport network.
308 For SDN: Compute/PCI to the transport network. One
309 connection point serves to identify the specific access and
310 some other service parameters, such as encapsulation type.
311 Each item of the list is a dict with:
312 "service_endpoint_id": (str)(uuid) Same meaning that for 'service_endpoint_mapping' (see __init__)
313 In case the config attribute mapping_not_needed is True, this value is not relevant. In this case
314 it will contain the string "device_id:device_interface_id"
315 "service_endpoint_encapsulation_type": None, "dot1q", ...
316 "service_endpoint_encapsulation_info": (dict) with:
317 "vlan": ..., (int, present if encapsulation is dot1q)
318 "vni": ... (int, present if encapsulation is vxlan),
319 "peers": [(ipv4_1), (ipv4_2)] (present if encapsulation is vxlan)
321 "device_id": ..., same meaning that for 'service_endpoint_mapping' (see __init__)
322 "device_interface_id": same meaning that for 'service_endpoint_mapping' (see __init__)
323 "switch_dpid": ..., present if mapping has been found for this device_id,device_interface_id
324 "switch_port": ... present if mapping has been found for this device_id,device_interface_id
325 "service_mapping_info": present if mapping has been found for this device_id,device_interface_id
326 :param kwargs: For future versions:
327 bandwidth (int): value in kilobytes
328 latency (int): value in milliseconds
329 Other QoS might be passed as keyword arguments.
330 :return: tuple: ``(service_id, conn_info)`` containing:
331 - *service_uuid* (str): UUID of the established connectivity service
332 - *conn_info* (dict or None): Information to be stored at the database (or ``None``).
333 This information will be provided to the :meth:`~.edit_connectivity_service` and :obj:`~.delete`.
334 **MUST** be JSON/YAML-serializable (plain data structures).
335 :raises: SdnConnectorException: In case of error. Nothing should be created in this case.
336 Provide the parameter http_code
338 # Step 1. Check in the overlay controller the virtual network created by the VIM
339 # Best option: get network id of the VIM as param (if the VIM already created the network),
340 # and do a request to the controller of the virtual networks whose VIM network id is the provided
341 # Next best option: obtain the network by doing a request to the controller
342 # of the virtual networks using the VLAN ID of any service endpoint.
343 # 1.1 Read VLAN ID from a service endpoint
344 # 1.2 Look for virtual networks with "Provider Network" including a VLAN ID.
345 # 1.3 If more than one, ERROR
346 # Step 2. Modify the existing virtual network in the overlay controller
347 # 2.1 Add VNI (VxLAN Network Identifier - one free from the provided range)
348 # 2.2 Add RouteTarget (RT) ('ASN:VNI', ASN = Autonomous System Number, provided as param or read from controller config)
349 # Step 3. Create a virtual network in the underlay controller
350 # 3.1 Create virtual network (name, VNI, RT)
351 # If the network already existed in the overlay controller, we should use the same name
352 # name = 'osm-plugin-' + overlay_name
354 # name = 'osm-plugin-' + VNI
355 self
.logger
.info("create_connectivity_service, service_type: {}, connection_points: {}".
356 format(service_type
, connection_points
))
357 if service_type
.lower() != 'elan':
358 raise SdnConnectorError('Only ELAN network type is supported by Juniper Contrail.')
366 vlan
= self
._get
_vlan
(connection_points
)
367 self
.logger
.debug("Provided vlan: {}".format(vlan
))
369 # 2 - Obtain free VNI
370 vni
= self
._generate
_vni
()
371 self
.logger
.debug("VNI: {}".format(vni
))
373 # 3 - Create virtual network (name, VNI, RT), by the moment the name will use VNI
375 while retry
< self
._max
_duplicate
_retry
:
377 vnet_name
= 'osm-plugin-' + str(vni
)
378 vnet_id
, _
= self
.underlay_api
.create_virtual_network(vnet_name
, vni
)
379 self
.used_vni
.add(vni
)
381 except DuplicateFound
as e
:
382 self
.logger
.debug("Duplicate error for vnet_name: {}".format(vnet_name
))
383 self
.used_vni
.add(vni
)
385 if retry
>= self
._max
_duplicate
_retry
:
388 # Try to obtain a new vni
389 vni
= self
._generate
_vni
()
396 "connection_points": conn_info_cp
# dict with port_name as key
399 # 4 - Create a port for each endpoint
400 for cp
in connection_points
:
401 switch_id
= cp
.get("service_endpoint_encapsulation_info").get("switch_dpid")
402 switch_port
= cp
.get("service_endpoint_encapsulation_info").get("switch_port")
403 vpg_id
, vmi_id
= self
._create
_port
(switch_id
, switch_port
, vnet_name
, vlan
)
405 cp_added
["vpg_id"] = vpg_id
406 cp_added
["vmi_id"] = vmi_id
407 conn_info_cp
[self
.underlay_api
.get_vpg_name(switch_id
, switch_port
)] = cp_added
409 return vnet_id
, conn_info
410 self
.logger
.info("created connectivity service, uuid: {}, name: {}".format(vnet_id
, vnet_name
))
411 except Exception as e
:
413 if isinstance(e
, SdnConnectorError
) or isinstance(e
, HttpException
):
414 self
.logger
.error("Error creating connectivity service: {}".format(e
))
416 self
.logger
.error("Error creating connectivity service: {}".format(e
), exc_info
=True)
419 # If nothing is created raise error else return what has been created and mask as error
421 raise SdnConnectorError("Exception create connectivity service: {}".format(str(e
)))
423 conn_info
["sdn_status"] = "ERROR"
424 # iterate over not added connection_points and add but marking them as error
425 for cp
in connection_points
[len(conn_info_cp
):]:
427 cp_error
["sdn_status"] = "ERROR"
428 switch_id
= cp
.get("service_endpoint_encapsulation_info").get("switch_dpid")
429 switch_port
= cp
.get("service_endpoint_encapsulation_info").get("switch_port")
430 conn_info_cp
[self
.underlay_api
.get_vpg_name(switch_id
, switch_port
)] = cp_error
431 return vnet_id
, conn_info
433 def delete_connectivity_service(self
, service_uuid
, conn_info
=None):
435 Disconnect multi-site endpoints previously connected
437 :param service_uuid: The one returned by create_connectivity_service
438 :param conn_info: The one returned by last call to 'create_connectivity_service' or 'edit_connectivity_service'
439 if they do not return None
441 :raises: SdnConnectorException: In case of error. The parameter http_code must be filled
443 self
.logger
.info("delete_connectivity_service vnet_name: {}, connection_points: {}".
444 format(service_uuid
, conn_info
))
447 vnet_uuid
= service_uuid
448 vnet_name
= conn_info
["vnet"]["name"] # always should exist as the network is the first thing created
449 connection_points
= conn_info
["connection_points"].values()
450 vlan
= self
._get
_vlan
(connection_points
)
452 # 1: For each connection point delete vlan from vpg and it is is the
453 # last one, delete vpg
454 for cp
in connection_points
:
455 self
._delete
_port
(cp
.get("vpg_id"), cp
.get("vmi_id"))
458 self
.underlay_api
.delete_virtual_network(vnet_uuid
)
459 except SdnConnectorError
:
461 except HttpException
as e
:
462 self
.logger
.error("Error deleting connectivity service: {}".format(e
))
463 raise SdnConnectorError("Exception deleting connectivity service: {}".format(str(e
)))
464 except Exception as e
:
465 self
.logger
.error("Error deleting connectivity service: {}".format(e
), exc_info
=True)
466 raise SdnConnectorError("Exception deleting connectivity service: {}".format(str(e
)))
470 def _get_vlan(connection_points
):
472 for cp
in connection_points
:
473 cp_vlan
= cp
.get("service_endpoint_encapsulation_info").get("vlan")
478 raise SdnConnectorError("More that one cp provided")
481 def edit_connectivity_service(self
, service_uuid
, conn_info
= None, connection_points
= None, **kwargs
):
482 """ Change an existing connectivity service.
484 This method's arguments and return value follow the same convention as
485 :meth:`~.create_connectivity_service`.
487 :param service_uuid: UUID of the connectivity service.
488 :param conn_info: (dict or None): Information previously returned by last call to create_connectivity_service
489 or edit_connectivity_service
490 :param connection_points: (list): If provided, the old list of connection points will be replaced.
491 :param kwargs: Same meaning that create_connectivity_service
492 :return: dict or None: Information to be updated and stored at the database.
493 When ``None`` is returned, no information should be changed.
494 When an empty dict is returned, the database record will be deleted.
495 **MUST** be JSON/YAML-serializable (plain data structures).
497 SdnConnectorException: In case of error.
499 # 0 - Check if there are connection_points marked as error and delete them
500 # 1 - Compare conn_info (old connection points) and connection_points (new ones to be applied):
501 # Obtain list of connection points to be added and to be deleted
502 # Obtain vlan and check it has not changed
503 # 2 - Obtain network: Check vnet exists and obtain name
504 # 3 - Delete unnecesary ports
506 self
.logger
.info("edit connectivity service, service_uuid: {}, conn_info: {}, "
507 "connection points: {} ".format(service_uuid
, conn_info
, connection_points
))
509 # conn_info should always exist and have connection_points and vnet elements
510 old_cp
= conn_info
.get("connection_points", {})
511 old_vlan
= self
._get
_vlan
(old_cp
)
513 # Check if an element of old_cp is marked as error, in case it is delete it
514 # Not return a new conn_info in this case because it is only partial information
515 # Current conn_info already marks ports as error
517 delete_conn_info
= []
519 if cp
.get("sdn_status") == "ERROR":
520 switch_id
= cp
.get("service_endpoint_encapsulation_info").get("switch_dpid")
521 switch_port
= cp
.get("service_endpoint_encapsulation_info").get("switch_port")
522 self
._delete
_port
(switch_id
, switch_port
, old_vlan
)
523 delete_conn_info
.append(self
.underlay_api
.get_vpg_name(switch_id
, switch_port
))
525 for i
in delete_conn_info
:
528 # Delete vnet status if exists (possibly marked as error)
529 if conn_info
.get("vnet",{}).get("sdn_status"):
530 del conn_info
["vnet"]["sdn_status"]
531 except HttpException
as e
:
532 self
.logger
.error("Error trying to delete old ports marked as error: {}".format(e
))
533 raise SdnConnectorError(e
)
534 except SdnConnectorError
as e
:
535 self
.logger
.error("Error trying to delete old ports marked as error: {}".format(e
))
537 except Exception as e
:
538 self
.logger
.error("Error trying to delete old ports marked as error: {}".format(e
), exc_info
=True)
539 raise SdnConnectorError("Error trying to delete old ports marked as error: {}".format(e
))
541 if connection_points
:
543 # Check and obtain what should be added and deleted, if there is an error here raise an exception
546 vlan
= self
._get
_vlan
(connection_points
)
548 old_port_list
= ["{}_{}".format(cp
["service_endpoint_encapsulation_info"]["switch_dpid"],
549 cp
["service_endpoint_encapsulation_info"]["switch_port"])
550 for cp
in old_cp
.values()]
551 port_list
= ["{}_{}".format(cp
["service_endpoint_encapsulation_info"]["switch_dpid"],
552 cp
["service_endpoint_encapsulation_info"]["switch_port"])
553 for cp
in connection_points
]
554 to_delete_ports
= list(set(old_port_list
) - set(port_list
))
555 to_add_ports
= list(set(port_list
) - set(old_port_list
))
558 vnet
= self
.underlay_api
.get_virtual_network(self
.get_url(), service_uuid
)
559 vnet_name
= vnet
["name"]
561 except SdnConnectorError
:
563 except Exception as e
:
564 self
.logger
.error("Error edit connectivity service: {}".format(e
), exc_info
=True)
565 raise SdnConnectorError("Exception edit connectivity service: {}".format(str(e
)))
568 # Delete unneeded ports and add new ones: if there is an error return conn_info
570 # Connection points returned in con_info should reflect what has (and should as ERROR) be done
571 # Start with old cp dictionary and modify it as we work
572 conn_info_cp
= old_cp
574 # Delete unneeded ports
575 for port_name
in conn_info_cp
.keys():
576 if port_name
in to_delete_ports
:
577 cp
= conn_info_cp
[port_name
]
578 switch_id
= cp
.get("service_endpoint_encapsulation_info").get("switch_dpid")
579 switch_port
= cp
.get("service_endpoint_encapsulation_info").get("switch_port")
580 self
.logger
.debug("delete port switch_id, switch_port: {}".format(switch_id
, switch_port
))
581 self
._delete
_port
(switch_id
, switch_port
, vlan
)
582 del conn_info_cp
[port_name
]
585 for cp
in connection_points
:
586 if port_name
in to_add_ports
:
587 switch_id
= cp
.get("service_endpoint_encapsulation_info").get("switch_dpid")
588 switch_port
= cp
.get("service_endpoint_encapsulation_info").get("switch_port")
589 self
.logger
.debug("add port switch_id, switch_port: {}".format(switch_id
, switch_port
))
590 self
._create
_port
(switch_id
, switch_port
, vnet_name
, vlan
)
591 conn_info_cp
[port_name
]
593 conn_info
["connection_points"] = conn_info_cp
596 except Exception as e
:
598 if isinstance(e
, SdnConnectorError
) or isinstance(e
, HttpException
):
599 self
.logger
.error("Error edit connectivity service: {}".format(e
), exc_info
=True)
601 self
.logger
.error("Error edit connectivity service: {}".format(e
))
603 # There has been an error mount conn_info_cp marking as error cp that should
604 # have been deleted but have not or should have been added
605 for port_name
, cp
in conn_info_cp
.items():
606 if port_name
in to_delete_ports
:
607 cp
["sdn_status"] = "ERROR"
609 for cp
in connection_points
:
610 switch_id
= cp
.get("service_endpoint_encapsulation_info").get("switch_dpid")
611 switch_port
= cp
.get("service_endpoint_encapsulation_info").get("switch_port")
612 port_name
= self
.underlay_api
.get_vpg_name(switch_id
, switch_port
)
613 if port_name
in to_add_ports
:
615 cp_error
["sdn_status"] = "ERROR"
616 conn_info_cp
[port_name
] = cp_error
618 conn_info
["sdn_status"] = "ERROR"
619 conn_info
["connection_points"] = conn_info_cp
624 # Connection points have not changed, so do nothing
625 self
.logger
.info("no new connection_points provided, nothing to be done")
629 if __name__
== '__main__':
631 log_format
= "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)s %(funcName)s(): %(message)s"
632 log_formatter
= logging
.Formatter(log_format
, datefmt
='%Y-%m-%dT%H:%M:%S')
633 handler
= logging
.StreamHandler()
634 handler
.setFormatter(log_formatter
)
635 logger
= logging
.getLogger('openmano.sdnconn.junipercontrail')
636 #logger.setLevel(level=logging.ERROR)
637 #logger.setLevel(level=logging.INFO)
638 logger
.setLevel(level
=logging
.DEBUG
)
639 logger
.addHandler(handler
)
642 with
open('test.yaml') as f
:
643 config
= yaml
.safe_load(f
.read())
644 wim
= {'wim_url': config
.pop('wim_url')}
645 wim_account
= {'user': config
.pop('user'), 'password': config
.pop('password')}
646 logger
.info('wim: {}, wim_account: {}, config: {}'.format(wim
, wim_account
, config
))
649 juniper_contrail
= JuniperContrail(wim
=wim
, wim_account
=wim_account
, config
=config
, logger
=logger
)
654 vni
= juniper_contrail
._generate
_vni
()
655 juniper_contrail
.used_vni
.add(vni
)
656 print(juniper_contrail
.used_vni
)
657 juniper_contrail
.used_vni
.remove(1000003)
658 print(juniper_contrail
.used_vni
)
660 vni
= juniper_contrail
._generate
_vni
()
661 juniper_contrail
.used_vni
.add(vni
)
662 print(juniper_contrail
.used_vni
)
663 # 0. Check credentials
664 print('0. Check credentials')
665 juniper_contrail
.check_credentials()
667 underlay_url
= juniper_contrail
.get_url()
668 overlay_url
= juniper_contrail
.get_overlay_url()
671 vni
= juniper_contrail
._generate
_vni
()
672 juniper_contrail
.used_vni
.add(vni
)
673 print(juniper_contrail
.used_vni
)
674 juniper_contrail
.used_vni
.remove(1000003)
675 print(juniper_contrail
.used_vni
)
677 vni
= juniper_contrail
._generate
_vni
()
678 juniper_contrail
.used_vni
.add(vni
)
679 print(juniper_contrail
.used_vni
)
680 # 1. Read virtual networks from overlay controller
681 print('1. Read virtual networks from overlay controller')
683 vnets
= juniper_contrail
._get
_virtual
_networks
(overlay_url
)
684 logger
.debug(yaml
.safe_dump(vnets
, indent
=4, default_flow_style
=False))
686 except Exception as e
:
687 logger
.error('Exception reading virtual networks from overlay controller: %s', e
)
689 # 2. Read virtual networks from underlay controller
690 print('2. Read virtual networks from underlay controller')
691 vnets
= juniper_contrail
._get
_virtual
_networks
(underlay_url
)
692 logger
.debug(yaml
.safe_dump(vnets
, indent
=4, default_flow_style
=False))
694 # 3. Delete virtual networks gerardoX from underlay controller
695 print('3. Delete virtual networks gerardoX from underlay controller')
697 name
= vn
['fq_name'][2]
698 logger
.debug('Virtual network: {}'.format(name
))
700 name
= vn
['fq_name'][2]
701 if 'gerardo' in name
:
702 logger
.info('Virtual Network *gerardo*: {}, {}'.format(name
,vn
['uuid']))
703 if name
!= "gerardo":
704 print('Deleting Virtual Network: {}, {}'.format(name
,vn
['uuid']))
705 logger
.info('Deleting Virtual Network: {}, {}'.format(name
,vn
['uuid']))
706 juniper_contrail
._delete
_virtual
_network
(underlay_url
, vn
['uuid'])
708 # 4. Get virtual network (gerardo) from underlay controller
709 print('4. Get virtual network (gerardo) from underlay controller')
710 vnet1_info
= juniper_contrail
._get
_virtual
_network
(underlay_url
, 'c5d332f7-420a-4e2b-a7b1-b56a59f20c97')
711 print(yaml
.safe_dump(vnet1_info
, indent
=4, default_flow_style
=False))
713 # 5. Create virtual network in underlay controller
714 print('5. Create virtual network in underlay controller')
717 vnet2_id
, _
= juniper_contrail
._create
_virtual
_network
(underlay_url
, myname
, myvni
)
718 vnet2_info
= juniper_contrail
._get
_virtual
_network
(underlay_url
, vnet2_id
)
719 print(yaml
.safe_dump(vnet2_info
, indent
=4, default_flow_style
=False))
721 # 6. Delete virtual network in underlay controller
722 print('6. Delete virtual network in underlay controller')
723 juniper_contrail
._delete
_virtual
_network
(underlay_url
, vnet2_id
)
725 # 7. Read previously deleted virtual network in underlay controller
726 print('7. Read previously deleted virtual network in underlay controller')
728 vnet2_info
= juniper_contrail
._get
_virtual
_network
(underlay_url
, vnet2_id
)
730 print('FAILED. Network {} exists'.format(vnet2_id
))
732 print('OK. Network {} does not exist because it has been deleted'.format(vnet2_id
))
733 except Exception as e
:
734 logger
.info('Exception reading virtual networks from overlay controller: %s', e
)
746 # 1 - Create a new virtual network
747 vnet2_id
, vnet2_created
= juniper_contrail
._create
_virtual
_network
(underlay_url
, net_name
, net_vni
)
748 print("Created virtual network:")
750 print(yaml
.safe_dump(vnet2_created
, indent
=4, default_flow_style
=False))
751 print("Get virtual network:")
752 vnet2_info
= juniper_contrail
._get
_virtual
_network
(underlay_url
, vnet2_id
)
753 print(json
.dumps(vnet2_info
, indent
=4))
756 # 2 - Create a new virtual port group
757 vpg_id
, vpg_info
= juniper_contrail
._create
_vpg
(underlay_url
, switch_1
, port_1
, net_name
, net_vlan
)
758 print("Created virtual port group:")
760 print(json
.dumps(vpg_info
, indent
=4))
762 print("Get virtual network:")
763 vnet2_info
= juniper_contrail
._get
_virtual
_network
(underlay_url
, vnet2_id
)
764 print(yaml
.safe_dump(vnet2_info
, indent
=4, default_flow_style
=False))
767 # 3 - Create a new virtual machine interface
768 vmi_id
, vmi_info
= juniper_contrail
._create
_vmi
(underlay_url
, switch_1
, port_1
, net_name
, net_vlan
)
769 print("Created virtual machine interface:")
771 print(yaml
.safe_dump(vmi_info
, indent
=4, default_flow_style
=False))
773 # 4 - Create a second virtual port group
774 # 5 - Create a second virtual machine interface
776 ### Test rapido de modificación de requests:
777 # Ver que metodos siguen funcionando y cuales no e irlos corrigiendo
780 vnets = juniper_contrail._get_virtual_networks(underlay_url)
781 logger.debug("Virtual networks:")
782 logger.debug(json.dumps(vnets, indent=2))
784 vpgs = juniper_contrail._get_vpgs(underlay_url)
785 logger.debug("Virtual port groups:")
786 logger.debug(json.dumps(vpgs, indent=2))
792 vmi_uuid = "dbfd2099-b895-459e-98af-882d77d968c1"
793 vmi = juniper_contrail._get_vmi(underlay_url, vmi_uuid)
794 logger.debug("Virtual machine interface:")
795 logger.debug(json.dumps(vmi, indent=2))
798 logger.debug("Delete vmi")
799 juniper_contrail._delete_vmi(underlay_url, vmi_uuid)
804 vpg_uuid = "85156474-d1a5-44c0-9d8b-8f690f39d27e"
805 vpg = juniper_contrail._get_vpg(underlay_url, vpg_uuid)
806 logger.debug("Virtual port group:")
807 logger.debug(json.dumps(vpg, indent=2))
809 vpg = juniper_contrail._delete_vpg(underlay_url, vpg_uuid)
812 # 1 - Obtain virtual network
814 vnet_uuid = "68457d61-6558-4d38-a03d-369a9de803ea"
815 vnet = juniper_contrail._get_virtual_network(underlay_url, vnet_uuid)
816 logger.debug("Virtual network:")
817 logger.debug(json.dumps(vnet, indent=2))
818 # Delete virtual network
819 juniper_contrail._delete_virtual_network(underlay_url, vnet_uuid)