blob: 467d05df8cf1419199e0fc861b9baec5db7199ca [file] [log] [blame]
tiernoed3e4d42019-10-21 15:31:27 +00001# -*- coding: utf-8 -*-
2##
3# Copyright 2018 University of Bristol - High Performance Networks Research
4# Group
5# All Rights Reserved.
6#
7# Contributors: Anderson Bravalheri, Dimitrios Gkounis, Abubakar Siddique
8# Muqaddas, Navdeep Uniyal, Reza Nejabati and Dimitra Simeonidou
9#
10# Licensed under the Apache License, Version 2.0 (the "License"); you may
11# not use this file except in compliance with the License. You may obtain
12# a copy of the License at
13#
14# http://www.apache.org/licenses/LICENSE-2.0
15#
16# Unless required by applicable law or agreed to in writing, software
17# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
18# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
19# License for the specific language governing permissions and limitations
20# under the License.
21#
22# For those usages not covered by the Apache License, Version 2.0 please
23# contact with: <highperformance-networks@bristol.ac.uk>
24#
25# Neither the name of the University of Bristol nor the names of its
26# contributors may be used to endorse or promote products derived from
27# this software without specific prior written permission.
28#
29# This work has been performed in the context of DCMS UK 5G Testbeds
30# & Trials Programme and in the framework of the Metro-Haul project -
31# funded by the European Commission under Grant number 761727 through the
32# Horizon 2020 and 5G-PPP programmes.
33##
34"""The SDN connector is responsible for establishing both wide area network connectivity (WIM)
35and intranet SDN connectivity.
36
37It receives information from ports to be connected .
38"""
sousaedu80135b92021-02-17 15:05:18 +010039
tierno72774862020-05-04 11:44:15 +000040from http import HTTPStatus
sousaedu049cbb12022-01-05 11:39:35 +000041import logging
tiernoed3e4d42019-10-21 15:31:27 +000042
43
tierno72774862020-05-04 11:44:15 +000044class SdnConnectorError(Exception):
tiernoed3e4d42019-10-21 15:31:27 +000045 """Base Exception for all connector related errors
sousaedu80135b92021-02-17 15:05:18 +010046 provide the parameter 'http_code' (int) with the error code:
47 Bad_Request = 400
48 Unauthorized = 401 (e.g. credentials are not valid)
49 Not_Found = 404 (e.g. try to edit or delete a non existing connectivity service)
50 Forbidden = 403
51 Method_Not_Allowed = 405
52 Not_Acceptable = 406
53 Request_Timeout = 408 (e.g timeout reaching server, or cannot reach the server)
54 Conflict = 409
55 Service_Unavailable = 503
56 Internal_Server_Error = 500
tiernoed3e4d42019-10-21 15:31:27 +000057 """
sousaedu80135b92021-02-17 15:05:18 +010058
tierno72774862020-05-04 11:44:15 +000059 def __init__(self, message, http_code=HTTPStatus.INTERNAL_SERVER_ERROR.value):
60 Exception.__init__(self, message)
61 self.http_code = http_code
tiernoed3e4d42019-10-21 15:31:27 +000062
63
64class SdnConnectorBase(object):
65 """Abstract base class for all the SDN connectors
66
67 Arguments:
68 wim (dict): WIM record, as stored in the database
69 wim_account (dict): WIM account record, as stored in the database
70 config
71 The arguments of the constructor are converted to object attributes.
72 An extra property, ``service_endpoint_mapping`` is created from ``config``.
73 """
sousaedu80135b92021-02-17 15:05:18 +010074
tiernoed3e4d42019-10-21 15:31:27 +000075 def __init__(self, wim, wim_account, config=None, logger=None):
76 """
tiernoed3e4d42019-10-21 15:31:27 +000077 :param wim: (dict). Contains among others 'wim_url'
78 :param wim_account: (dict). Contains among others 'uuid' (internal id), 'name',
79 'sdn' (True if is intended for SDN-assist or False if intended for WIM), 'user', 'password'.
80 :param config: (dict or None): Particular information of plugin. These keys if present have a common meaning:
81 'mapping_not_needed': (bool) False by default or if missing, indicates that mapping is not needed.
82 'service_endpoint_mapping': (list) provides the internal endpoint mapping. The meaning is:
sousaedu80135b92021-02-17 15:05:18 +010083 KEY meaning for WIM meaning for SDN assist
tiernoed3e4d42019-10-21 15:31:27 +000084 -------- -------- --------
sousaedu80135b92021-02-17 15:05:18 +010085 device_id pop_switch_dpid compute_id
86 device_interface_id pop_switch_port compute_pci_address
87 service_endpoint_id wan_service_endpoint_id SDN_service_endpoint_id
88 service_mapping_info wan_service_mapping_info SDN_service_mapping_info
tiernoed3e4d42019-10-21 15:31:27 +000089 contains extra information if needed. Text in Yaml format
sousaedu80135b92021-02-17 15:05:18 +010090 switch_dpid wan_switch_dpid SDN_switch_dpid
91 switch_port wan_switch_port SDN_switch_port
tiernoed3e4d42019-10-21 15:31:27 +000092 datacenter_id vim_account vim_account
sousaedu80135b92021-02-17 15:05:18 +010093 id: (internal, do not use)
94 wim_id: (internal, do not use)
tiernoed3e4d42019-10-21 15:31:27 +000095 :param logger (logging.Logger): optional logger object. If none is passed 'openmano.sdn.sdnconn' is used.
96 """
sousaedu80135b92021-02-17 15:05:18 +010097 self.logger = logger or logging.getLogger("ro.sdn")
tiernoed3e4d42019-10-21 15:31:27 +000098 self.wim = wim
99 self.wim_account = wim_account
100 self.config = config or {}
sousaedu80135b92021-02-17 15:05:18 +0100101 self.service_endpoint_mapping = self.config.get("service_endpoint_mapping", [])
tiernoed3e4d42019-10-21 15:31:27 +0000102
103 def check_credentials(self):
104 """Check if the connector itself can access the SDN/WIM with the provided url (wim.wim_url),
105 user (wim_account.user), and password (wim_account.password)
106
107 Raises:
108 SdnConnectorError: Issues regarding authorization, access to
109 external URLs, etc are detected.
110 """
111 raise NotImplementedError
112
113 def get_connectivity_service_status(self, service_uuid, conn_info=None):
114 """Monitor the status of the connectivity service established
115
116 Arguments:
117 service_uuid (str): UUID of the connectivity service
118 conn_info (dict or None): Information returned by the connector
119 during the service creation/edition and subsequently stored in
120 the database.
121
122 Returns:
123 dict: JSON/YAML-serializable dict that contains a mandatory key
124 ``sdn_status`` associated with one of the following values::
125
126 {'sdn_status': 'ACTIVE'}
127 # The service is up and running.
128
129 {'sdn_status': 'INACTIVE'}
130 # The service was created, but the connector
131 # cannot determine yet if connectivity exists
132 # (ideally, the caller needs to wait and check again).
133
134 {'sdn_status': 'DOWN'}
135 # Connection was previously established,
136 # but an error/failure was detected.
137
138 {'sdn_status': 'ERROR'}
139 # An error occurred when trying to create the service/
140 # establish the connectivity.
141
142 {'sdn_status': 'BUILD'}
143 # Still trying to create the service, the caller
144 # needs to wait and check again.
145
146 Additionally ``error_msg``(**str**) and ``sdn_info``(**dict**)
147 keys can be used to provide additional status explanation or
148 new information available for the connectivity service.
149 """
150 raise NotImplementedError
151
152 def create_connectivity_service(self, service_type, connection_points, **kwargs):
153 """
sousaedu80135b92021-02-17 15:05:18 +0100154 Establish SDN/WAN connectivity between the endpoints
tiernoed3e4d42019-10-21 15:31:27 +0000155 :param service_type: (str): ``ELINE`` (L2), ``ELAN`` (L2), ``ETREE`` (L2), ``L3``.
156 :param connection_points: (list): each point corresponds to
157 an entry point to be connected. For WIM: from the DC to the transport network.
158 For SDN: Compute/PCI to the transport network. One
159 connection point serves to identify the specific access and
160 some other service parameters, such as encapsulation type.
161 Each item of the list is a dict with:
162 "service_endpoint_id": (str)(uuid) Same meaning that for 'service_endpoint_mapping' (see __init__)
163 In case the config attribute mapping_not_needed is True, this value is not relevant. In this case
164 it will contain the string "device_id:device_interface_id"
165 "service_endpoint_encapsulation_type": None, "dot1q", ...
166 "service_endpoint_encapsulation_info": (dict) with:
167 "vlan": ..., (int, present if encapsulation is dot1q)
168 "vni": ... (int, present if encapsulation is vxlan),
169 "peers": [(ipv4_1), (ipv4_2)] (present if encapsulation is vxlan)
170 "mac": ...
171 "device_id": ..., same meaning that for 'service_endpoint_mapping' (see __init__)
172 "device_interface_id": same meaning that for 'service_endpoint_mapping' (see __init__)
173 "switch_dpid": ..., present if mapping has been found for this device_id,device_interface_id
174 "swith_port": ... present if mapping has been found for this device_id,device_interface_id
175 "service_mapping_info": present if mapping has been found for this device_id,device_interface_id
176 :param kwargs: For future versions:
177 bandwidth (int): value in kilobytes
178 latency (int): value in milliseconds
179 Other QoS might be passed as keyword arguments.
180 :return: tuple: ``(service_id, conn_info)`` containing:
181 - *service_uuid* (str): UUID of the established connectivity service
182 - *conn_info* (dict or None): Information to be stored at the database (or ``None``).
183 This information will be provided to the :meth:`~.edit_connectivity_service` and :obj:`~.delete`.
184 **MUST** be JSON/YAML-serializable (plain data structures).
185 :raises: SdnConnectorException: In case of error. Nothing should be created in this case.
186 Provide the parameter http_code
187 """
188 raise NotImplementedError
189
190 def delete_connectivity_service(self, service_uuid, conn_info=None):
191 """
192 Disconnect multi-site endpoints previously connected
193
194 :param service_uuid: The one returned by create_connectivity_service
195 :param conn_info: The one returned by last call to 'create_connectivity_service' or 'edit_connectivity_service'
196 if they do not return None
197 :return: None
198 :raises: SdnConnectorException: In case of error. The parameter http_code must be filled
199 """
200 raise NotImplementedError
201
sousaedu80135b92021-02-17 15:05:18 +0100202 def edit_connectivity_service(
203 self, service_uuid, conn_info=None, connection_points=None, **kwargs
204 ):
205 """Change an existing connectivity service.
tiernoed3e4d42019-10-21 15:31:27 +0000206
207 This method's arguments and return value follow the same convention as
208 :meth:`~.create_connectivity_service`.
209
210 :param service_uuid: UUID of the connectivity service.
211 :param conn_info: (dict or None): Information previously returned by last call to create_connectivity_service
212 or edit_connectivity_service
213 :param connection_points: (list): If provided, the old list of connection points will be replaced.
214 :param kwargs: Same meaning that create_connectivity_service
215 :return: dict or None: Information to be updated and stored at the database.
216 When ``None`` is returned, no information should be changed.
217 When an empty dict is returned, the database record will be deleted.
218 **MUST** be JSON/YAML-serializable (plain data structures).
219 Raises:
220 SdnConnectorException: In case of error.
221 """
222
223 def clear_all_connectivity_services(self):
224 """Delete all WAN Links in a WIM.
225
226 This method is intended for debugging only, and should delete all the
227 connections controlled by the WIM/SDN, not only the connections that
228 a specific RO is aware of.
229
230 Raises:
231 SdnConnectorException: In case of error.
232 """
233 raise NotImplementedError
234
235 def get_all_active_connectivity_services(self):
236 """Provide information about all active connections provisioned by a
237 WIM.
238
239 Raises:
240 SdnConnectorException: In case of error.
241 """
242 raise NotImplementedError