blob: cc9376b0eeaee49f293fed1d1c19810e4c39da27 [file] [log] [blame]
David García00e29dd2018-12-10 09:43:50 +01001#!/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
24import requests
25import json
26import logging
27from enum import Enum
28
29from wimconn import WimConnector, WimConnectorError
30
31
32class 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.',
David García0ce24dc2019-01-10 23:31:03 +010046 UNSUPPORTED_FEATURE = "Unsupported feature",
47 UNAUTHORIZED = "Failed while authenticating"
David García00e29dd2018-12-10 09:43:50 +010048
49
50class WimAPIActions(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
58class DynpacConnector(WimConnector):
sasiain1c7f6e42019-07-08 10:15:31 +020059 __supported_service_types = ["ELINE (L2)", "ELINE"]
David García00e29dd2018-12-10 09:43:50 +010060 __supported_encapsulation_types = ["dot1q"]
61 __WIM_LOGGER = 'openmano.wimconn.dynpac'
62 __ENCAPSULATION_TYPE_PARAM = "service_endpoint_encapsulation_type"
David García0ce24dc2019-01-10 23:31:03 +010063 __ENCAPSULATION_INFO_PARAM = "service_endpoint_encapsulation_info"
David García00e29dd2018-12-10 09:43:50 +010064 __BACKUP_PARAM = "backup"
65 __BANDWIDTH_PARAM = "bandwidth"
66 __SERVICE_ENDPOINT_PARAM = "service_endpoint_id"
67 __WAN_SERVICE_ENDPOINT_PARAM = "wan_service_endpoint_id"
68 __WAN_MAPPING_INFO_PARAM = "wan_service_mapping_info"
69 __SW_ID_PARAM = "wan_switch_dpid"
70 __SW_PORT_PARAM = "wan_switch_port"
71 __VLAN_PARAM = "vlan"
72
73 # Public functions exposed to the Resource Orchestrator
74 def __init__(self, wim, wim_account, config):
75 self.logger = logging.getLogger(self.__WIM_LOGGER)
76 self.__wim = wim
77 self.__wim_account = wim_account
78 self.__config = config
79 self.__wim_url = self.__wim.get("wim_url")
80 self.__user = wim_account.get("user")
81 self.__passwd = wim_account.get("passwd")
82 self.logger.info("Initialized.")
83
84 def create_connectivity_service(self,
85 service_type,
86 connection_points,
87 **kwargs):
88 self.__check_service(service_type, connection_points, kwargs)
89
90 body = self.__get_body(service_type, connection_points, kwargs)
91
92 headers = {'Content-type': 'application/x-www-form-urlencoded'}
93 endpoint = "{}/service/create".format(self.__wim_url)
94
95 try:
96 response = requests.post(endpoint, data=body, headers=headers)
97 except requests.exceptions.RequestException as e:
98 self.__exception(e.message, http_code=503)
99
100 if response.status_code != 200:
101 error = json.loads(response.content)
102 reason = "Reason: {}. ".format(error.get("code"))
103 description = "Description: {}.".format(error.get("description"))
104 exception = reason + description
105 self.__exception(exception, http_code=response.status_code)
106 uuid = response.content
107 self.logger.info("Service with uuid {} created.".format(uuid))
108 return (uuid, None)
109
110 def edit_connectivity_service(self, service_uuid,
111 conn_info, connection_points,
112 **kwargs):
113 self.__exception(WimError.UNSUPPORTED_FEATURE, http_code=501)
114
115 def get_connectivity_service_status(self, service_uuid):
116 endpoint = "{}/service/status/{}".format(self.__wim_url, service_uuid)
117 try:
118 response = requests.get(endpoint)
119 except requests.exceptions.RequestException as e:
120 self.__exception(e.message, http_code=503)
121
122 if response.status_code != 200:
123 self.__exception(WimError.STATUS, http_code=response.status_code)
124 self.logger.info("Status for service with uuid {}: {}"
125 .format(service_uuid, response.content))
126 return response.content
127
128 def delete_connectivity_service(self, service_uuid, conn_info):
129 endpoint = "{}/service/delete/{}".format(self.__wim_url, service_uuid)
130 try:
131 response = requests.delete(endpoint)
132 except requests.exceptions.RequestException as e:
133 self.__exception(e.message, http_code=503)
134 if response.status_code != 200:
135 self.__exception(WimError.DELETE, http_code=response.status_code)
136
137 self.logger.info("Service with uuid: {} deleted".format(service_uuid))
138
139 def clear_all_connectivity_services(self):
140 endpoint = "{}/service/clearAll".format(self.__wim_url)
141 try:
142 response = requests.delete(endpoint)
143 http_code = response.status_code
144 except requests.exceptions.RequestException as e:
145 self.__exception(e.message, http_code=503)
146 if http_code != 200:
147 self.__exception(WimError.CLEAR_ALL, http_code=http_code)
148
149 self.logger.info("{} services deleted".format(response.content))
150 return "{} services deleted".format(response.content)
151
152 def check_connectivity(self):
153 endpoint = "{}/checkConnectivity".format(self.__wim_url)
David García0ce24dc2019-01-10 23:31:03 +0100154
155 try:
156 response = requests.get(endpoint)
157 http_code = response.status_code
158 except requests.exceptions.RequestException as e:
159 self.__exception(e.message, http_code=503)
160
161 if http_code != 200:
162 self.__exception(WimError.UNREACHABLE, http_code=http_code)
163 self.logger.info("Connectivity checked")
164
165 def check_credentials(self):
166 endpoint = "{}/checkCredentials".format(self.__wim_url)
David García00e29dd2018-12-10 09:43:50 +0100167 auth = (self.__user, self.__passwd)
168
169 try:
170 response = requests.get(endpoint, auth=auth)
171 http_code = response.status_code
172 except requests.exceptions.RequestException as e:
173 self.__exception(e.message, http_code=503)
174
175 if http_code != 200:
David García0ce24dc2019-01-10 23:31:03 +0100176 self.__exception(WimError.UNAUTHORIZED, http_code=http_code)
177 self.logger.info("Credentials checked")
David García00e29dd2018-12-10 09:43:50 +0100178
179 # Private functions
180 def __exception(self, x, **kwargs):
181 http_code = kwargs.get("http_code")
182 if hasattr(x, "value"):
183 error = x.value
184 else:
185 error = x
186 self.logger.error(error)
187 raise WimConnectorError(error, http_code=http_code)
188
189 def __check_service(self, service_type, connection_points, kwargs):
190 if service_type not in self.__supported_service_types:
191 self.__exception(WimError.SERVICE_TYPE_ERROR, http_code=400)
192
193 if len(connection_points) != 2:
194 self.__exception(WimError.CONNECTION_POINTS_SIZE, http_code=400)
195
196 for connection_point in connection_points:
197 enc_type = connection_point.get(self.__ENCAPSULATION_TYPE_PARAM)
198 if enc_type not in self.__supported_encapsulation_types:
199 self.__exception(WimError.ENCAPSULATION_TYPE, http_code=400)
200
sasiain1c7f6e42019-07-08 10:15:31 +0200201 # Commented out for as long as parameter isn't implemented
202 # bandwidth = kwargs.get(self.__BANDWIDTH_PARAM)
203 # if not isinstance(bandwidth, int):
204 # self.__exception(WimError.BANDWIDTH, http_code=400)
David García00e29dd2018-12-10 09:43:50 +0100205
sasiain1c7f6e42019-07-08 10:15:31 +0200206 # Commented out for as long as parameter isn't implemented
207 # backup = kwargs.get(self.__BACKUP_PARAM)
208 # if not isinstance(backup, bool):
209 # self.__exception(WimError.BACKUP, http_code=400)
David García00e29dd2018-12-10 09:43:50 +0100210
211 def __get_body(self, service_type, connection_points, kwargs):
sasiain1c7f6e42019-07-08 10:15:31 +0200212 port_mapping = self.__config.get("service_endpoint_mapping")
David García00e29dd2018-12-10 09:43:50 +0100213 selected_ports = []
214 for connection_point in connection_points:
215 endpoint_id = connection_point.get(self.__SERVICE_ENDPOINT_PARAM)
tierno433a63d2019-04-02 11:49:31 +0000216 port = filter(lambda x: x.get(self.__WAN_SERVICE_ENDPOINT_PARAM) == endpoint_id, port_mapping)[0]
sasiain1c7f6e42019-07-08 10:15:31 +0200217 port_info = port.get(self.__WAN_MAPPING_INFO_PARAM)
David García00e29dd2018-12-10 09:43:50 +0100218 selected_ports.append(port_info)
sasiain1c7f6e42019-07-08 10:15:31 +0200219 if service_type == "ELINE (L2)" or service_type == "ELINE":
David García00e29dd2018-12-10 09:43:50 +0100220 service_type = "L2"
221 body = {
222 "connection_points": [{
223 "wan_switch_dpid": selected_ports[0].get(self.__SW_ID_PARAM),
224 "wan_switch_port": selected_ports[0].get(self.__SW_PORT_PARAM),
David García0ce24dc2019-01-10 23:31:03 +0100225 "wan_vlan": connection_points[0].get(self.__ENCAPSULATION_INFO_PARAM).get(self.__VLAN_PARAM)
David García00e29dd2018-12-10 09:43:50 +0100226 }, {
227 "wan_switch_dpid": selected_ports[1].get(self.__SW_ID_PARAM),
228 "wan_switch_port": selected_ports[1].get(self.__SW_PORT_PARAM),
tierno433a63d2019-04-02 11:49:31 +0000229 "wan_vlan": connection_points[1].get(self.__ENCAPSULATION_INFO_PARAM).get(self.__VLAN_PARAM)
David García00e29dd2018-12-10 09:43:50 +0100230 }],
sasiain1c7f6e42019-07-08 10:15:31 +0200231 "bandwidth": 100, # Hardcoded for as long as parameter isn't implemented
David García00e29dd2018-12-10 09:43:50 +0100232 "service_type": service_type,
sasiain1c7f6e42019-07-08 10:15:31 +0200233 "backup": False # Hardcoded for as long as parameter isn't implemented
David García00e29dd2018-12-10 09:43:50 +0100234 }
235 return "body={}".format(json.dumps(body))