1 # -*- coding: utf-8 -*-
4 # Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
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
21 This is the thread for the http server North API.
22 Two thread will be launched, with normal and administrative permissions.
25 from uuid
import uuid4
26 from http
import HTTPStatus
28 __author__
= "Alfonso Tierno"
29 __date__
= "2019-10-22"
31 version_date
= "Oct 2019"
34 class SdnException(Exception):
35 def __init__(self
, message
, http_code
=HTTPStatus
.BAD_REQUEST
.value
):
36 self
.http_code
= http_code
37 Exception.__init
__(self
, message
)
41 running_info
= {} # TODO OVIM move the info of running threads from config_dic to this static variable
44 def __init__(self
, db
, plugins
):
46 self
.plugins
= plugins
48 def start_service(self
):
49 pass # TODO py3 needed to load wims and plugins
51 def stop_service(self
):
54 def show_network(self
, uuid
):
57 def delete_network(self
, uuid
):
60 def new_network(self
, network
):
63 def get_openflow_rules(self
, network_id
=None):
65 Get openflow id from DB
66 :param network_id: Network id, if none all networks will be retrieved
67 :return: Return a list with Openflow rules per net
74 where_
= {"net_id": network_id
}
75 result
, content
= self
.db
.get_table(
76 SELECT
=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
77 WHERE
=where_
, FROM
='of_flows')
80 raise SdnException(str(content
), -result
)
83 def edit_openflow_rules(self
, network_id
=None):
86 To make actions over the net. The action is to reinstall the openflow rules
87 network_id can be 'all'
88 :param network_id: Network id, if none all networks will be retrieved
89 :return : Number of nets updated
96 where_
= {"uuid": network_id
}
97 result
, content
= self
.db
.get_table(SELECT
=("uuid", "type"), WHERE
=where_
, FROM
='nets')
100 raise SdnException(str(content
), -result
)
103 if net
["type"] != "ptp" and net
["type"] != "data":
108 self
.net_update_ofc_thread(net
['uuid'])
109 except SdnException
as e
:
110 raise SdnException("Error updating network'{}' {}".format(net
['uuid'], e
),
111 HTTPStatus
.INTERNAL_SERVER_ERROR
.value
)
112 except Exception as e
:
113 raise SdnException("Error updating network '{}' {}".format(net
['uuid'], e
),
114 HTTPStatus
.INTERNAL_SERVER_ERROR
.value
)
118 def delete_openflow_rules(self
, ofc_id
=None):
120 To make actions over the net. The action is to delete ALL openflow rules
121 :return: return operation result
125 if 'Default' in self
.config
['ofcs_thread']:
126 r
, c
= self
.config
['ofcs_thread']['Default'].insert_task("clear-all")
128 raise SdnException("Default Openflow controller not not running", HTTPStatus
.NOT_FOUND
.value
)
130 elif ofc_id
in self
.config
['ofcs_thread']:
131 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("clear-all")
135 raise SdnException(str(c
), -r
)
137 raise SdnException("Openflow controller not found with ofc_id={}".format(ofc_id
),
138 HTTPStatus
.NOT_FOUND
.value
)
141 def get_openflow_ports(self
, ofc_id
=None):
143 Obtain switch ports names of openflow controller
144 :return: Return flow ports in DB
147 if 'Default' in self
.config
['ofcs_thread']:
148 conn
= self
.config
['ofcs_thread']['Default'].OF_connector
150 raise SdnException("Default Openflow controller not not running", HTTPStatus
.NOT_FOUND
.value
)
152 elif ofc_id
in self
.config
['ofcs_thread']:
153 conn
= self
.config
['ofcs_thread'][ofc_id
].OF_connector
155 raise SdnException("Openflow controller not found with ofc_id={}".format(ofc_id
),
156 HTTPStatus
.NOT_FOUND
.value
)
159 def new_of_controller(self
, ofc_data
):
161 Create a new openflow controller into DB
162 :param ofc_data: Dict openflow controller data
163 :return: openflow controller dpid
166 "uuid": str(uuid4()),
167 "name": ofc_data
["name"],
169 "type": ofc_data
["type"],
170 "wim_url": "{}:{}".format(ofc_data
["ip"], ofc_data
["port"]),
173 "uuid": str(uuid4()),
174 "name": ofc_data
["name"],
175 "wim_id": db_wim
["uuid"],
177 "user": ofc_data
.get("user"),
178 "password": ofc_data
.get("password"),
179 "config": yaml
.safe_dump({"dpid": ofc_data
["dpid"], "version": ofc_data
.get("version")},
180 default_flow_style
=True, width
=256)
184 {"wim_accounts": db_wim_account
},
186 uuid_list
= [db_wim
["uuid"], db_wim_account
["uuid"]]
187 self
.db
.new_rows(db_tables
, uuid_list
)
188 return db_wim_account
["uuid"]
190 def edit_of_controller(self
, of_id
, ofc_data
):
192 Edit an openflow controller entry from DB
196 raise SdnException("No data received during uptade OF contorller",
197 http_code
=HTTPStatus
.INTERNAL_SERVER_ERROR
.value
)
199 old_of_controller
= self
.show_of_controller(of_id
)
201 if old_of_controller
:
202 result
, content
= self
.db
.update_rows('ofcs', ofc_data
, WHERE
={'uuid': of_id
}, log
=False)
206 raise SdnException("Error uptating OF contorller with uuid {}".format(of_id
),
209 raise SdnException("Error uptating OF contorller with uuid {}".format(of_id
),
210 http_code
=HTTPStatus
.INTERNAL_SERVER_ERROR
.value
)
212 def delete_of_controller(self
, of_id
):
214 Delete an openflow controller from DB.
215 :param of_id: openflow controller dpid
218 wim_accounts
= self
.db
.get_rows(FROM
='wim_accounts', WHERE
={"uuid": of_id
, "sdn": "true"})
220 raise SdnException("Cannot find sdn controller with id='{}'".format(of_id
),
221 http_code
=HTTPStatus
.NOT_FOUND
.value
)
222 elif len(wim_accounts
) > 1:
223 raise SdnException("Found more than one sdn controller with id='{}'".format(of_id
),
224 http_code
=HTTPStatus
.CONFLICT
.value
)
225 self
.db
.delete_row(FROM
='wim_accounts', WHERE
={"uuid": of_id
})
226 self
.db
.delete_row(FROM
='wims', WHERE
={"uuid": wim_accounts
[0]["wim_id"]})
229 def _format_of_controller(self
, wim_account
, wim
=None):
230 of_data
= {x
: wim_account
[x
] for x
in ("uuid", "name", "user")}
231 if isinstance(wim_account
["config"], str):
232 config
= yaml
.load(wim_account
["config"], Loader
=yaml
.Loader
)
233 of_data
["dpid"] = config
.get("dpid")
234 of_data
["version"] = config
.get("version")
236 ip
, port
= wim
["wim_url"].split(":")
238 of_data
["port"] = port
239 of_data
["type"] = wim
["type"]
242 def show_of_controller(self
, of_id
):
244 Show an openflow controller by dpid from DB.
245 :param db_filter: List with where query parameters
248 wim_accounts
= self
.db
.get_rows(FROM
='wim_accounts', WHERE
={"uuid": of_id
, "sdn": "true"})
250 raise SdnException("Cannot find sdn controller with id='{}'".format(of_id
),
251 http_code
=HTTPStatus
.NOT_FOUND
.value
)
252 elif len(wim_accounts
) > 1:
253 raise SdnException("Found more than one sdn controller with id='{}'".format(of_id
),
254 http_code
=HTTPStatus
.CONFLICT
.value
)
255 wims
= self
.db
.get_rows(FROM
='wims', WHERE
={"uuid": wim_accounts
[0]["wim_id"]})
256 return self
._format
_of
_controller
(wim_accounts
[0], wims
[0])
258 def get_of_controllers(self
, filter=None):
260 Show an openflow controllers from DB.
263 filter = filter or {}
264 filter["sdn"] = "true"
265 wim_accounts
= self
.db
.get_rows(FROM
='wim_accounts', WHERE
=filter)
266 return [self
._format
_of
_controller
(w
) for w
in wim_accounts
]
268 def set_of_port_mapping(self
, maps
, sdn_id
, switch_dpid
, vim_id
):
270 Create new port mapping entry
271 :param of_maps: List with port mapping information
272 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
273 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
274 :param sdn_id: ofc id
275 :param switch_dpid: switch dpid
276 :param vim_id: datacenter
279 # get wim from wim_account
280 wim_accounts
= self
.db
.get_rows(FROM
='wim_accounts', WHERE
={"uuid": sdn_id
})
282 raise SdnException("Not found sdn id={}".format(sdn_id
), http_code
=HTTPStatus
.NOT_FOUND
.value
)
283 wim_id
= wim_accounts
[0]["wim_id"]
284 db_wim_port_mappings
= []
288 'switch_dpid': switch_dpid
,
289 "switch_port": map.get("switch_port"),
290 'datacenter_id': vim_id
,
291 "device_id": map.get("compute_node"),
292 "service_endpoint_id": switch_dpid
+ "-" + str(uuid4())
295 new_map
["device_interface_id"] = map["pci"].lower()
297 if map.get("switch_mac"):
298 config
["switch_mac"] = map["switch_mac"]
300 new_map
["service_mapping_info"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
301 db_wim_port_mappings
.append(new_map
)
304 {"wim_port_mappings": db_wim_port_mappings
},
306 self
.db
.new_rows(db_tables
, [])
307 return db_wim_port_mappings
309 def clear_of_port_mapping(self
, db_filter
=None):
311 Clear port mapping filtering using db_filter dict
312 :param db_filter: Parameter to filter during remove process
315 return self
.db
.delete_row(FROM
='wim_port_mappings', WHERE
=db_filter
)
317 def get_of_port_mappings(self
, db_filter
=None):
319 Retrive port mapping from DB
323 maps
= self
.db
.get_rows(WHERE
=db_filter
, FROM
='wim_port_mappings')
325 if map.get("service_mapping_info"):
326 map["service_mapping_info"] = yaml
.load(map["service_mapping_info"], Loader
=yaml
.Loader
)
328 map["service_mapping_info"] = {}