Fixed bug that was ommiting the user and password info of the SDN controllers
[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 temp_dict['of_user'] = db_config['user']
355 temp_dict['of_password'] = db_config['password']
356
357 temp_dict['of_debug'] = self.config['log_level_of']
358
359 if temp_dict['of_controller'] == 'opendaylight':
360 module = "ODL"
361 else:
362 module = temp_dict['of_controller']
363
364 if module not in ovim.of_module:
365 module_info = imp.find_module(module)
366 of_conn_module = imp.load_module("OF_conn", *module_info)
367 ovim.of_module[module] = of_conn_module
368 else:
369 of_conn_module = ovim.of_module[module]
370
371 try:
372 return of_conn_module.OF_conn(temp_dict)
373 except Exception as e:
374 self.logger.error("Cannot open the Openflow controller '%s': %s", type(e).__name__, str(e))
375 if module_info and module_info[0]:
376 file.close(module_info[0])
377 raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e).__name__, str(e)),
378 HTTP_Internal_Server_Error)
379 except (IOError, ImportError) as e:
380 if module_info and module_info[0]:
381 file.close(module_info[0])
382 self.logger.error("Cannot open openflow controller module '%s'; %s: %s; revise 'of_controller' "
383 "field of configuration file.", module, type(e).__name__, str(e))
384 raise ovimException("Cannot open openflow controller module '{}'; {}: {}; revise 'of_controller' "
385 "field of configuration file.".format(module, type(e).__name__, str(e)),
386 HTTP_Internal_Server_Error)
387
388 def _create_ofc_thread(self, of_conn, ofc_uuid="Default"):
389 """
390 Create and launch a of thread
391 :return: thread obj
392 """
393 # create openflow thread
394
395 if 'of_controller_nets_with_same_vlan' in self.config:
396 ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
397 else:
398 ofc_net_same_vlan = False
399
400 thread = oft.openflow_thread(ofc_uuid, of_conn, of_test=self.of_test_mode, db=self.db_of, db_lock=self.db_lock,
401 pmp_with_same_vlan=ofc_net_same_vlan, debug=self.config['log_level_of'])
402 #r, c = thread.OF_connector.obtain_port_correspondence()
403 #if r < 0:
404 # raise ovimException("Cannot get openflow information %s", c)
405 thread.start()
406 return thread
407
408 def stop_service(self):
409 threads = self.config.get('host_threads', {})
410 if 'of_thread' in self.config:
411 threads['of'] = (self.config['of_thread'])
412 if 'ofcs_thread' in self.config:
413 ofcs_thread = self.config['ofcs_thread']
414 for ofc in ofcs_thread:
415 threads[ofc] = ofcs_thread[ofc]
416
417 if 'dhcp_thread' in self.config:
418 threads['dhcp'] = (self.config['dhcp_thread'])
419
420 for thread in threads.values():
421 thread.insert_task("exit")
422 for thread in threads.values():
423 thread.join()
424
425 def get_networks(self, columns=None, db_filter={}, limit=None):
426 """
427 Retreive networks available
428 :param columns: List with select query parameters
429 :param db_filter: List with where query parameters
430 :param limit: Query limit result
431 :return:
432 """
433 result, content = self.db.get_table(SELECT=columns, FROM='nets', WHERE=db_filter, LIMIT=limit)
434
435 if result < 0:
436 raise ovimException(str(content), -result)
437
438 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
439
440 return content
441
442 def show_network(self, network_id, db_filter={}):
443 """
444 Get network from DB by id
445 :param network_id: net Id
446 :param db_filter: List with where query parameters
447 :return:
448 """
449 # obtain data
450 if not network_id:
451 raise ovimException("Not network id was not found")
452 db_filter['uuid'] = network_id
453
454 result, content = self.db.get_table(FROM='nets', WHERE=db_filter, LIMIT=100)
455
456 if result < 0:
457 raise ovimException(str(content), -result)
458 elif result == 0:
459 raise ovimException("show_network network '%s' not found" % network_id, -result)
460 else:
461 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
462 # get ports from DB
463 result, ports = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
464 WHERE={'net_id': network_id}, LIMIT=100)
465 if len(ports) > 0:
466 content[0]['ports'] = ports
467
468 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
469 return content[0]
470
471 def new_network(self, network):
472 """
473 Create a net in DB
474 :return:
475 """
476 tenant_id = network.get('tenant_id')
477
478 if tenant_id:
479 result, _ = self.db.get_table(FROM='tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id, "enabled": True})
480 if result <= 0:
481 raise ovimException("set_network error, no tenant founded", -result)
482
483 bridge_net = None
484 # check valid params
485 net_provider = network.get('provider')
486 net_type = network.get('type')
487 net_vlan = network.get("vlan")
488 net_bind_net = network.get("bind_net")
489 net_bind_type = network.get("bind_type")
490 name = network["name"]
491
492 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
493 vlan_index = name.rfind(":")
494 if not net_bind_net and not net_bind_type and vlan_index > 1:
495 try:
496 vlan_tag = int(name[vlan_index + 1:])
497 if not vlan_tag and vlan_tag < 4096:
498 net_bind_net = name[:vlan_index]
499 net_bind_type = "vlan:" + name[vlan_index + 1:]
500 except:
501 pass
502
503 if net_bind_net:
504 # look for a valid net
505 if self._check_valid_uuid(net_bind_net):
506 net_bind_key = "uuid"
507 else:
508 net_bind_key = "name"
509 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
510 if result < 0:
511 raise ovimException(' getting nets from db ' + content, HTTP_Internal_Server_Error)
512 elif result == 0:
513 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
514 elif result > 1:
515 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
516 network["bind_net"] = content[0]["uuid"]
517
518 if net_bind_type:
519 if net_bind_type[0:5] != "vlan:":
520 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
521 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
522 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
523 HTTP_Bad_Request)
524 network["bind_type"] = net_bind_type
525
526 if net_provider:
527 if net_provider[:9] == "openflow:":
528 if net_type:
529 if net_type != "ptp" and net_type != "data":
530 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
531 HTTP_Bad_Request)
532 else:
533 net_type = 'data'
534 else:
535 if net_type:
536 if net_type != "bridge_man" and net_type != "bridge_data":
537 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
538 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
539 else:
540 net_type = 'bridge_man'
541
542 if not net_type:
543 net_type = 'bridge_man'
544
545 if net_provider:
546 if net_provider[:7] == 'bridge:':
547 # check it is one of the pre-provisioned bridges
548 bridge_net_name = net_provider[7:]
549 for brnet in self.config['bridge_nets']:
550 if brnet[0] == bridge_net_name: # free
551 if not brnet[3]:
552 raise ovimException("invalid 'provider:physical', "
553 "bridge '%s' is already used" % bridge_net_name, HTTP_Conflict)
554 bridge_net = brnet
555 net_vlan = brnet[1]
556 break
557 # if bridge_net==None:
558 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
559 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
560 # return
561
562 elif self.config['network_type'] == 'bridge' and (net_type == 'bridge_data' or net_type == 'bridge_man'):
563 # look for a free precreated nets
564 for brnet in self.config['bridge_nets']:
565 if not brnet[3]: # free
566 if not bridge_net:
567 if net_type == 'bridge_man': # look for the smaller speed
568 if brnet[2] < bridge_net[2]:
569 bridge_net = brnet
570 else: # look for the larger speed
571 if brnet[2] > bridge_net[2]:
572 bridge_net = brnet
573 else:
574 bridge_net = brnet
575 net_vlan = brnet[1]
576 if not bridge_net:
577 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
578 "will overcome this limit", HTTP_Bad_Request)
579 else:
580 self.logger.debug("using net " + bridge_net)
581 net_provider = "bridge:" + bridge_net[0]
582 net_vlan = bridge_net[1]
583 elif net_type == 'bridge_data' or net_type == 'bridge_man' and self.config['network_type'] == 'ovs':
584 net_provider = 'OVS'
585 if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
586 net_vlan = self.db.get_free_net_vlan()
587 if net_vlan < 0:
588 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error)
589 if net_provider == 'OVS':
590 net_provider = 'OVS' + ":" + str(net_vlan)
591
592 network['provider'] = net_provider
593 network['type'] = net_type
594 network['vlan'] = net_vlan
595 dhcp_integrity = True
596 if 'enable_dhcp' in network and network['enable_dhcp']:
597 dhcp_integrity = self._check_dhcp_data_integrity(network)
598
599 result, content = self.db.new_row('nets', network, True, True)
600
601 if result >= 0 and dhcp_integrity:
602 if bridge_net:
603 bridge_net[3] = content
604 if self.config.get("dhcp_server") and self.config['network_type'] == 'bridge':
605 if network["name"] in self.config["dhcp_server"].get("nets", ()):
606 self.config["dhcp_nets"].append(content)
607 self.logger.debug("dhcp_server: add new net", content)
608 elif not bridge_net and bridge_net[0] in self.config["dhcp_server"].get("bridge_ifaces", ()):
609 self.config["dhcp_nets"].append(content)
610 self.logger.debug("dhcp_server: add new net", content, content)
611 return content
612 else:
613 raise ovimException("Error posting network", HTTP_Internal_Server_Error)
614 # TODO kei change update->edit
615
616 def edit_network(self, network_id, network):
617 """
618 Update entwork data byt id
619 :return:
620 """
621 # Look for the previous data
622 where_ = {'uuid': network_id}
623 result, network_old = self.db.get_table(FROM='nets', WHERE=where_)
624 if result < 0:
625 raise ovimException("Error updating network %s" % network_old, HTTP_Internal_Server_Error)
626 elif result == 0:
627 raise ovimException('network %s not found' % network_id, HTTP_Not_Found)
628 # get ports
629 nbports, content = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
630 WHERE={'net_id': network_id}, LIMIT=100)
631 if result < 0:
632 raise ovimException("http_put_network_id error %d %s" % (result, network_old), HTTP_Internal_Server_Error)
633 if nbports > 0:
634 if 'type' in network and network['type'] != network_old[0]['type']:
635 raise ovimException("Can not change type of network while having ports attached",
636 HTTP_Method_Not_Allowed)
637 if 'vlan' in network and network['vlan'] != network_old[0]['vlan']:
638 raise ovimException("Can not change vlan of network while having ports attached",
639 HTTP_Method_Not_Allowed)
640
641 # check valid params
642 net_provider = network.get('provider', network_old[0]['provider'])
643 net_type = network.get('type', network_old[0]['type'])
644 net_bind_net = network.get("bind_net")
645 net_bind_type = network.get("bind_type")
646 if net_bind_net:
647 # look for a valid net
648 if self._check_valid_uuid(net_bind_net):
649 net_bind_key = "uuid"
650 else:
651 net_bind_key = "name"
652 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
653 if result < 0:
654 raise ovimException('Getting nets from db ' + content, HTTP_Internal_Server_Error)
655 elif result == 0:
656 raise ovimException("bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
657 elif result > 1:
658 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net),
659 HTTP_Bad_Request)
660 network["bind_net"] = content[0]["uuid"]
661 if net_bind_type:
662 if net_bind_type[0:5] != "vlan:":
663 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
664 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
665 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
666 HTTP_Bad_Request)
667 if net_provider:
668 if net_provider[:9] == "openflow:":
669 if net_type != "ptp" and net_type != "data":
670 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request)
671 else:
672 if net_type != "bridge_man" and net_type != "bridge_data":
673 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
674 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
675
676 # insert in data base
677 result, content = self.db.update_rows('nets', network, WHERE={'uuid': network_id}, log=True)
678 if result >= 0:
679 # if result > 0 and nbports>0 and 'admin_state_up' in network
680 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
681 if result > 0:
682
683 try:
684 self.net_update_ofc_thread(network_id)
685 except ovimException as e:
686 raise ovimException("Error while launching openflow rules in network '{}' {}"
687 .format(network_id, str(e)), HTTP_Internal_Server_Error)
688 except Exception as e:
689 raise ovimException("Error while launching openflow rules in network '{}' {}"
690 .format(network_id, str(e)), HTTP_Internal_Server_Error)
691
692 if self.config.get("dhcp_server"):
693 if network_id in self.config["dhcp_nets"]:
694 self.config["dhcp_nets"].remove(network_id)
695 if network.get("name", network_old[0]["name"]) in self.config["dhcp_server"].get("nets", ()):
696 self.config["dhcp_nets"].append(network_id)
697 else:
698 net_bind = network.get("bind_type", network_old[0]["bind_type"])
699 if net_bind and net_bind and net_bind[:7] == "bridge:" and net_bind[7:] in self.config["dhcp_server"].get(
700 "bridge_ifaces", ()):
701 self.config["dhcp_nets"].append(network_id)
702 return network_id
703 else:
704 raise ovimException(content, -result)
705
706 def delete_network(self, network_id):
707 """
708 Delete network by network id
709 :param network_id: network id
710 :return:
711 """
712
713 # delete from the data base
714 result, content = self.db.delete_row('nets', network_id)
715
716 if result == 0:
717 raise ovimException("Network %s not found " % network_id, HTTP_Not_Found)
718 elif result > 0:
719 for brnet in self.config['bridge_nets']:
720 if brnet[3] == network_id:
721 brnet[3] = None
722 break
723 if self.config.get("dhcp_server") and network_id in self.config["dhcp_nets"]:
724 self.config["dhcp_nets"].remove(network_id)
725 return content
726 else:
727 raise ovimException("Error deleting network %s" % network_id, HTTP_Internal_Server_Error)
728
729 def get_openflow_rules(self, network_id=None):
730 """
731 Get openflow id from DB
732 :param network_id: Network id, if none all networks will be retrieved
733 :return: Return a list with Openflow rules per net
734 """
735 # ignore input data
736 if not network_id:
737 where_ = {}
738 else:
739 where_ = {"net_id": network_id}
740 result, content = self.db.get_table(
741 SELECT=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
742 WHERE=where_, FROM='of_flows')
743
744 if result < 0:
745 raise ovimException(str(content), -result)
746 return content
747
748 def edit_openflow_rules(self, network_id=None):
749
750 """
751 To make actions over the net. The action is to reinstall the openflow rules
752 network_id can be 'all'
753 :param network_id: Network id, if none all networks will be retrieved
754 :return : Number of nets updated
755 """
756
757 # ignore input data
758 if not network_id:
759 where_ = {}
760 else:
761 where_ = {"uuid": network_id}
762 result, content = self.db.get_table(SELECT=("uuid", "type"), WHERE=where_, FROM='nets')
763
764 if result < 0:
765 raise ovimException(str(content), -result)
766
767 for net in content:
768 if net["type"] != "ptp" and net["type"] != "data":
769 result -= 1
770 continue
771
772 try:
773 self.net_update_ofc_thread(net['uuid'])
774 except ovimException as e:
775 raise ovimException("Error updating network'{}' {}".format(net['uuid'], str(e)),
776 HTTP_Internal_Server_Error)
777 except Exception as e:
778 raise ovimException("Error updating network '{}' {}".format(net['uuid'], str(e)),
779 HTTP_Internal_Server_Error)
780
781 return result
782
783 def delete_openflow_rules(self, ofc_id=None):
784 """
785 To make actions over the net. The action is to delete ALL openflow rules
786 :return: return operation result
787 """
788
789 if not ofc_id:
790 if 'Default' in self.config['ofcs_thread']:
791 r, c = self.config['ofcs_thread']['Default'].insert_task("clear-all")
792 else:
793 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
794
795 elif ofc_id in self.config['ofcs_thread']:
796 r, c = self.config['ofcs_thread'][ofc_id].insert_task("clear-all")
797
798 # ignore input data
799 if r < 0:
800 raise ovimException(str(c), -r)
801 else:
802 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
803 return r
804
805 def get_openflow_ports(self, ofc_id=None):
806 """
807 Obtain switch ports names of openflow controller
808 :return: Return flow ports in DB
809 """
810 if not ofc_id:
811 if 'Default' in self.config['ofcs_thread']:
812 conn = self.config['ofcs_thread']['Default'].OF_connector
813 else:
814 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
815
816 if ofc_id in self.config['ofcs_thread']:
817 conn = self.config['ofcs_thread'][ofc_id].OF_connector
818 else:
819 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
820 return conn.pp2ofi
821
822 def get_ports(self, columns=None, filter={}, limit=None):
823 # result, content = my.db.get_ports(where_)
824 result, content = self.db.get_table(SELECT=columns, WHERE=filter, FROM='ports', LIMIT=limit)
825 if result < 0:
826 self.logger.error("http_get_ports Error %d %s", result, content)
827 raise ovimException(str(content), -result)
828 else:
829 convert_boolean(content, ('admin_state_up',))
830 return content
831
832 def new_port(self, port_data):
833 port_data['type'] = 'external'
834 if port_data.get('net_id'):
835 # check that new net has the correct type
836 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
837 if result < 0:
838 raise ovimException(str(new_net), -result)
839 # insert in data base
840 result, uuid = self.db.new_row('ports', port_data, True, True)
841 if result > 0:
842 if 'net_id' in port_data:
843 try:
844 self.net_update_ofc_thread(port_data['net_id'])
845 except ovimException as e:
846 raise ovimException("Cannot insert a task for updating network '{}' {}"
847 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
848 except Exception as e:
849 raise ovimException("Cannot insert a task for updating network '{}' {}"
850 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
851
852 return uuid
853 else:
854 raise ovimException(str(uuid), -result)
855
856 def new_external_port(self, port_data):
857 """
858 Create new external port and check port mapping correspondence
859 :param port_data: port_data = {
860 'region': 'datacenter region',
861 'compute_node': 'compute node id',
862 'pci': 'pci port address',
863 'vlan': 'net vlan',
864 'net_id': 'net id',
865 'tenant_id': 'tenant id',
866 'mac': 'switch mac',
867 'name': 'port name'
868 'ip_address': 'ip address - optional'}
869 :return:
870 """
871
872 port_data['type'] = 'external'
873
874 if port_data.get('net_id'):
875 # check that new net has the correct type
876 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
877 if result < 0:
878 raise ovimException(str(new_net), -result)
879 # insert in data base
880 db_filter = {}
881
882 if port_data.get('region'):
883 db_filter['region'] = port_data['region']
884 if port_data.get('pci'):
885 db_filter['pci'] = port_data['pci']
886 if port_data.get('compute_node'):
887 db_filter['compute_node'] = port_data['compute_node']
888
889 columns = ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
890 port_mapping_data = self.get_of_port_mappings(columns, db_filter)
891
892 if not len(port_mapping_data):
893 raise ovimException("No port mapping founded for '{}'".format(str(db_filter)),
894 HTTP_Not_Found)
895 elif len(port_mapping_data) > 1:
896 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
897 HTTP_Conflict)
898
899 port_data['ofc_id'] = port_mapping_data[0]['ofc_id']
900 port_data['switch_dpid'] = port_mapping_data[0]['switch_dpid']
901 port_data['switch_port'] = port_mapping_data[0]['switch_port']
902 port_data['switch_mac'] = port_mapping_data[0]['switch_mac']
903
904 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
905 if 'region' in port_data:
906 del port_data['region']
907 if 'pci' in port_data:
908 del port_data['pci']
909 if 'compute_node' in port_data:
910 del port_data['compute_node']
911
912 result, uuid = self.db.new_row('ports', port_data, True, True)
913 if result > 0:
914 try:
915 self.net_update_ofc_thread(port_data['net_id'], port_data['ofc_id'])
916 except ovimException as e:
917 raise ovimException("Cannot insert a task for updating network '{}' {}".
918 format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
919 except Exception as e:
920 raise ovimException("Cannot insert a task for updating network '{}' {}"
921 .format(port_data['net_id'], e), HTTP_Internal_Server_Error)
922 return uuid
923 else:
924 raise ovimException(str(uuid), -result)
925
926 def net_update_ofc_thread(self, net_id, ofc_id=None):
927 """
928 Insert a update net task by net id or ofc_id for each ofc thread
929 :param net_id: network id
930 :param ofc_id: openflow controller id
931 :return:
932 """
933 if not net_id:
934 raise ovimException("No net_id received", HTTP_Internal_Server_Error)
935
936 switch_dpid = None
937 r = -1
938 c = 'No valid ofc_id or switch_dpid received'
939
940 if not ofc_id:
941 ports = self.get_ports(filter={"net_id": net_id})
942 for port in ports:
943 port_ofc_id = port.get('ofc_id', None)
944 if port_ofc_id:
945 ofc_id = port['ofc_id']
946 switch_dpid = port['switch_dpid']
947 break
948
949 # If no ofc_id found it, default ofc_id is used.
950 if not ofc_id and not switch_dpid:
951 ofc_id = "Default"
952
953 if ofc_id and ofc_id in self.config['ofcs_thread']:
954 r, c = self.config['ofcs_thread'][ofc_id].insert_task("update-net", net_id)
955 elif switch_dpid:
956
957 ofcs_dpid_list = self.config['ofcs_thread_dpid']
958 for ofc_t in ofcs_dpid_list:
959 if switch_dpid in ofc_t:
960 r, c = ofc_t[switch_dpid].insert_task("update-net", net_id)
961
962 if r < 0:
963 message = "Cannot insert a task for updating network '{}', {}".format(net_id, c)
964 self.logger.error(message)
965 raise ovimException(message, HTTP_Internal_Server_Error)
966
967 def delete_port(self, port_id):
968 # Look for the previous port data
969 result, ports = self.db.get_table(WHERE={'uuid': port_id, "type": "external"}, FROM='ports')
970 if result < 0:
971 raise ovimException("Cannot get port info from database: {}".format(ports), http_code=-result)
972 # delete from the data base
973 result, content = self.db.delete_row('ports', port_id)
974 if result == 0:
975 raise ovimException("External port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
976 elif result < 0:
977 raise ovimException("Cannot delete port from database: {}".format(content), http_code=-result)
978 # update network
979 network = ports[0].get('net_id', None)
980 if network:
981 # change of net.
982
983 try:
984 self.net_update_ofc_thread(network)
985 except ovimException as e:
986 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
987 HTTP_Internal_Server_Error)
988 except Exception as e:
989 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
990 HTTP_Internal_Server_Error)
991
992 return content
993
994 def edit_port(self, port_id, port_data, admin=True):
995 # Look for the previous port data
996 result, content = self.db.get_table(FROM="ports", WHERE={'uuid': port_id})
997 if result < 0:
998 raise ovimException("Cannot get port info from database: {}".format(content), http_code=-result)
999 elif result == 0:
1000 raise ovimException("Port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1001 port = content[0]
1002 nets = []
1003 host_id = None
1004 result = 1
1005 if 'net_id' in port_data:
1006 # change of net.
1007 old_net = port.get('net_id', None)
1008 new_net = port_data['net_id']
1009 if old_net != new_net:
1010
1011 if new_net:
1012 nets.append(new_net) # put first the new net, so that new openflow rules are created before removing the old ones
1013 if old_net:
1014 nets.append(old_net)
1015 if port['type'] == 'instance:bridge' or port['type'] == 'instance:ovs':
1016 raise ovimException("bridge interfaces cannot be attached to a different net", http_code=HTTP_Forbidden)
1017 elif port['type'] == 'external' and not admin:
1018 raise ovimException("Needed admin privileges",http_code=HTTP_Unauthorized)
1019 if new_net:
1020 # check that new net has the correct type
1021 result, new_net_dict = self.db.check_target_net(new_net, None, port['type'])
1022 if result < 0:
1023 raise ovimException("Error {}".format(new_net_dict), http_code=HTTP_Conflict)
1024 # change VLAN for SR-IOV ports
1025 if result >= 0 and port["type"] == "instance:data" and port["model"] == "VF": # TODO consider also VFnotShared
1026 if new_net:
1027 port_data["vlan"] = None
1028 else:
1029 port_data["vlan"] = new_net_dict["vlan"]
1030 # get host where this VM is allocated
1031 result, content = self.db.get_table(FROM="instances", WHERE={"uuid": port["instance_id"]})
1032 if result > 0:
1033 host_id = content[0]["host_id"]
1034
1035 # insert in data base
1036 if result >= 0:
1037 result, content = self.db.update_rows('ports', port_data, WHERE={'uuid': port_id}, log=False)
1038
1039 # Insert task to complete actions
1040 if result > 0:
1041 for net_id in nets:
1042 try:
1043 self.net_update_ofc_thread(net_id)
1044 except ovimException as e:
1045 raise ovimException("Error updating network'{}' {}".format(net_id, str(e)),
1046 HTTP_Internal_Server_Error)
1047 except Exception as e:
1048 raise ovimException("Error updating network '{}' {}".format(net_id, str(e)),
1049 HTTP_Internal_Server_Error)
1050
1051 if host_id:
1052 r, v = self.config['host_threads'][host_id].insert_task("edit-iface", port_id, old_net, new_net)
1053 if r < 0:
1054 self.logger.error("Error updating network '{}' {}".format(r,v))
1055 # TODO Do something if fails
1056 if result >= 0:
1057 return port_id
1058 else:
1059 raise ovimException("Error {}".format(content), http_code=-result)
1060
1061 def new_of_controller(self, ofc_data):
1062 """
1063 Create a new openflow controller into DB
1064 :param ofc_data: Dict openflow controller data
1065 :return: openflow controller dpid
1066 """
1067
1068 result, ofc_uuid = self.db.new_row('ofcs', ofc_data, True, True)
1069 if result < 0:
1070 raise ovimException("New ofc Error %s" % ofc_uuid, HTTP_Internal_Server_Error)
1071
1072 ofc_data['uuid'] = ofc_uuid
1073 of_conn = self._load_of_module(ofc_data)
1074 self._create_ofc_task(ofc_uuid, ofc_data['dpid'], of_conn)
1075
1076 return ofc_uuid
1077
1078 def edit_of_controller(self, of_id, ofc_data):
1079 """
1080 Edit an openflow controller entry from DB
1081 :return:
1082 """
1083 if not ofc_data:
1084 raise ovimException("No data received during uptade OF contorller", http_code=HTTP_Internal_Server_Error)
1085
1086 old_of_controller = self.show_of_controller(of_id)
1087
1088 if old_of_controller:
1089 result, content = self.db.update_rows('ofcs', ofc_data, WHERE={'uuid': of_id}, log=False)
1090 if result >= 0:
1091 return ofc_data
1092 else:
1093 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1094 http_code=-result)
1095 else:
1096 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1097 http_code=HTTP_Internal_Server_Error)
1098
1099 def delete_of_controller(self, of_id):
1100 """
1101 Delete an openflow controller from DB.
1102 :param of_id: openflow controller dpid
1103 :return:
1104 """
1105
1106 ofc = self.show_of_controller(of_id)
1107
1108 result, content = self.db.delete_row("ofcs", of_id)
1109 if result < 0:
1110 raise ovimException("Cannot delete ofc from database: {}".format(content), http_code=-result)
1111 elif result == 0:
1112 raise ovimException("ofc {} not found ".format(content), http_code=HTTP_Not_Found)
1113
1114 ofc_thread = self.config['ofcs_thread'][of_id]
1115 del self.config['ofcs_thread'][of_id]
1116 for ofc_th in self.config['ofcs_thread_dpid']:
1117 if ofc['dpid'] in ofc_th:
1118 self.config['ofcs_thread_dpid'].remove(ofc_th)
1119
1120 ofc_thread.insert_task("exit")
1121 #ofc_thread.join()
1122
1123 return content
1124
1125 def show_of_controller(self, uuid):
1126 """
1127 Show an openflow controller by dpid from DB.
1128 :param db_filter: List with where query parameters
1129 :return:
1130 """
1131
1132 result, content = self.db.get_table(FROM='ofcs', WHERE={"uuid": uuid}, LIMIT=100)
1133
1134 if result == 0:
1135 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid),
1136 http_code=HTTP_Not_Found)
1137 elif result < 0:
1138 raise ovimException("Openflow controller with uuid '{}' error".format(uuid),
1139 http_code=HTTP_Internal_Server_Error)
1140 return content[0]
1141
1142 def get_of_controllers(self, columns=None, db_filter={}, limit=None):
1143 """
1144 Show an openflow controllers from DB.
1145 :param columns: List with SELECT query parameters
1146 :param db_filter: List with where query parameters
1147 :param limit: result Limit
1148 :return:
1149 """
1150 result, content = self.db.get_table(SELECT=columns, FROM='ofcs', WHERE=db_filter, LIMIT=limit)
1151
1152 if result < 0:
1153 raise ovimException(str(content), -result)
1154
1155 return content
1156
1157 def get_tenants(self, columns=None, db_filter={}, limit=None):
1158 """
1159 Retrieve tenant list from DB
1160 :param columns: List with SELECT query parameters
1161 :param db_filter: List with where query parameters
1162 :param limit: result limit
1163 :return:
1164 """
1165 result, content = self.db.get_table(FROM='tenants', SELECT=columns, WHERE=db_filter, LIMIT=limit)
1166 if result < 0:
1167 raise ovimException('get_tenatns Error {}'.format(str(content)), -result)
1168 else:
1169 convert_boolean(content, ('enabled',))
1170 return content
1171
1172 def show_tenant_id(self, tenant_id):
1173 """
1174 Get tenant from DB by id
1175 :param tenant_id: tenant id
1176 :return:
1177 """
1178 result, content = self.db.get_table(FROM='tenants', SELECT=('uuid', 'name', 'description', 'enabled'),
1179 WHERE={"uuid": tenant_id})
1180 if result < 0:
1181 raise ovimException(str(content), -result)
1182 elif result == 0:
1183 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1184 else:
1185 convert_boolean(content, ('enabled',))
1186 return content[0]
1187
1188 def new_tentant(self, tenant):
1189 """
1190 Create a tenant and store in DB
1191 :param tenant: Dictionary with tenant data
1192 :return: the uuid of created tenant. Raise exception upon error
1193 """
1194
1195 # insert in data base
1196 result, tenant_uuid = self.db.new_tenant(tenant)
1197
1198 if result >= 0:
1199 return tenant_uuid
1200 else:
1201 raise ovimException(str(tenant_uuid), -result)
1202
1203 def delete_tentant(self, tenant_id):
1204 """
1205 Delete a tenant from the database.
1206 :param tenant_id: Tenant id
1207 :return: delete tenant id
1208 """
1209
1210 # check permissions
1211 r, tenants_flavors = self.db.get_table(FROM='tenants_flavors', SELECT=('flavor_id', 'tenant_id'),
1212 WHERE={'tenant_id': tenant_id})
1213 if r <= 0:
1214 tenants_flavors = ()
1215 r, tenants_images = self.db.get_table(FROM='tenants_images', SELECT=('image_id', 'tenant_id'),
1216 WHERE={'tenant_id': tenant_id})
1217 if r <= 0:
1218 tenants_images = ()
1219
1220 result, content = self.db.delete_row('tenants', tenant_id)
1221 if result == 0:
1222 raise ovimException("tenant '%s' not found" % tenant_id, HTTP_Not_Found)
1223 elif result > 0:
1224 for flavor in tenants_flavors:
1225 self.db.delete_row_by_key("flavors", "uuid", flavor['flavor_id'])
1226 for image in tenants_images:
1227 self.db.delete_row_by_key("images", "uuid", image['image_id'])
1228 return content
1229 else:
1230 raise ovimException("Error deleting tenant '%s' " % tenant_id, HTTP_Internal_Server_Error)
1231
1232 def edit_tenant(self, tenant_id, tenant_data):
1233 """
1234 Update a tenant data identified by tenant id
1235 :param tenant_id: tenant id
1236 :param tenant_data: Dictionary with tenant data
1237 :return:
1238 """
1239
1240 # Look for the previous data
1241 result, tenant_data_old = self.db.get_table(FROM='tenants', WHERE={'uuid': tenant_id})
1242 if result < 0:
1243 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id, tenant_data_old),
1244 HTTP_Internal_Server_Error)
1245 elif result == 0:
1246 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1247
1248 # insert in data base
1249 result, content = self.db.update_rows('tenants', tenant_data, WHERE={'uuid': tenant_id}, log=True)
1250 if result >= 0:
1251 return content
1252 else:
1253 raise ovimException(str(content), -result)
1254
1255 def set_of_port_mapping(self, of_maps, ofc_id=None, switch_dpid=None, region=None):
1256 """
1257 Create new port mapping entry
1258 :param of_maps: List with port mapping information
1259 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1260 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1261 :param ofc_id: ofc id
1262 :param switch_dpid: switch dpid
1263 :param region: datacenter region id
1264 :return:
1265 """
1266
1267 for map in of_maps:
1268 if ofc_id:
1269 map['ofc_id'] = ofc_id
1270 if switch_dpid:
1271 map['switch_dpid'] = switch_dpid
1272 if region:
1273 map['region'] = region
1274
1275 for of_map in of_maps:
1276 result, uuid = self.db.new_row('of_port_mappings', of_map, True)
1277 if result > 0:
1278 of_map["uuid"] = uuid
1279 else:
1280 raise ovimException(str(uuid), -result)
1281 return of_maps
1282
1283 def clear_of_port_mapping(self, db_filter={}):
1284 """
1285 Clear port mapping filtering using db_filter dict
1286 :param db_filter: Parameter to filter during remove process
1287 :return:
1288 """
1289 result, content = self.db.delete_row_by_dict(FROM='of_port_mappings', WHERE=db_filter)
1290 # delete_row_by_key
1291 if result >= 0:
1292 return content
1293 else:
1294 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter)),
1295 HTTP_Internal_Server_Error)
1296
1297 def get_of_port_mappings(self, column=None, db_filter=None, db_limit=None):
1298 """
1299 Retrive port mapping from DB
1300 :param column:
1301 :param db_filter:
1302 :return:
1303 """
1304 result, content = self.db.get_table(SELECT=column, WHERE=db_filter, FROM='of_port_mappings', LIMIT=db_limit)
1305
1306 if result < 0:
1307 self.logger.error("get_of_port_mappings Error %d %s", result, content)
1308 raise ovimException(str(content), -result)
1309 else:
1310 return content
1311
1312 def get_dhcp_controller(self):
1313 """
1314 Create an host_thread object for manage openvim controller and not create a thread for itself
1315 :return: dhcp_host openvim controller object
1316 """
1317
1318 if 'openvim_controller' in self.config['host_threads']:
1319 return self.config['host_threads']['openvim_controller']
1320
1321 bridge_ifaces = []
1322 controller_ip = self.config['ovs_controller_ip']
1323 ovs_controller_user = self.config['ovs_controller_user']
1324
1325 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
1326 host_develop_mode = True if self.config['mode'] == 'development' else False
1327
1328 dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip,
1329 db=self.db_of,
1330 db_lock=self.db_lock, test=host_test_mode,
1331 image_path=self.config['image_path'], version=self.config['version'],
1332 host_id='openvim_controller', develop_mode=host_develop_mode,
1333 develop_bridge_iface=bridge_ifaces)
1334
1335 self.config['host_threads']['openvim_controller'] = dhcp_host
1336 if not host_test_mode:
1337 dhcp_host.ssh_connect()
1338 return dhcp_host
1339
1340 def launch_dhcp_server(self, vlan, first_ip, last_ip, cidr, gateway):
1341 """
1342 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1343 :param vlan: vlan identifier
1344 :param first_ip: First dhcp range ip
1345 :param last_ip: Last dhcp range ip
1346 :param cidr: net cidr
1347 :param gateway: net gateway
1348 :return:
1349 """
1350 ip_tools = IPNetwork(cidr)
1351 dhcp_netmask = str(ip_tools.netmask)
1352 ip_range = [first_ip, last_ip]
1353
1354 dhcp_path = self.config['ovs_controller_file_path']
1355
1356 controller_host = self.get_dhcp_controller()
1357 controller_host.create_linux_bridge(vlan)
1358 controller_host.create_dhcp_interfaces(vlan, first_ip, dhcp_netmask)
1359 controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path, gateway)
1360
1361