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