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