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