c99627c3958be14899379a377319a76c7a97c5e2
[osm/RO.git] / RO-SDN-dynpac / osm_rosdn_dynpac / wimconn_dynpac.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 ##
5 # Copyright 2018 David GarcĂ­a, University of the Basque Country
6 # Copyright 2018 University of the Basque Country
7 # This file is part of openmano
8 # All Rights Reserved.
9 # Contact information at http://i2t.ehu.eus
10 #
11 # # Licensed under the Apache License, Version 2.0 (the "License");
12 # you may not use this file except in compliance with the License.
13 # You may obtain a copy of the License at
14 #
15 # http://www.apache.org/licenses/LICENSE-2.0
16 #
17 # Unless required by applicable law or agreed to in writing, software
18 # distributed under the License is distributed on an "AS IS" BASIS,
19 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
20 # implied.
21 # See the License for the specific language governing permissions and
22 # limitations under the License.
23
24 import requests
25 import json
26 import logging
27 from enum import Enum
28
29 from osm_ro_plugin.sdnconn import SdnConnectorBase, SdnConnectorError
30
31
32 class SdnError(Enum):
33 UNREACHABLE = 'Unable to reach the WIM.',
34 SERVICE_TYPE_ERROR = 'Unexpected service_type. Only "L2" is accepted.',
35 CONNECTION_POINTS_SIZE = \
36 'Unexpected number of connection points: 2 expected.',
37 ENCAPSULATION_TYPE = \
38 'Unexpected service_endpoint_encapsulation_type. \
39 Only "dotq1" is accepted.',
40 BANDWIDTH = 'Unable to get the bandwidth.',
41 STATUS = 'Unable to get the status for the service.',
42 DELETE = 'Unable to delete service.',
43 CLEAR_ALL = 'Unable to clear all the services',
44 UNKNOWN_ACTION = 'Unknown action invoked.',
45 BACKUP = 'Unable to get the backup parameter.',
46 UNSUPPORTED_FEATURE = "Unsupported feature",
47 UNAUTHORIZED = "Failed while authenticating"
48
49
50 class SdnAPIActions(Enum):
51 CHECK_CONNECTIVITY = "CHECK_CONNECTIVITY",
52 CREATE_SERVICE = "CREATE_SERVICE",
53 DELETE_SERVICE = "DELETE_SERVICE",
54 CLEAR_ALL = "CLEAR_ALL",
55 SERVICE_STATUS = "SERVICE_STATUS",
56
57
58 class DynpacConnector(SdnConnectorBase):
59 __supported_service_types = ["ELINE (L2)", "ELINE"]
60 __supported_encapsulation_types = ["dot1q"]
61 __WIM_LOGGER = 'openmano.sdnconn.dynpac'
62 __ENCAPSULATION_TYPE_PARAM = "service_endpoint_encapsulation_type"
63 __ENCAPSULATION_INFO_PARAM = "service_endpoint_encapsulation_info"
64 __BACKUP_PARAM = "backup"
65 __BANDWIDTH_PARAM = "bandwidth"
66 __SERVICE_ENDPOINT_PARAM = "service_endpoint_id"
67 __WAN_SERVICE_ENDPOINT_PARAM = "service_endpoint_id"
68 __WAN_MAPPING_INFO_PARAM = "service_mapping_info"
69 __SW_ID_PARAM = "switch_dpid"
70 __SW_PORT_PARAM = "switch_port"
71 __VLAN_PARAM = "vlan"
72
73 # Public functions exposed to the Resource Orchestrator
74 def __init__(self, wim, wim_account, config=None, logger=None):
75 self.logger = logger or logging.getLogger(self.__WIM_LOGGER)
76 super().__init__(wim, wim_account, config, self.logger)
77 self.__wim = wim
78 self.__wim_account = wim_account
79 self.__config = config
80 self.__wim_url = self.__wim.get("wim_url")
81 self.__user = wim_account.get("user")
82 self.__passwd = wim_account.get("password")
83 self.logger.info("Initialized.")
84
85 def create_connectivity_service(self, service_type, connection_points, **kwargs):
86 self.__check_service(service_type, connection_points, kwargs)
87
88 body = self.__get_body(service_type, connection_points, kwargs)
89
90 headers = {'Content-type': 'application/x-www-form-urlencoded'}
91 endpoint = "{}/service/create".format(self.__wim_url)
92
93 try:
94 response = requests.post(endpoint, data=body, headers=headers)
95 except requests.exceptions.RequestException as e:
96 self.__exception(e.message, http_code=503)
97
98 if response.status_code != 200:
99 error = json.loads(response.content)
100 reason = "Reason: {}. ".format(error.get("code"))
101 description = "Description: {}.".format(error.get("description"))
102 exception = reason + description
103 self.__exception(exception, http_code=response.status_code)
104 uuid = response.content
105 self.logger.info("Service with uuid {} created.".format(uuid))
106 return (uuid, None)
107
108 def edit_connectivity_service(self, service_uuid,
109 conn_info, connection_points,
110 **kwargs):
111 self.__exception(SdnError.UNSUPPORTED_FEATURE, http_code=501)
112
113 def get_connectivity_service_status(self, service_uuid):
114 endpoint = "{}/service/status/{}".format(self.__wim_url, service_uuid)
115 try:
116 response = requests.get(endpoint)
117 except requests.exceptions.RequestException as e:
118 self.__exception(e.message, http_code=503)
119
120 if response.status_code != 200:
121 self.__exception(SdnError.STATUS, http_code=response.status_code)
122 self.logger.info("Status for service with uuid {}: {}"
123 .format(service_uuid, response.content))
124 return response.content
125
126 def delete_connectivity_service(self, service_uuid, conn_info):
127 endpoint = "{}/service/delete/{}".format(self.__wim_url, service_uuid)
128 try:
129 response = requests.delete(endpoint)
130 except requests.exceptions.RequestException as e:
131 self.__exception(e.message, http_code=503)
132 if response.status_code != 200:
133 self.__exception(SdnError.DELETE, http_code=response.status_code)
134
135 self.logger.info("Service with uuid: {} deleted".format(service_uuid))
136
137 def clear_all_connectivity_services(self):
138 endpoint = "{}/service/clearAll".format(self.__wim_url)
139 try:
140 response = requests.delete(endpoint)
141 http_code = response.status_code
142 except requests.exceptions.RequestException as e:
143 self.__exception(e.message, http_code=503)
144 if http_code != 200:
145 self.__exception(SdnError.CLEAR_ALL, http_code=http_code)
146
147 self.logger.info("{} services deleted".format(response.content))
148 return "{} services deleted".format(response.content)
149
150 def check_connectivity(self):
151 endpoint = "{}/checkConnectivity".format(self.__wim_url)
152
153 try:
154 response = requests.get(endpoint)
155 http_code = response.status_code
156 except requests.exceptions.RequestException as e:
157 self.__exception(e.message, http_code=503)
158
159 if http_code != 200:
160 self.__exception(SdnError.UNREACHABLE, http_code=http_code)
161 self.logger.info("Connectivity checked")
162
163 def check_credentials(self):
164 endpoint = "{}/checkCredentials".format(self.__wim_url)
165 auth = (self.__user, self.__passwd)
166
167 try:
168 response = requests.get(endpoint, auth=auth)
169 http_code = response.status_code
170 except requests.exceptions.RequestException as e:
171 self.__exception(e.message, http_code=503)
172
173 if http_code != 200:
174 self.__exception(SdnError.UNAUTHORIZED, http_code=http_code)
175 self.logger.info("Credentials checked")
176
177 # Private functions
178 def __exception(self, x, **kwargs):
179 http_code = kwargs.get("http_code")
180 if hasattr(x, "value"):
181 error = x.value
182 else:
183 error = x
184 self.logger.error(error)
185 raise SdnConnectorError(error, http_code=http_code)
186
187 def __check_service(self, service_type, connection_points, kwargs):
188 if service_type not in self.__supported_service_types:
189 self.__exception(SdnError.SERVICE_TYPE_ERROR, http_code=400)
190
191 if len(connection_points) != 2:
192 self.__exception(SdnError.CONNECTION_POINTS_SIZE, http_code=400)
193
194 for connection_point in connection_points:
195 enc_type = connection_point.get(self.__ENCAPSULATION_TYPE_PARAM)
196 if enc_type not in self.__supported_encapsulation_types:
197 self.__exception(SdnError.ENCAPSULATION_TYPE, http_code=400)
198
199 # Commented out for as long as parameter isn't implemented
200 # bandwidth = kwargs.get(self.__BANDWIDTH_PARAM)
201 # if not isinstance(bandwidth, int):
202 # self.__exception(SdnError.BANDWIDTH, http_code=400)
203
204 # Commented out for as long as parameter isn't implemented
205 # backup = kwargs.get(self.__BACKUP_PARAM)
206 # if not isinstance(backup, bool):
207 # self.__exception(SdnError.BACKUP, http_code=400)
208
209 def __get_body(self, service_type, connection_points, kwargs):
210 port_mapping = self.__config.get("service_endpoint_mapping")
211 selected_ports = []
212 for connection_point in connection_points:
213 endpoint_id = connection_point.get(self.__SERVICE_ENDPOINT_PARAM)
214 port = filter(lambda x: x.get(self.__WAN_SERVICE_ENDPOINT_PARAM) == endpoint_id, port_mapping)[0]
215 port_info = port.get(self.__WAN_MAPPING_INFO_PARAM)
216 selected_ports.append(port_info)
217 if service_type == "ELINE (L2)" or service_type == "ELINE":
218 service_type = "L2"
219 body = {
220 "connection_points": [{
221 "wan_switch_dpid": selected_ports[0].get(self.__SW_ID_PARAM),
222 "wan_switch_port": selected_ports[0].get(self.__SW_PORT_PARAM),
223 "wan_vlan": connection_points[0].get(self.__ENCAPSULATION_INFO_PARAM).get(self.__VLAN_PARAM)
224 }, {
225 "wan_switch_dpid": selected_ports[1].get(self.__SW_ID_PARAM),
226 "wan_switch_port": selected_ports[1].get(self.__SW_PORT_PARAM),
227 "wan_vlan": connection_points[1].get(self.__ENCAPSULATION_INFO_PARAM).get(self.__VLAN_PARAM)
228 }],
229 "bandwidth": 100, # Hardcoded for as long as parameter isn't implemented
230 "service_type": service_type,
231 "backup": False # Hardcoded for as long as parameter isn't implemented
232 }
233 return "body={}".format(json.dumps(body))