83a974234b9a663ff3b65d8a8943d595e32a9650
[osm/openvim.git] / ovim.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openvim
6 # All Rights Reserved.
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
18 # under the License.
19 #
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
22 ##
23
24 '''
25 This is the thread for the http server North API.
26 Two thread will be launched, with normal and administrative permissions.
27 '''
28
29 __author__ = "Alfonso Tierno, Leonardo Mirabal"
30 __date__ = "$06-Feb-2017 12:07:15$"
31 __version__ = "0.5.8-r524"
32 version_date = "March 2017"
33 database_version = "0.15" #expected database schema version
34
35 import threading
36 import vim_db
37 import logging
38 import threading
39 import imp
40 import host_thread as ht
41 import dhcp_thread as dt
42 import openflow_thread as oft
43 from netaddr import IPNetwork
44 from jsonschema import validate as js_v, exceptions as js_e
45 import openflow_conn
46
47 HTTP_Bad_Request = 400
48 HTTP_Unauthorized = 401
49 HTTP_Not_Found = 404
50 HTTP_Forbidden = 403
51 HTTP_Method_Not_Allowed = 405
52 HTTP_Not_Acceptable = 406
53 HTTP_Request_Timeout = 408
54 HTTP_Conflict = 409
55 HTTP_Service_Unavailable = 503
56 HTTP_Internal_Server_Error= 500
57
58
59 def convert_boolean(data, items):
60 '''Check recursively the content of data, and if there is an key contained in items, convert value from string to boolean
61 It assumes that bandwidth is well formed
62 Attributes:
63 'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
64 'items': tuple of keys to convert
65 Return:
66 None
67 '''
68 if type(data) is dict:
69 for k in data.keys():
70 if type(data[k]) is dict or type(data[k]) is tuple or type(data[k]) is list:
71 convert_boolean(data[k], items)
72 if k in items:
73 if type(data[k]) is str:
74 if data[k] == "false":
75 data[k] = False
76 elif data[k] == "true":
77 data[k] = True
78 if type(data) is tuple or type(data) is list:
79 for k in data:
80 if type(k) is dict or type(k) is tuple or type(k) is list:
81 convert_boolean(k, items)
82
83
84
85 class ovimException(Exception):
86 def __init__(self, message, http_code=HTTP_Bad_Request):
87 self.http_code = http_code
88 Exception.__init__(self, message)
89
90
91 class ovim():
92 running_info = {} #TODO OVIM move the info of running threads from config_dic to this static variable
93 of_module = {}
94
95 def __init__(self, configuration):
96 self.config = configuration
97 self.logger = logging.getLogger(configuration["logger_name"])
98 self.db = None
99 self.db = self._create_database_connection()
100 self.db_lock = None
101 self.db_of = None
102 self.of_test_mode = False
103
104 def _create_database_connection(self):
105 db = vim_db.vim_db((self.config["network_vlan_range_start"], self.config["network_vlan_range_end"]),
106 self.config['log_level_db']);
107 if db.connect(self.config['db_host'], self.config['db_user'], self.config['db_passwd'],
108 self.config['db_name']) == -1:
109 # self.logger.error("Cannot connect to database %s at %s@%s", self.config['db_name'], self.config['db_user'],
110 # self.config['db_host'])
111 raise ovimException("Cannot connect to database {} at {}@{}".format(self.config['db_name'],
112 self.config['db_user'],
113 self.config['db_host']) )
114 return db
115
116 @staticmethod
117 def get_version():
118 return __version__
119
120 @staticmethod
121 def get_version_date():
122 return version_date
123
124 @staticmethod
125 def get_database_version():
126 return database_version
127
128 @staticmethod
129 def _check_dhcp_data_integrity(network):
130 """
131 Check if all dhcp parameter for anet are valid, if not will be calculated from cidr value
132 :param network: list with user nets paramters
133 :return:
134 """
135 if "cidr" in network:
136 cidr = network["cidr"]
137 ip_tools = IPNetwork(cidr)
138 cidr_len = ip_tools.prefixlen
139 if cidr_len > 29:
140 return False
141
142 ips = IPNetwork(cidr)
143 if "dhcp_first_ip" not in network:
144 network["dhcp_first_ip"] = str(ips[2])
145 if "dhcp_last_ip" not in network:
146 network["dhcp_last_ip"] = str(ips[-2])
147 if "gateway_ip" not in network:
148 network["gateway_ip"] = str(ips[1])
149
150 return True
151 else:
152 return False
153
154 @staticmethod
155 def _check_valid_uuid(uuid):
156 id_schema = {"type": "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
157 try:
158 js_v(uuid, id_schema)
159 return True
160 except js_e.ValidationError:
161 return False
162
163 def start_service(self):
164 """
165 Start ovim services
166 :return:
167 """
168 global database_version
169 # if self.running_info:
170 # return #TODO service can be checked and rebuild broken threads
171 r = self.db.get_db_version()
172 if r[0] < 0:
173 raise ovimException("DATABASE is not a VIM one or it is a '0.0' version. Try to upgrade to version '{}' with "\
174 "'./database_utils/migrate_vim_db.sh'".format(database_version) )
175 elif r[1] != database_version:
176 raise ovimException("DATABASE wrong version '{}'. Try to upgrade/downgrade to version '{}' with "\
177 "'./database_utils/migrate_vim_db.sh'".format(r[1], database_version) )
178
179 # create database connection for openflow threads
180 self.db_of = self._create_database_connection()
181 self.config["db"] = self.db_of
182 self.db_lock = threading.Lock()
183 self.config["db_lock"] = self.db_lock
184
185 self.of_test_mode = False if self.config['mode'] == 'normal' or self.config['mode'] == "OF only" else True
186 # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge,
187 # speed in Gbit/s
188
189 self.config['dhcp_nets'] = []
190 self.config['bridge_nets'] = []
191 for bridge, vlan_speed in self.config["bridge_ifaces"].items():
192 # skip 'development_bridge'
193 if self.config['mode'] == 'development' and self.config['development_bridge'] == bridge:
194 continue
195 self.config['bridge_nets'].append([bridge, vlan_speed[0], vlan_speed[1], None])
196
197 # check if this bridge is already used (present at database) for a network)
198 used_bridge_nets = []
199 for brnet in self.config['bridge_nets']:
200 r, nets = self.db.get_table(SELECT=('uuid',), FROM='nets', WHERE={'provider': "bridge:" + brnet[0]})
201 if r > 0:
202 brnet[3] = nets[0]['uuid']
203 used_bridge_nets.append(brnet[0])
204 if self.config.get("dhcp_server"):
205 if brnet[0] in self.config["dhcp_server"]["bridge_ifaces"]:
206 self.config['dhcp_nets'].append(nets[0]['uuid'])
207 if len(used_bridge_nets) > 0:
208 self.logger.info("found used bridge nets: " + ",".join(used_bridge_nets))
209 # get nets used by dhcp
210 if self.config.get("dhcp_server"):
211 for net in self.config["dhcp_server"].get("nets", ()):
212 r, nets = self.db.get_table(SELECT=('uuid',), FROM='nets', WHERE={'name': net})
213 if r > 0:
214 self.config['dhcp_nets'].append(nets[0]['uuid'])
215
216 # OFC default
217 self._start_ofc_default_task()
218
219 # OFC per tenant in DB
220 self._start_of_db_tasks()
221
222 # create dhcp_server thread
223 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
224 dhcp_params = self.config.get("dhcp_server")
225 if dhcp_params:
226 thread = dt.dhcp_thread(dhcp_params=dhcp_params, test=host_test_mode, dhcp_nets=self.config["dhcp_nets"],
227 db=self.db_of, db_lock=self.db_lock, debug=self.config['log_level_of'])
228 thread.start()
229 self.config['dhcp_thread'] = thread
230
231 # Create one thread for each host
232 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
233 host_develop_mode = True if self.config['mode'] == 'development' else False
234 host_develop_bridge_iface = self.config.get('development_bridge', None)
235
236 # get host list from data base before starting threads
237 r, hosts = self.db.get_table(SELECT=('name', 'ip_name', 'user', 'uuid'), FROM='hosts', WHERE={'status': 'ok'})
238 if r < 0:
239 raise ovimException("Cannot get hosts from database {}".format(hosts))
240
241 self.config['host_threads'] = {}
242 for host in hosts:
243 host['image_path'] = '/opt/VNF/images/openvim'
244 thread = ht.host_thread(name=host['name'], user=host['user'], host=host['ip_name'], db=self.db_of,
245 db_lock=self.db_lock, test=host_test_mode, image_path=self.config['image_path'],
246 version=self.config['version'], host_id=host['uuid'], develop_mode=host_develop_mode,
247 develop_bridge_iface=host_develop_bridge_iface)
248 thread.start()
249 self.config['host_threads'][host['uuid']] = thread
250
251 # create ovs dhcp thread
252 result, content = self.db.get_table(FROM='nets')
253 if result < 0:
254 self.logger.error("http_get_ports Error %d %s", result, content)
255 raise ovimException(str(content), -result)
256
257 for net in content:
258 net_type = net['type']
259 if (net_type == 'bridge_data' or net_type == 'bridge_man') \
260 and net["provider"][:4] == 'OVS:' and net["enable_dhcp"] == "true":
261 self.launch_dhcp_server(net['vlan'],
262 net['dhcp_first_ip'],
263 net['dhcp_last_ip'],
264 net['cidr'],
265 net['gateway_ip'])
266
267 def _start_of_db_tasks(self):
268 """
269 Start ofc task for existing ofcs in database
270 :param db_of:
271 :param db_lock:
272 :return:
273 """
274 ofcs = self.get_of_controllers()
275
276 for ofc in ofcs:
277 of_conn = self._load_of_module(ofc)
278 # create ofc thread per of controller
279 self._create_ofc_task(ofc['uuid'], ofc['dpid'], of_conn)
280
281 def _create_ofc_task(self, ofc_uuid, dpid, of_conn):
282 """
283 Create an ofc thread for handle each sdn controllers
284 :param ofc_uuid: sdn controller uuid
285 :param dpid: sdn controller dpid
286 :param of_conn: OF_conn module
287 :return:
288 """
289 if 'ofcs_thread' not in self.config and 'ofcs_thread_dpid' not in self.config:
290 ofcs_threads = {}
291 ofcs_thread_dpid = []
292 else:
293 ofcs_threads = self.config['ofcs_thread']
294 ofcs_thread_dpid = self.config['ofcs_thread_dpid']
295
296 if ofc_uuid not in ofcs_threads:
297 ofc_thread = self._create_ofc_thread(of_conn, ofc_uuid)
298 if ofc_uuid == "Default":
299 self.config['of_thread'] = ofc_thread
300
301 ofcs_threads[ofc_uuid] = ofc_thread
302 self.config['ofcs_thread'] = ofcs_threads
303
304 ofcs_thread_dpid.append({dpid: ofc_thread})
305 self.config['ofcs_thread_dpid'] = ofcs_thread_dpid
306
307 def _start_ofc_default_task(self):
308 """
309 Create default ofc thread
310 """
311 if 'of_controller' not in self.config \
312 and 'of_controller_ip' not in self.config \
313 and 'of_controller_port' not in self.config \
314 and 'of_controller_dpid' not in self.config:
315 return
316
317 # OF THREAD
318 db_config = {}
319 db_config['ip'] = self.config.get('of_controller_ip')
320 db_config['port'] = self.config.get('of_controller_port')
321 db_config['dpid'] = self.config.get('of_controller_dpid')
322 db_config['type'] = self.config.get('of_controller')
323 db_config['user'] = self.config.get('of_user')
324 db_config['password'] = self.config.get('of_password')
325
326 # create connector to the openflow controller
327 # load other parameters starting by of_ from config dict in a temporal dict
328
329 of_conn = self._load_of_module(db_config)
330 # create openflow thread
331 self._create_ofc_task("Default", db_config['dpid'], of_conn)
332
333 def _load_of_module(self, db_config):
334 """
335 import python module for each SDN controller supported
336 :param db_config: SDN dn information
337 :return: Module
338 """
339 if not db_config:
340 raise ovimException("No module found it", HTTP_Internal_Server_Error)
341
342 module_info = None
343
344 try:
345 if self.of_test_mode:
346 return openflow_conn.OfTestConnector({"name": db_config['type'],
347 "dpid": db_config['dpid'],
348 "of_debug": self.config['log_level_of']})
349 temp_dict = {}
350
351 if db_config:
352 temp_dict['of_ip'] = db_config['ip']
353 temp_dict['of_port'] = db_config['port']
354 temp_dict['of_dpid'] = db_config['dpid']
355 temp_dict['of_controller'] = db_config['type']
356 temp_dict['of_user'] = db_config['user']
357 temp_dict['of_password'] = db_config['password']
358
359 temp_dict['of_debug'] = self.config['log_level_of']
360
361 if temp_dict['of_controller'] == 'opendaylight':
362 module = "ODL"
363 else:
364 module = temp_dict['of_controller']
365
366 if module not in ovim.of_module:
367 module_info = imp.find_module(module)
368 of_conn_module = imp.load_module("OF_conn", *module_info)
369 ovim.of_module[module] = of_conn_module
370 else:
371 of_conn_module = ovim.of_module[module]
372
373 try:
374 return of_conn_module.OF_conn(temp_dict)
375 except Exception as e:
376 self.logger.error("Cannot open the Openflow controller '%s': %s", type(e).__name__, str(e))
377 if module_info and module_info[0]:
378 file.close(module_info[0])
379 raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e).__name__, str(e)),
380 HTTP_Internal_Server_Error)
381 except (IOError, ImportError) as e:
382 if module_info and module_info[0]:
383 file.close(module_info[0])
384 self.logger.error("Cannot open openflow controller module '%s'; %s: %s; revise 'of_controller' "
385 "field of configuration file.", module, type(e).__name__, str(e))
386 raise ovimException("Cannot open openflow controller module '{}'; {}: {}; revise 'of_controller' "
387 "field of configuration file.".format(module, type(e).__name__, str(e)),
388 HTTP_Internal_Server_Error)
389
390 def _create_ofc_thread(self, of_conn, ofc_uuid="Default"):
391 """
392 Create and launch a of thread
393 :return: thread obj
394 """
395 # create openflow thread
396
397 #if 'of_controller_nets_with_same_vlan' in self.config:
398 # ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
399 #else:
400 # ofc_net_same_vlan = False
401 ofc_net_same_vlan = False
402
403 thread = oft.openflow_thread(ofc_uuid, of_conn, of_test=self.of_test_mode, db=self.db_of, db_lock=self.db_lock,
404 pmp_with_same_vlan=ofc_net_same_vlan, debug=self.config['log_level_of'])
405 #r, c = thread.OF_connector.obtain_port_correspondence()
406 #if r < 0:
407 # raise ovimException("Cannot get openflow information %s", c)
408 thread.start()
409 return thread
410
411 def stop_service(self):
412 threads = self.config.get('host_threads', {})
413 if 'of_thread' in self.config:
414 threads['of'] = (self.config['of_thread'])
415 if 'ofcs_thread' in self.config:
416 ofcs_thread = self.config['ofcs_thread']
417 for ofc in ofcs_thread:
418 threads[ofc] = ofcs_thread[ofc]
419
420 if 'dhcp_thread' in self.config:
421 threads['dhcp'] = (self.config['dhcp_thread'])
422
423 for thread in threads.values():
424 thread.insert_task("exit")
425 for thread in threads.values():
426 thread.join()
427
428 def get_networks(self, columns=None, db_filter={}, limit=None):
429 """
430 Retreive networks available
431 :param columns: List with select query parameters
432 :param db_filter: List with where query parameters
433 :param limit: Query limit result
434 :return:
435 """
436 result, content = self.db.get_table(SELECT=columns, FROM='nets', WHERE=db_filter, LIMIT=limit)
437
438 if result < 0:
439 raise ovimException(str(content), -result)
440
441 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
442
443 return content
444
445 def show_network(self, network_id, db_filter={}):
446 """
447 Get network from DB by id
448 :param network_id: net Id
449 :param db_filter: List with where query parameters
450 :return:
451 """
452 # obtain data
453 if not network_id:
454 raise ovimException("Not network id was not found")
455 db_filter['uuid'] = network_id
456
457 result, content = self.db.get_table(FROM='nets', WHERE=db_filter, LIMIT=100)
458
459 if result < 0:
460 raise ovimException(str(content), -result)
461 elif result == 0:
462 raise ovimException("show_network network '%s' not found" % network_id, -result)
463 else:
464 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
465 # get ports from DB
466 result, ports = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
467 WHERE={'net_id': network_id}, LIMIT=100)
468 if len(ports) > 0:
469 content[0]['ports'] = ports
470
471 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
472 return content[0]
473
474 def new_network(self, network):
475 """
476 Create a net in DB
477 :return:
478 """
479 tenant_id = network.get('tenant_id')
480
481 if tenant_id:
482 result, _ = self.db.get_table(FROM='tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id, "enabled": True})
483 if result <= 0:
484 raise ovimException("set_network error, no tenant founded", -result)
485
486 bridge_net = None
487 # check valid params
488 net_provider = network.get('provider')
489 net_type = network.get('type')
490 net_vlan = network.get("vlan")
491 net_bind_net = network.get("bind_net")
492 net_bind_type = network.get("bind_type")
493 name = network["name"]
494
495 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
496 vlan_index = name.rfind(":")
497 if not net_bind_net and not net_bind_type and vlan_index > 1:
498 try:
499 vlan_tag = int(name[vlan_index + 1:])
500 if not vlan_tag and vlan_tag < 4096:
501 net_bind_net = name[:vlan_index]
502 net_bind_type = "vlan:" + name[vlan_index + 1:]
503 except:
504 pass
505
506 if net_bind_net:
507 # look for a valid net
508 if self._check_valid_uuid(net_bind_net):
509 net_bind_key = "uuid"
510 else:
511 net_bind_key = "name"
512 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
513 if result < 0:
514 raise ovimException(' getting nets from db ' + content, HTTP_Internal_Server_Error)
515 elif result == 0:
516 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
517 elif result > 1:
518 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
519 network["bind_net"] = content[0]["uuid"]
520
521 if net_bind_type:
522 if net_bind_type[0:5] != "vlan:":
523 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
524 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
525 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
526 HTTP_Bad_Request)
527 network["bind_type"] = net_bind_type
528
529 if net_provider:
530 if net_provider[:9] == "openflow:":
531 if net_type:
532 if net_type != "ptp" and net_type != "data":
533 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
534 HTTP_Bad_Request)
535 else:
536 net_type = 'data'
537 else:
538 if net_type:
539 if net_type != "bridge_man" and net_type != "bridge_data":
540 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
541 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
542 else:
543 net_type = 'bridge_man'
544
545 if not net_type:
546 net_type = 'bridge_man'
547
548 if net_provider:
549 if net_provider[:7] == 'bridge:':
550 # check it is one of the pre-provisioned bridges
551 bridge_net_name = net_provider[7:]
552 for brnet in self.config['bridge_nets']:
553 if brnet[0] == bridge_net_name: # free
554 if not brnet[3]:
555 raise ovimException("invalid 'provider:physical', "
556 "bridge '%s' is already used" % bridge_net_name, HTTP_Conflict)
557 bridge_net = brnet
558 net_vlan = brnet[1]
559 break
560 # if bridge_net==None:
561 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
562 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
563 # return
564
565 elif self.config['network_type'] == 'bridge' and (net_type == 'bridge_data' or net_type == 'bridge_man'):
566 # look for a free precreated nets
567 for brnet in self.config['bridge_nets']:
568 if not brnet[3]: # free
569 if not bridge_net:
570 if net_type == 'bridge_man': # look for the smaller speed
571 if brnet[2] < bridge_net[2]:
572 bridge_net = brnet
573 else: # look for the larger speed
574 if brnet[2] > bridge_net[2]:
575 bridge_net = brnet
576 else:
577 bridge_net = brnet
578 net_vlan = brnet[1]
579 if not bridge_net:
580 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
581 "will overcome this limit", HTTP_Bad_Request)
582 else:
583 self.logger.debug("using net " + bridge_net)
584 net_provider = "bridge:" + bridge_net[0]
585 net_vlan = bridge_net[1]
586 elif net_type == 'bridge_data' or net_type == 'bridge_man' and self.config['network_type'] == 'ovs':
587 net_provider = 'OVS'
588 if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
589 net_vlan = self.db.get_free_net_vlan()
590 if net_vlan < 0:
591 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error)
592 if net_provider == 'OVS':
593 net_provider = 'OVS' + ":" + str(net_vlan)
594
595 network['provider'] = net_provider
596 network['type'] = net_type
597 network['vlan'] = net_vlan
598 dhcp_integrity = True
599 if 'enable_dhcp' in network and network['enable_dhcp']:
600 dhcp_integrity = self._check_dhcp_data_integrity(network)
601
602 result, content = self.db.new_row('nets', network, True, True)
603
604 if result >= 0 and dhcp_integrity:
605 if bridge_net:
606 bridge_net[3] = content
607 if self.config.get("dhcp_server") and self.config['network_type'] == 'bridge':
608 if network["name"] in self.config["dhcp_server"].get("nets", ()):
609 self.config["dhcp_nets"].append(content)
610 self.logger.debug("dhcp_server: add new net", content)
611 elif not bridge_net and bridge_net[0] in self.config["dhcp_server"].get("bridge_ifaces", ()):
612 self.config["dhcp_nets"].append(content)
613 self.logger.debug("dhcp_server: add new net", content, content)
614 return content
615 else:
616 raise ovimException("Error posting network", HTTP_Internal_Server_Error)
617 # TODO kei change update->edit
618
619 def edit_network(self, network_id, network):
620 """
621 Update entwork data byt id
622 :return:
623 """
624 # Look for the previous data
625 where_ = {'uuid': network_id}
626 result, network_old = self.db.get_table(FROM='nets', WHERE=where_)
627 if result < 0:
628 raise ovimException("Error updating network %s" % network_old, HTTP_Internal_Server_Error)
629 elif result == 0:
630 raise ovimException('network %s not found' % network_id, HTTP_Not_Found)
631 # get ports
632 nbports, content = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
633 WHERE={'net_id': network_id}, LIMIT=100)
634 if result < 0:
635 raise ovimException("http_put_network_id error %d %s" % (result, network_old), HTTP_Internal_Server_Error)
636 if nbports > 0:
637 if 'type' in network and network['type'] != network_old[0]['type']:
638 raise ovimException("Can not change type of network while having ports attached",
639 HTTP_Method_Not_Allowed)
640 if 'vlan' in network and network['vlan'] != network_old[0]['vlan']:
641 raise ovimException("Can not change vlan of network while having ports attached",
642 HTTP_Method_Not_Allowed)
643
644 # check valid params
645 net_provider = network.get('provider', network_old[0]['provider'])
646 net_type = network.get('type', network_old[0]['type'])
647 net_bind_net = network.get("bind_net")
648 net_bind_type = network.get("bind_type")
649 if net_bind_net:
650 # look for a valid net
651 if self._check_valid_uuid(net_bind_net):
652 net_bind_key = "uuid"
653 else:
654 net_bind_key = "name"
655 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
656 if result < 0:
657 raise ovimException('Getting nets from db ' + content, HTTP_Internal_Server_Error)
658 elif result == 0:
659 raise ovimException("bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
660 elif result > 1:
661 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net),
662 HTTP_Bad_Request)
663 network["bind_net"] = content[0]["uuid"]
664 if net_bind_type:
665 if net_bind_type[0:5] != "vlan:":
666 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
667 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
668 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
669 HTTP_Bad_Request)
670 if net_provider:
671 if net_provider[:9] == "openflow:":
672 if net_type != "ptp" and net_type != "data":
673 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request)
674 else:
675 if net_type != "bridge_man" and net_type != "bridge_data":
676 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
677 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
678
679 # insert in data base
680 result, content = self.db.update_rows('nets', network, WHERE={'uuid': network_id}, log=True)
681 if result >= 0:
682 # if result > 0 and nbports>0 and 'admin_state_up' in network
683 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
684 if result > 0:
685
686 try:
687 if nbports:
688 self.net_update_ofc_thread(network_id)
689 except ovimException as e:
690 raise ovimException("Error while launching openflow rules in network '{}' {}"
691 .format(network_id, str(e)), HTTP_Internal_Server_Error)
692 except Exception as e:
693 raise ovimException("Error while launching openflow rules in network '{}' {}"
694 .format(network_id, str(e)), HTTP_Internal_Server_Error)
695
696 if self.config.get("dhcp_server"):
697 if network_id in self.config["dhcp_nets"]:
698 self.config["dhcp_nets"].remove(network_id)
699 if network.get("name", network_old[0]["name"]) in self.config["dhcp_server"].get("nets", ()):
700 self.config["dhcp_nets"].append(network_id)
701 else:
702 net_bind = network.get("bind_type", network_old[0]["bind_type"])
703 if net_bind and net_bind and net_bind[:7] == "bridge:" and net_bind[7:] in self.config["dhcp_server"].get(
704 "bridge_ifaces", ()):
705 self.config["dhcp_nets"].append(network_id)
706 return network_id
707 else:
708 raise ovimException(content, -result)
709
710 def delete_network(self, network_id):
711 """
712 Delete network by network id
713 :param network_id: network id
714 :return:
715 """
716
717 # delete from the data base
718 result, content = self.db.delete_row('nets', network_id)
719
720 if result == 0:
721 raise ovimException("Network %s not found " % network_id, HTTP_Not_Found)
722 elif result > 0:
723 for brnet in self.config['bridge_nets']:
724 if brnet[3] == network_id:
725 brnet[3] = None
726 break
727 if self.config.get("dhcp_server") and network_id in self.config["dhcp_nets"]:
728 self.config["dhcp_nets"].remove(network_id)
729 return content
730 else:
731 raise ovimException("Error deleting network %s" % network_id, HTTP_Internal_Server_Error)
732
733 def get_openflow_rules(self, network_id=None):
734 """
735 Get openflow id from DB
736 :param network_id: Network id, if none all networks will be retrieved
737 :return: Return a list with Openflow rules per net
738 """
739 # ignore input data
740 if not network_id:
741 where_ = {}
742 else:
743 where_ = {"net_id": network_id}
744 result, content = self.db.get_table(
745 SELECT=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
746 WHERE=where_, FROM='of_flows')
747
748 if result < 0:
749 raise ovimException(str(content), -result)
750 return content
751
752 def edit_openflow_rules(self, network_id=None):
753
754 """
755 To make actions over the net. The action is to reinstall the openflow rules
756 network_id can be 'all'
757 :param network_id: Network id, if none all networks will be retrieved
758 :return : Number of nets updated
759 """
760
761 # ignore input data
762 if not network_id:
763 where_ = {}
764 else:
765 where_ = {"uuid": network_id}
766 result, content = self.db.get_table(SELECT=("uuid", "type"), WHERE=where_, FROM='nets')
767
768 if result < 0:
769 raise ovimException(str(content), -result)
770
771 for net in content:
772 if net["type"] != "ptp" and net["type"] != "data":
773 result -= 1
774 continue
775
776 try:
777 self.net_update_ofc_thread(net['uuid'])
778 except ovimException as e:
779 raise ovimException("Error updating network'{}' {}".format(net['uuid'], str(e)),
780 HTTP_Internal_Server_Error)
781 except Exception as e:
782 raise ovimException("Error updating network '{}' {}".format(net['uuid'], str(e)),
783 HTTP_Internal_Server_Error)
784
785 return result
786
787 def delete_openflow_rules(self, ofc_id=None):
788 """
789 To make actions over the net. The action is to delete ALL openflow rules
790 :return: return operation result
791 """
792
793 if not ofc_id:
794 if 'Default' in self.config['ofcs_thread']:
795 r, c = self.config['ofcs_thread']['Default'].insert_task("clear-all")
796 else:
797 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
798
799 elif ofc_id in self.config['ofcs_thread']:
800 r, c = self.config['ofcs_thread'][ofc_id].insert_task("clear-all")
801
802 # ignore input data
803 if r < 0:
804 raise ovimException(str(c), -r)
805 else:
806 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
807 return r
808
809 def get_openflow_ports(self, ofc_id=None):
810 """
811 Obtain switch ports names of openflow controller
812 :return: Return flow ports in DB
813 """
814 if not ofc_id:
815 if 'Default' in self.config['ofcs_thread']:
816 conn = self.config['ofcs_thread']['Default'].OF_connector
817 else:
818 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
819
820 if ofc_id in self.config['ofcs_thread']:
821 conn = self.config['ofcs_thread'][ofc_id].OF_connector
822 else:
823 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
824 return conn.pp2ofi
825
826 def get_ports(self, columns=None, filter={}, limit=None):
827 # result, content = my.db.get_ports(where_)
828 result, content = self.db.get_table(SELECT=columns, WHERE=filter, FROM='ports', LIMIT=limit)
829 if result < 0:
830 self.logger.error("http_get_ports Error %d %s", result, content)
831 raise ovimException(str(content), -result)
832 else:
833 convert_boolean(content, ('admin_state_up',))
834 return content
835
836 def new_port(self, port_data):
837 port_data['type'] = 'external'
838 if port_data.get('net_id'):
839 # check that new net has the correct type
840 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
841 if result < 0:
842 raise ovimException(str(new_net), -result)
843 # insert in data base
844 result, uuid = self.db.new_row('ports', port_data, True, True)
845 if result > 0:
846 if 'net_id' in port_data:
847 try:
848 self.net_update_ofc_thread(port_data['net_id'])
849 except ovimException as e:
850 raise ovimException("Cannot insert a task for updating network '{}' {}"
851 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
852 except Exception as e:
853 raise ovimException("Cannot insert a task for updating network '{}' {}"
854 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
855
856 return uuid
857 else:
858 raise ovimException(str(uuid), -result)
859
860 def new_external_port(self, port_data):
861 """
862 Create new external port and check port mapping correspondence
863 :param port_data: port_data = {
864 'region': 'datacenter region',
865 'compute_node': 'compute node id',
866 'pci': 'pci port address',
867 'vlan': 'net vlan',
868 'net_id': 'net id',
869 'tenant_id': 'tenant id',
870 'mac': 'switch mac',
871 'name': 'port name'
872 'ip_address': 'ip address - optional'}
873 :return:
874 """
875
876 port_data['type'] = 'external'
877
878 if port_data.get('net_id'):
879 # check that new net has the correct type
880 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
881 if result < 0:
882 raise ovimException(str(new_net), -result)
883 # insert in data base
884 db_filter = {}
885
886 if port_data.get('region'):
887 db_filter['region'] = port_data['region']
888 if port_data.get('pci'):
889 db_filter['pci'] = port_data['pci']
890 if port_data.get('compute_node'):
891 db_filter['compute_node'] = port_data['compute_node']
892
893 columns = ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
894 port_mapping_data = self.get_of_port_mappings(columns, db_filter)
895
896 if not len(port_mapping_data):
897 raise ovimException("No port mapping founded for '{}'".format(str(db_filter)),
898 HTTP_Not_Found)
899 elif len(port_mapping_data) > 1:
900 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
901 HTTP_Conflict)
902
903 port_data['ofc_id'] = port_mapping_data[0]['ofc_id']
904 port_data['switch_dpid'] = port_mapping_data[0]['switch_dpid']
905 port_data['switch_port'] = port_mapping_data[0]['switch_port']
906 port_data['switch_mac'] = port_mapping_data[0]['switch_mac']
907
908 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
909 if 'region' in port_data:
910 del port_data['region']
911 if 'pci' in port_data:
912 del port_data['pci']
913 if 'compute_node' in port_data:
914 del port_data['compute_node']
915
916 result, uuid = self.db.new_row('ports', port_data, True, True)
917 if result > 0:
918 try:
919 self.net_update_ofc_thread(port_data['net_id'], port_data['ofc_id'])
920 except ovimException as e:
921 raise ovimException("Cannot insert a task for updating network '{}' {}".
922 format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
923 except Exception as e:
924 raise ovimException("Cannot insert a task for updating network '{}' {}"
925 .format(port_data['net_id'], e), HTTP_Internal_Server_Error)
926 return uuid
927 else:
928 raise ovimException(str(uuid), -result)
929
930 def net_update_ofc_thread(self, net_id, ofc_id=None, switch_dpid=None):
931 """
932 Insert a update net task by net id or ofc_id for each ofc thread
933 :param net_id: network id
934 :param ofc_id: openflow controller id
935 :param switch_dpid: switch dpid
936 :return:
937 """
938 if not net_id:
939 raise ovimException("No net_id received", HTTP_Internal_Server_Error)
940
941 r = -1
942 c = 'No valid ofc_id or switch_dpid received'
943
944 if not ofc_id:
945 ports = self.get_ports(filter={"net_id": net_id})
946 for port in ports:
947 port_ofc_id = port.get('ofc_id', None)
948 if port_ofc_id:
949 ofc_id = port['ofc_id']
950 switch_dpid = port['switch_dpid']
951 break
952 #TODO if not ofc_id: look at database table ofcs
953
954
955 # If no ofc_id found it, default ofc_id is used.
956 if not ofc_id and not switch_dpid:
957 ofc_id = "Default"
958
959 if ofc_id and ofc_id in self.config['ofcs_thread']:
960 r, c = self.config['ofcs_thread'][ofc_id].insert_task("update-net", net_id)
961 elif switch_dpid:
962
963 ofcs_dpid_list = self.config['ofcs_thread_dpid']
964 for ofc_t in ofcs_dpid_list:
965 if switch_dpid in ofc_t:
966 r, c = ofc_t[switch_dpid].insert_task("update-net", net_id)
967
968 if r < 0:
969 message = "Cannot insert a task for updating network '{}', {}".format(net_id, c)
970 self.logger.error(message)
971 raise ovimException(message, HTTP_Internal_Server_Error)
972
973 def delete_port(self, port_id):
974 # Look for the previous port data
975 result, ports = self.db.get_table(WHERE={'uuid': port_id, "type": "external"}, FROM='ports')
976 if result < 0:
977 raise ovimException("Cannot get port info from database: {}".format(ports), http_code=-result)
978 # delete from the data base
979 result, content = self.db.delete_row('ports', port_id)
980 if result == 0:
981 raise ovimException("External port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
982 elif result < 0:
983 raise ovimException("Cannot delete port from database: {}".format(content), http_code=-result)
984 # update network
985 network = ports[0].get('net_id', None)
986 if network:
987 # change of net.
988
989 try:
990 self.net_update_ofc_thread(network, ofc_id=ports[0]["ofc_id"], switch_dpid=ports[0]["switch_dpid"])
991 except ovimException as e:
992 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
993 HTTP_Internal_Server_Error)
994 except Exception as e:
995 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
996 HTTP_Internal_Server_Error)
997
998 return content
999
1000 def edit_port(self, port_id, port_data, admin=True):
1001 # Look for the previous port data
1002 result, content = self.db.get_table(FROM="ports", WHERE={'uuid': port_id})
1003 if result < 0:
1004 raise ovimException("Cannot get port info from database: {}".format(content), http_code=-result)
1005 elif result == 0:
1006 raise ovimException("Port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1007 port = content[0]
1008 nets = []
1009 host_id = None
1010 result = 1
1011 if 'net_id' in port_data:
1012 # change of net.
1013 old_net = port.get('net_id', None)
1014 new_net = port_data['net_id']
1015 if old_net != new_net:
1016
1017 if new_net:
1018 nets.append(new_net) # put first the new net, so that new openflow rules are created before removing the old ones
1019 if old_net:
1020 nets.append(old_net)
1021 if port['type'] == 'instance:bridge' or port['type'] == 'instance:ovs':
1022 raise ovimException("bridge interfaces cannot be attached to a different net", http_code=HTTP_Forbidden)
1023 elif port['type'] == 'external' and not admin:
1024 raise ovimException("Needed admin privileges",http_code=HTTP_Unauthorized)
1025 if new_net:
1026 # check that new net has the correct type
1027 result, new_net_dict = self.db.check_target_net(new_net, None, port['type'])
1028 if result < 0:
1029 raise ovimException("Error {}".format(new_net_dict), http_code=HTTP_Conflict)
1030 # change VLAN for SR-IOV ports
1031 if result >= 0 and port["type"] == "instance:data" and port["model"] == "VF": # TODO consider also VFnotShared
1032 if new_net:
1033 port_data["vlan"] = None
1034 else:
1035 port_data["vlan"] = new_net_dict["vlan"]
1036 # get host where this VM is allocated
1037 result, content = self.db.get_table(FROM="instances", WHERE={"uuid": port["instance_id"]})
1038 if result > 0:
1039 host_id = content[0]["host_id"]
1040
1041 # insert in data base
1042 if result >= 0:
1043 result, content = self.db.update_rows('ports', port_data, WHERE={'uuid': port_id}, log=False)
1044 port.update(port_data)
1045
1046 # Insert task to complete actions
1047 if result > 0:
1048 for net_id in nets:
1049 try:
1050 self.net_update_ofc_thread(net_id, port["ofc_id"], switch_dpid=port["switch_dpid"])
1051 except ovimException as e:
1052 raise ovimException("Error updating network'{}' {}".format(net_id, str(e)),
1053 HTTP_Internal_Server_Error)
1054 except Exception as e:
1055 raise ovimException("Error updating network '{}' {}".format(net_id, str(e)),
1056 HTTP_Internal_Server_Error)
1057
1058 if host_id:
1059 r, v = self.config['host_threads'][host_id].insert_task("edit-iface", port_id, old_net, new_net)
1060 if r < 0:
1061 self.logger.error("Error updating network '{}' {}".format(r,v))
1062 # TODO Do something if fails
1063 if result >= 0:
1064 return port_id
1065 else:
1066 raise ovimException("Error {}".format(content), http_code=-result)
1067
1068 def new_of_controller(self, ofc_data):
1069 """
1070 Create a new openflow controller into DB
1071 :param ofc_data: Dict openflow controller data
1072 :return: openflow controller dpid
1073 """
1074
1075 result, ofc_uuid = self.db.new_row('ofcs', ofc_data, True, True)
1076 if result < 0:
1077 raise ovimException("New ofc Error %s" % ofc_uuid, HTTP_Internal_Server_Error)
1078
1079 ofc_data['uuid'] = ofc_uuid
1080 of_conn = self._load_of_module(ofc_data)
1081 self._create_ofc_task(ofc_uuid, ofc_data['dpid'], of_conn)
1082
1083 return ofc_uuid
1084
1085 def edit_of_controller(self, of_id, ofc_data):
1086 """
1087 Edit an openflow controller entry from DB
1088 :return:
1089 """
1090 if not ofc_data:
1091 raise ovimException("No data received during uptade OF contorller", http_code=HTTP_Internal_Server_Error)
1092
1093 old_of_controller = self.show_of_controller(of_id)
1094
1095 if old_of_controller:
1096 result, content = self.db.update_rows('ofcs', ofc_data, WHERE={'uuid': of_id}, log=False)
1097 if result >= 0:
1098 return ofc_data
1099 else:
1100 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1101 http_code=-result)
1102 else:
1103 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1104 http_code=HTTP_Internal_Server_Error)
1105
1106 def delete_of_controller(self, of_id):
1107 """
1108 Delete an openflow controller from DB.
1109 :param of_id: openflow controller dpid
1110 :return:
1111 """
1112
1113 ofc = self.show_of_controller(of_id)
1114
1115 result, content = self.db.delete_row("ofcs", of_id)
1116 if result < 0:
1117 raise ovimException("Cannot delete ofc from database: {}".format(content), http_code=-result)
1118 elif result == 0:
1119 raise ovimException("ofc {} not found ".format(content), http_code=HTTP_Not_Found)
1120
1121 ofc_thread = self.config['ofcs_thread'][of_id]
1122 del self.config['ofcs_thread'][of_id]
1123 for ofc_th in self.config['ofcs_thread_dpid']:
1124 if ofc['dpid'] in ofc_th:
1125 self.config['ofcs_thread_dpid'].remove(ofc_th)
1126
1127 ofc_thread.insert_task("exit")
1128 #ofc_thread.join()
1129
1130 return content
1131
1132 def show_of_controller(self, uuid):
1133 """
1134 Show an openflow controller by dpid from DB.
1135 :param db_filter: List with where query parameters
1136 :return:
1137 """
1138
1139 result, content = self.db.get_table(FROM='ofcs', WHERE={"uuid": uuid}, LIMIT=100)
1140
1141 if result == 0:
1142 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid),
1143 http_code=HTTP_Not_Found)
1144 elif result < 0:
1145 raise ovimException("Openflow controller with uuid '{}' error".format(uuid),
1146 http_code=HTTP_Internal_Server_Error)
1147 return content[0]
1148
1149 def get_of_controllers(self, columns=None, db_filter={}, limit=None):
1150 """
1151 Show an openflow controllers from DB.
1152 :param columns: List with SELECT query parameters
1153 :param db_filter: List with where query parameters
1154 :param limit: result Limit
1155 :return:
1156 """
1157 result, content = self.db.get_table(SELECT=columns, FROM='ofcs', WHERE=db_filter, LIMIT=limit)
1158
1159 if result < 0:
1160 raise ovimException(str(content), -result)
1161
1162 return content
1163
1164 def get_tenants(self, columns=None, db_filter={}, limit=None):
1165 """
1166 Retrieve tenant list from DB
1167 :param columns: List with SELECT query parameters
1168 :param db_filter: List with where query parameters
1169 :param limit: result limit
1170 :return:
1171 """
1172 result, content = self.db.get_table(FROM='tenants', SELECT=columns, WHERE=db_filter, LIMIT=limit)
1173 if result < 0:
1174 raise ovimException('get_tenatns Error {}'.format(str(content)), -result)
1175 else:
1176 convert_boolean(content, ('enabled',))
1177 return content
1178
1179 def show_tenant_id(self, tenant_id):
1180 """
1181 Get tenant from DB by id
1182 :param tenant_id: tenant id
1183 :return:
1184 """
1185 result, content = self.db.get_table(FROM='tenants', SELECT=('uuid', 'name', 'description', 'enabled'),
1186 WHERE={"uuid": tenant_id})
1187 if result < 0:
1188 raise ovimException(str(content), -result)
1189 elif result == 0:
1190 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1191 else:
1192 convert_boolean(content, ('enabled',))
1193 return content[0]
1194
1195 def new_tentant(self, tenant):
1196 """
1197 Create a tenant and store in DB
1198 :param tenant: Dictionary with tenant data
1199 :return: the uuid of created tenant. Raise exception upon error
1200 """
1201
1202 # insert in data base
1203 result, tenant_uuid = self.db.new_tenant(tenant)
1204
1205 if result >= 0:
1206 return tenant_uuid
1207 else:
1208 raise ovimException(str(tenant_uuid), -result)
1209
1210 def delete_tentant(self, tenant_id):
1211 """
1212 Delete a tenant from the database.
1213 :param tenant_id: Tenant id
1214 :return: delete tenant id
1215 """
1216
1217 # check permissions
1218 r, tenants_flavors = self.db.get_table(FROM='tenants_flavors', SELECT=('flavor_id', 'tenant_id'),
1219 WHERE={'tenant_id': tenant_id})
1220 if r <= 0:
1221 tenants_flavors = ()
1222 r, tenants_images = self.db.get_table(FROM='tenants_images', SELECT=('image_id', 'tenant_id'),
1223 WHERE={'tenant_id': tenant_id})
1224 if r <= 0:
1225 tenants_images = ()
1226
1227 result, content = self.db.delete_row('tenants', tenant_id)
1228 if result == 0:
1229 raise ovimException("tenant '%s' not found" % tenant_id, HTTP_Not_Found)
1230 elif result > 0:
1231 for flavor in tenants_flavors:
1232 self.db.delete_row_by_key("flavors", "uuid", flavor['flavor_id'])
1233 for image in tenants_images:
1234 self.db.delete_row_by_key("images", "uuid", image['image_id'])
1235 return content
1236 else:
1237 raise ovimException("Error deleting tenant '%s' " % tenant_id, HTTP_Internal_Server_Error)
1238
1239 def edit_tenant(self, tenant_id, tenant_data):
1240 """
1241 Update a tenant data identified by tenant id
1242 :param tenant_id: tenant id
1243 :param tenant_data: Dictionary with tenant data
1244 :return:
1245 """
1246
1247 # Look for the previous data
1248 result, tenant_data_old = self.db.get_table(FROM='tenants', WHERE={'uuid': tenant_id})
1249 if result < 0:
1250 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id, tenant_data_old),
1251 HTTP_Internal_Server_Error)
1252 elif result == 0:
1253 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1254
1255 # insert in data base
1256 result, content = self.db.update_rows('tenants', tenant_data, WHERE={'uuid': tenant_id}, log=True)
1257 if result >= 0:
1258 return content
1259 else:
1260 raise ovimException(str(content), -result)
1261
1262 def set_of_port_mapping(self, of_maps, ofc_id=None, switch_dpid=None, region=None):
1263 """
1264 Create new port mapping entry
1265 :param of_maps: List with port mapping information
1266 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1267 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1268 :param ofc_id: ofc id
1269 :param switch_dpid: switch dpid
1270 :param region: datacenter region id
1271 :return:
1272 """
1273
1274 for map in of_maps:
1275 if ofc_id:
1276 map['ofc_id'] = ofc_id
1277 if switch_dpid:
1278 map['switch_dpid'] = switch_dpid
1279 if region:
1280 map['region'] = region
1281
1282 for of_map in of_maps:
1283 result, uuid = self.db.new_row('of_port_mappings', of_map, True)
1284 if result > 0:
1285 of_map["uuid"] = uuid
1286 else:
1287 raise ovimException(str(uuid), -result)
1288 return of_maps
1289
1290 def clear_of_port_mapping(self, db_filter={}):
1291 """
1292 Clear port mapping filtering using db_filter dict
1293 :param db_filter: Parameter to filter during remove process
1294 :return:
1295 """
1296 result, content = self.db.delete_row_by_dict(FROM='of_port_mappings', WHERE=db_filter)
1297 # delete_row_by_key
1298 if result >= 0:
1299 return content
1300 else:
1301 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter)),
1302 HTTP_Internal_Server_Error)
1303
1304 def get_of_port_mappings(self, column=None, db_filter=None, db_limit=None):
1305 """
1306 Retrive port mapping from DB
1307 :param column:
1308 :param db_filter:
1309 :return:
1310 """
1311 result, content = self.db.get_table(SELECT=column, WHERE=db_filter, FROM='of_port_mappings', LIMIT=db_limit)
1312
1313 if result < 0:
1314 self.logger.error("get_of_port_mappings Error %d %s", result, content)
1315 raise ovimException(str(content), -result)
1316 else:
1317 return content
1318
1319 def get_dhcp_controller(self):
1320 """
1321 Create an host_thread object for manage openvim controller and not create a thread for itself
1322 :return: dhcp_host openvim controller object
1323 """
1324
1325 if 'openvim_controller' in self.config['host_threads']:
1326 return self.config['host_threads']['openvim_controller']
1327
1328 bridge_ifaces = []
1329 controller_ip = self.config['ovs_controller_ip']
1330 ovs_controller_user = self.config['ovs_controller_user']
1331
1332 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
1333 host_develop_mode = True if self.config['mode'] == 'development' else False
1334
1335 dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip,
1336 db=self.db_of,
1337 db_lock=self.db_lock, test=host_test_mode,
1338 image_path=self.config['image_path'], version=self.config['version'],
1339 host_id='openvim_controller', develop_mode=host_develop_mode,
1340 develop_bridge_iface=bridge_ifaces)
1341
1342 self.config['host_threads']['openvim_controller'] = dhcp_host
1343 if not host_test_mode:
1344 dhcp_host.ssh_connect()
1345 return dhcp_host
1346
1347 def launch_dhcp_server(self, vlan, first_ip, last_ip, cidr, gateway):
1348 """
1349 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1350 :param vlan: vlan identifier
1351 :param first_ip: First dhcp range ip
1352 :param last_ip: Last dhcp range ip
1353 :param cidr: net cidr
1354 :param gateway: net gateway
1355 :return:
1356 """
1357 ip_tools = IPNetwork(cidr)
1358 dhcp_netmask = str(ip_tools.netmask)
1359 ip_range = [first_ip, last_ip]
1360
1361 dhcp_path = self.config['ovs_controller_file_path']
1362
1363 controller_host = self.get_dhcp_controller()
1364 controller_host.create_linux_bridge(vlan)
1365 controller_host.create_dhcp_interfaces(vlan, first_ip, dhcp_netmask)
1366 controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path, gateway)
1367
1368