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