Add Dynpac WIM Connector
[osm/RO.git] / osm_ro / wim / 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 wimconn import WimConnector, WimConnectorError
30
31
32 class WimError(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
48
49 class WimAPIActions(Enum):
50 CHECK_CONNECTIVITY = "CHECK_CONNECTIVITY",
51 CREATE_SERVICE = "CREATE_SERVICE",
52 DELETE_SERVICE = "DELETE_SERVICE",
53 CLEAR_ALL = "CLEAR_ALL",
54 SERVICE_STATUS = "SERVICE_STATUS",
55
56
57 class DynpacConnector(WimConnector):
58 __supported_service_types = ["ELINE (L2)"]
59 __supported_encapsulation_types = ["dot1q"]
60 __WIM_LOGGER = 'openmano.wimconn.dynpac'
61 __ENCAPSULATION_TYPE_PARAM = "service_endpoint_encapsulation_type"
62 __BACKUP_PARAM = "backup"
63 __BANDWIDTH_PARAM = "bandwidth"
64 __SERVICE_ENDPOINT_PARAM = "service_endpoint_id"
65 __WAN_SERVICE_ENDPOINT_PARAM = "wan_service_endpoint_id"
66 __WAN_MAPPING_INFO_PARAM = "wan_service_mapping_info"
67 __SW_ID_PARAM = "wan_switch_dpid"
68 __SW_PORT_PARAM = "wan_switch_port"
69 __VLAN_PARAM = "vlan"
70
71 # Public functions exposed to the Resource Orchestrator
72 def __init__(self, wim, wim_account, config):
73 self.logger = logging.getLogger(self.__WIM_LOGGER)
74 self.__wim = wim
75 self.__wim_account = wim_account
76 self.__config = config
77 self.__wim_url = self.__wim.get("wim_url")
78 self.__user = wim_account.get("user")
79 self.__passwd = wim_account.get("passwd")
80 self.logger.info("Initialized.")
81
82 def create_connectivity_service(self,
83 service_type,
84 connection_points,
85 **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(WimError.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(WimError.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(WimError.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(WimError.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 auth = (self.__user, self.__passwd)
153
154 try:
155 response = requests.get(endpoint, auth=auth)
156 http_code = response.status_code
157 except requests.exceptions.RequestException as e:
158 self.__exception(e.message, http_code=503)
159
160 if http_code != 200:
161 self.__exception(WimError.UNREACHABLE, http_code=http_code)
162 self.logger.info("Connectivity checked")
163
164 # Private functions
165 def __exception(self, x, **kwargs):
166 http_code = kwargs.get("http_code")
167 if hasattr(x, "value"):
168 error = x.value
169 else:
170 error = x
171 self.logger.error(error)
172 raise WimConnectorError(error, http_code=http_code)
173
174 def __check_service(self, service_type, connection_points, kwargs):
175 if service_type not in self.__supported_service_types:
176 self.__exception(WimError.SERVICE_TYPE_ERROR, http_code=400)
177
178 if len(connection_points) != 2:
179 self.__exception(WimError.CONNECTION_POINTS_SIZE, http_code=400)
180
181 for connection_point in connection_points:
182 enc_type = connection_point.get(self.__ENCAPSULATION_TYPE_PARAM)
183 if enc_type not in self.__supported_encapsulation_types:
184 self.__exception(WimError.ENCAPSULATION_TYPE, http_code=400)
185
186 bandwidth = kwargs.get(self.__BANDWIDTH_PARAM)
187 if not isinstance(bandwidth, int):
188 self.__exception(WimError.BANDWIDTH, http_code=400)
189
190 backup = kwargs.get(self.__BACKUP_PARAM)
191 if not isinstance(backup, bool):
192 self.__exception(WimError.BACKUP, http_code=400)
193
194 def __get_body(self, service_type, connection_points, kwargs):
195 port_mapping = self.__config.get("port_mapping")
196 selected_ports = []
197 for connection_point in connection_points:
198 endpoint_id = connection_point.get(self.__SERVICE_ENDPOINT_PARAM)
199 port = filter(lambda x: x.get(self.__WAN_SERVICE_ENDPOINT_PARAM)
200 == endpoint_id, port_mapping)[0]
201 wsmpi_json = port.get(self.__WAN_MAPPING_INFO_PARAM)
202 port_info = json.loads(wsmpi_json)
203 selected_ports.append(port_info)
204 if service_type == "ELINE (L2)":
205 service_type = "L2"
206 body = {
207 "connection_points": [{
208 "wan_switch_dpid": selected_ports[0].get(self.__SW_ID_PARAM),
209 "wan_switch_port": selected_ports[0].get(self.__SW_PORT_PARAM),
210 "wan_vlan": connection_points[0].get(self.__VLAN_PARAM)
211 }, {
212 "wan_switch_dpid": selected_ports[1].get(self.__SW_ID_PARAM),
213 "wan_switch_port": selected_ports[1].get(self.__SW_PORT_PARAM),
214 "wan_vlan": connection_points[1].get(self.__VLAN_PARAM)
215 }],
216 "bandwidth": kwargs.get(self.__BANDWIDTH_PARAM),
217 "service_type": service_type,
218 "backup": kwargs.get(self.__BACKUP_PARAM)
219 }
220 return "body={}".format(json.dumps(body))