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