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