blob: 6317421d9d865d3872c0ae91b02a53bb1b429224 [file] [log] [blame]
mirabald87877c2017-03-31 15:15:52 +02001#!/usr/bin/env python
tierno57f7bda2017-02-09 12:01:55 +01002# -*- 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
tierno51068952017-04-26 15:09:48 +020025"""
tierno57f7bda2017-02-09 12:01:55 +010026This is the thread for the http server North API.
27Two thread will be launched, with normal and administrative permissions.
tierno51068952017-04-26 15:09:48 +020028"""
tierno57f7bda2017-02-09 12:01:55 +010029
30import threading
mirabal6878e3f2017-06-05 09:19:26 -050031import yaml
garciadeblas071df952017-04-21 11:12:50 +020032import vim_db
tierno57f7bda2017-02-09 12:01:55 +010033import logging
tierno29d80242017-04-25 18:07:08 +020034# import imp
tierno95a9e832017-04-27 18:49:37 +020035import os.path
mirabal9f657102017-04-10 20:05:40 +020036import argparse
mirabal65ba8f82017-02-15 12:36:33 +010037from netaddr import IPNetwork
38from jsonschema import validate as js_v, exceptions as js_e
garciadeblas071df952017-04-21 11:12:50 +020039import host_thread as ht
40import dhcp_thread as dt
41import openflow_thread as oft
42import openflow_conn
mirabal9f657102017-04-10 20:05:40 +020043
tierno51068952017-04-26 15:09:48 +020044__author__ = "Alfonso Tierno, Leonardo Mirabal"
45__date__ = "$06-Feb-2017 12:07:15$"
mirabal6878e3f2017-06-05 09:19:26 -050046__version__ = "0.5.18-r534"
mirabalcaeb2242017-05-31 10:52:22 -050047version_date = "Jun 2017"
mirabal6878e3f2017-06-05 09:19:26 -050048database_version = 21 #needed database schema version
tierno57f7bda2017-02-09 12:01:55 +010049
50HTTP_Bad_Request = 400
51HTTP_Unauthorized = 401
52HTTP_Not_Found = 404
53HTTP_Forbidden = 403
54HTTP_Method_Not_Allowed = 405
55HTTP_Not_Acceptable = 406
56HTTP_Request_Timeout = 408
57HTTP_Conflict = 409
58HTTP_Service_Unavailable = 503
59HTTP_Internal_Server_Error= 500
60
61
62def convert_boolean(data, items):
63 '''Check recursively the content of data, and if there is an key contained in items, convert value from string to boolean
64 It assumes that bandwidth is well formed
65 Attributes:
66 'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
67 'items': tuple of keys to convert
68 Return:
69 None
70 '''
71 if type(data) is dict:
72 for k in data.keys():
73 if type(data[k]) is dict or type(data[k]) is tuple or type(data[k]) is list:
74 convert_boolean(data[k], items)
75 if k in items:
76 if type(data[k]) is str:
77 if data[k] == "false":
78 data[k] = False
79 elif data[k] == "true":
80 data[k] = True
81 if type(data) is tuple or type(data) is list:
82 for k in data:
83 if type(k) is dict or type(k) is tuple or type(k) is list:
84 convert_boolean(k, items)
85
86
87
88class ovimException(Exception):
89 def __init__(self, message, http_code=HTTP_Bad_Request):
90 self.http_code = http_code
91 Exception.__init__(self, message)
92
93
94class ovim():
95 running_info = {} #TODO OVIM move the info of running threads from config_dic to this static variable
mirabal580435e2017-03-01 16:17:10 +010096 of_module = {}
97
tierno57f7bda2017-02-09 12:01:55 +010098 def __init__(self, configuration):
99 self.config = configuration
tierno46ca3a92017-04-05 19:49:24 +0200100 self.logger_name = configuration.get("logger_name", "openvim")
101 self.logger = logging.getLogger(self.logger_name)
tierno57f7bda2017-02-09 12:01:55 +0100102 self.db = None
tierno46ca3a92017-04-05 19:49:24 +0200103 self.db = self._create_database_connection()
mirabal580435e2017-03-01 16:17:10 +0100104 self.of_test_mode = False
tierno57f7bda2017-02-09 12:01:55 +0100105
106 def _create_database_connection(self):
107 db = vim_db.vim_db((self.config["network_vlan_range_start"], self.config["network_vlan_range_end"]),
tierno46ca3a92017-04-05 19:49:24 +0200108 self.logger_name + ".db", self.config.get('log_level_db'))
tierno57f7bda2017-02-09 12:01:55 +0100109 if db.connect(self.config['db_host'], self.config['db_user'], self.config['db_passwd'],
110 self.config['db_name']) == -1:
111 # self.logger.error("Cannot connect to database %s at %s@%s", self.config['db_name'], self.config['db_user'],
112 # self.config['db_host'])
113 raise ovimException("Cannot connect to database {} at {}@{}".format(self.config['db_name'],
114 self.config['db_user'],
115 self.config['db_host']) )
116 return db
117
mirabale9f6f1a2017-02-16 17:57:35 +0100118 @staticmethod
mirabal50a052f2017-03-27 18:08:07 +0200119 def get_version():
120 return __version__
121
122 @staticmethod
123 def get_version_date():
124 return version_date
125
126 @staticmethod
127 def get_database_version():
128 return database_version
129
130 @staticmethod
mirabale9f6f1a2017-02-16 17:57:35 +0100131 def _check_dhcp_data_integrity(network):
132 """
133 Check if all dhcp parameter for anet are valid, if not will be calculated from cidr value
134 :param network: list with user nets paramters
135 :return:
136 """
137 if "cidr" in network:
138 cidr = network["cidr"]
139 ip_tools = IPNetwork(cidr)
140 cidr_len = ip_tools.prefixlen
141 if cidr_len > 29:
142 return False
143
144 ips = IPNetwork(cidr)
145 if "dhcp_first_ip" not in network:
mirabal72fcda72017-05-09 11:01:06 +0200146 network["dhcp_first_ip"] = str(ips[3])
mirabale9f6f1a2017-02-16 17:57:35 +0100147 if "dhcp_last_ip" not in network:
148 network["dhcp_last_ip"] = str(ips[-2])
149 if "gateway_ip" not in network:
mirabal6878e3f2017-06-05 09:19:26 -0500150 network["gateway_ip"] = str(ips[1])
mirabale9f6f1a2017-02-16 17:57:35 +0100151
152 return True
153 else:
154 return False
155
156 @staticmethod
157 def _check_valid_uuid(uuid):
158 id_schema = {"type": "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
159 try:
160 js_v(uuid, id_schema)
161 return True
162 except js_e.ValidationError:
163 return False
tierno57f7bda2017-02-09 12:01:55 +0100164
165 def start_service(self):
mirabal580435e2017-03-01 16:17:10 +0100166 """
167 Start ovim services
168 :return:
169 """
tierno2db743b2017-03-28 17:23:15 +0200170 global database_version
mirabal580435e2017-03-01 16:17:10 +0100171 # if self.running_info:
tierno57f7bda2017-02-09 12:01:55 +0100172 # return #TODO service can be checked and rebuild broken threads
173 r = self.db.get_db_version()
tierno95a9e832017-04-27 18:49:37 +0200174 db_path = __file__
175 db_path = db_path[:db_path.rfind("/")]
176 if os.path.exists(db_path + "/database_utils/migrate_vim_db.sh"):
177 db_path += "/database_utils"
178 else:
179 db_path += "/../database_utils"
180
mirabal580435e2017-03-01 16:17:10 +0100181 if r[0] < 0:
tierno95a9e832017-04-27 18:49:37 +0200182 raise ovimException("DATABASE is not valid. If you think it is corrupted, you can init it with"
183 " '{db_path}/init_vim_db.sh' script".format(db_path=db_path))
184 elif r[0] != database_version:
185 raise ovimException("DATABASE wrong version '{current}'. Try to upgrade/downgrade to version '{target}'"
186 " with '{db_path}/migrate_vim_db.sh {target}'".format(
187 current=r[0], target=database_version, db_path=db_path))
tierno46ca3a92017-04-05 19:49:24 +0200188 self.logger.critical("Starting ovim server version: '{} {}' database version '{}'".format(
189 self.get_version(), self.get_version_date(), self.get_database_version()))
tierno57f7bda2017-02-09 12:01:55 +0100190 # create database connection for openflow threads
tiernoe0c28c12017-05-04 18:44:40 +0200191 self.config["db"] = self._create_database_connection()
192 self.config["db_lock"] = threading.Lock()
tierno57f7bda2017-02-09 12:01:55 +0100193
mirabal580435e2017-03-01 16:17:10 +0100194 self.of_test_mode = False if self.config['mode'] == 'normal' or self.config['mode'] == "OF only" else True
mirabal42ca0092017-06-14 05:42:30 -0500195
196 # Create one thread for each host
197 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
198 host_develop_mode = True if self.config['mode'] == 'development' else False
199 host_develop_bridge_iface = self.config.get('development_bridge', None)
200
201 # get host list from data base before starting threads
202 r, hosts = self.db.get_table(SELECT=('name', 'ip_name', 'user', 'uuid', 'password', 'keyfile'),
203 FROM='hosts', WHERE={'status': 'ok'})
204 if r < 0:
205 raise ovimException("Cannot get hosts from database {}".format(hosts))
206
207 self.config['host_threads'] = {}
208
209 for host in hosts:
210 thread = ht.host_thread(name=host['name'], user=host['user'], host=host['ip_name'], db=self.config["db"],
211 password=host['password'],
212 keyfile=host.get('keyfile', self.config["host_ssh_keyfile"]),
213 db_lock=self.config["db_lock"], test=host_test_mode,
214 image_path=self.config['host_image_path'],
215 version=self.config['version'], host_id=host['uuid'],
216 develop_mode=host_develop_mode,
217 develop_bridge_iface=host_develop_bridge_iface,
218 logger_name=self.logger_name + ".host." + host['name'],
219 debug=self.config.get('log_level_host'))
220
221 try:
222 thread.check_connectivity()
223 except Exception as e:
224 self.logger.critical('Error detected for compute = {} with ip = {}'
225 .format(host['name'], host['ip_name']))
mirabald48f4f92017-06-29 10:04:21 -0500226 thread.start()
mirabal42ca0092017-06-14 05:42:30 -0500227 self.config['host_threads'][host['uuid']] = thread
228
mirabal580435e2017-03-01 16:17:10 +0100229 # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge,
230 # speed in Gbit/s
231
tierno57f7bda2017-02-09 12:01:55 +0100232 self.config['dhcp_nets'] = []
233 self.config['bridge_nets'] = []
234 for bridge, vlan_speed in self.config["bridge_ifaces"].items():
mirabal580435e2017-03-01 16:17:10 +0100235 # skip 'development_bridge'
tierno57f7bda2017-02-09 12:01:55 +0100236 if self.config['mode'] == 'development' and self.config['development_bridge'] == bridge:
237 continue
238 self.config['bridge_nets'].append([bridge, vlan_speed[0], vlan_speed[1], None])
239
240 # check if this bridge is already used (present at database) for a network)
241 used_bridge_nets = []
242 for brnet in self.config['bridge_nets']:
tierno686b3952017-03-10 13:57:24 +0100243 r, nets = self.db.get_table(SELECT=('uuid',), FROM='nets', WHERE={'provider': "bridge:" + brnet[0]})
tierno57f7bda2017-02-09 12:01:55 +0100244 if r > 0:
245 brnet[3] = nets[0]['uuid']
246 used_bridge_nets.append(brnet[0])
247 if self.config.get("dhcp_server"):
248 if brnet[0] in self.config["dhcp_server"]["bridge_ifaces"]:
249 self.config['dhcp_nets'].append(nets[0]['uuid'])
250 if len(used_bridge_nets) > 0:
251 self.logger.info("found used bridge nets: " + ",".join(used_bridge_nets))
252 # get nets used by dhcp
253 if self.config.get("dhcp_server"):
254 for net in self.config["dhcp_server"].get("nets", ()):
tierno686b3952017-03-10 13:57:24 +0100255 r, nets = self.db.get_table(SELECT=('uuid',), FROM='nets', WHERE={'name': net})
tierno57f7bda2017-02-09 12:01:55 +0100256 if r > 0:
257 self.config['dhcp_nets'].append(nets[0]['uuid'])
258
mirabal580435e2017-03-01 16:17:10 +0100259 # OFC default
260 self._start_ofc_default_task()
tierno57f7bda2017-02-09 12:01:55 +0100261
mirabal580435e2017-03-01 16:17:10 +0100262 # OFC per tenant in DB
263 self._start_of_db_tasks()
tierno57f7bda2017-02-09 12:01:55 +0100264
265 # create dhcp_server thread
266 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
267 dhcp_params = self.config.get("dhcp_server")
268 if dhcp_params:
269 thread = dt.dhcp_thread(dhcp_params=dhcp_params, test=host_test_mode, dhcp_nets=self.config["dhcp_nets"],
tiernoe0c28c12017-05-04 18:44:40 +0200270 db=self.config["db"], db_lock=self.config["db_lock"],
271 logger_name=self.logger_name + ".dhcp",
tierno43044b02017-04-06 18:58:24 +0200272 debug=self.config.get('log_level_of'))
tierno57f7bda2017-02-09 12:01:55 +0100273 thread.start()
274 self.config['dhcp_thread'] = thread
275
mirabal580435e2017-03-01 16:17:10 +0100276
tierno57f7bda2017-02-09 12:01:55 +0100277
mirabalb716ac52017-02-10 14:47:53 +0100278 # create ovs dhcp thread
279 result, content = self.db.get_table(FROM='nets')
280 if result < 0:
281 self.logger.error("http_get_ports Error %d %s", result, content)
282 raise ovimException(str(content), -result)
283
284 for net in content:
285 net_type = net['type']
tiernoa6933042017-05-24 16:54:33 +0200286 if (net_type == 'bridge_data' or net_type == 'bridge_man') and \
287 net["provider"][:4] == 'OVS:' and net["enable_dhcp"] == "true":
288 try:
mirabale16a6362017-07-10 05:45:56 -0500289 config_routes = net.get('routes')
290 if config_routes:
291 routes = yaml.safe_load(config_routes)
292 else:
293 routes = None
294
295 config_dns = net.get('dns')
296 if config_dns:
297 dns = yaml.safe_load(config_dns)
298 else:
299 dns = None
300
301 links = net.get('links')
302 if links:
303 links = yaml.safe_load(net.get('links'))
mirabal6878e3f2017-06-05 09:19:26 -0500304 self.launch_dhcp_server(net.get('vlan'),
305 net.get('dhcp_first_ip'),
306 net.get('dhcp_last_ip'),
307 net.get('cidr'),
308 net.get('gateway_ip'),
309 dns,
310 routes)
mirabale16a6362017-07-10 05:45:56 -0500311 self.launch_link_bridge_to_ovs(net['vlan'], net.get('gateway_ip'), net.get('cidr'), links, routes)
tiernoa6933042017-05-24 16:54:33 +0200312 except Exception as e:
313 self.logger.error("Fail at launching dhcp server for net_id='%s' net_name='%s': %s",
314 net["uuid"], net["name"], str(e))
315 self.db.update_rows("nets", {"status": "ERROR",
316 "last_error": "Fail at launching dhcp server: " + str(e)},
317 {"uuid": net["uuid"]})
mirabalb716ac52017-02-10 14:47:53 +0100318
mirabal580435e2017-03-01 16:17:10 +0100319 def _start_of_db_tasks(self):
320 """
321 Start ofc task for existing ofcs in database
322 :param db_of:
323 :param db_lock:
324 :return:
325 """
326 ofcs = self.get_of_controllers()
327
328 for ofc in ofcs:
329 of_conn = self._load_of_module(ofc)
330 # create ofc thread per of controller
331 self._create_ofc_task(ofc['uuid'], ofc['dpid'], of_conn)
332
333 def _create_ofc_task(self, ofc_uuid, dpid, of_conn):
334 """
335 Create an ofc thread for handle each sdn controllers
336 :param ofc_uuid: sdn controller uuid
337 :param dpid: sdn controller dpid
338 :param of_conn: OF_conn module
339 :return:
340 """
341 if 'ofcs_thread' not in self.config and 'ofcs_thread_dpid' not in self.config:
342 ofcs_threads = {}
343 ofcs_thread_dpid = []
344 else:
345 ofcs_threads = self.config['ofcs_thread']
346 ofcs_thread_dpid = self.config['ofcs_thread_dpid']
347
348 if ofc_uuid not in ofcs_threads:
349 ofc_thread = self._create_ofc_thread(of_conn, ofc_uuid)
350 if ofc_uuid == "Default":
351 self.config['of_thread'] = ofc_thread
352
353 ofcs_threads[ofc_uuid] = ofc_thread
354 self.config['ofcs_thread'] = ofcs_threads
355
356 ofcs_thread_dpid.append({dpid: ofc_thread})
357 self.config['ofcs_thread_dpid'] = ofcs_thread_dpid
358
359 def _start_ofc_default_task(self):
360 """
361 Create default ofc thread
362 """
363 if 'of_controller' not in self.config \
364 and 'of_controller_ip' not in self.config \
365 and 'of_controller_port' not in self.config \
366 and 'of_controller_dpid' not in self.config:
367 return
368
369 # OF THREAD
370 db_config = {}
371 db_config['ip'] = self.config.get('of_controller_ip')
372 db_config['port'] = self.config.get('of_controller_port')
373 db_config['dpid'] = self.config.get('of_controller_dpid')
374 db_config['type'] = self.config.get('of_controller')
375 db_config['user'] = self.config.get('of_user')
376 db_config['password'] = self.config.get('of_password')
377
378 # create connector to the openflow controller
379 # load other parameters starting by of_ from config dict in a temporal dict
380
381 of_conn = self._load_of_module(db_config)
382 # create openflow thread
383 self._create_ofc_task("Default", db_config['dpid'], of_conn)
384
385 def _load_of_module(self, db_config):
386 """
387 import python module for each SDN controller supported
mirabalf9a1a8d2017-03-15 12:42:27 +0100388 :param db_config: SDN dn information
mirabal580435e2017-03-01 16:17:10 +0100389 :return: Module
390 """
391 if not db_config:
392 raise ovimException("No module found it", HTTP_Internal_Server_Error)
393
394 module_info = None
395
396 try:
397 if self.of_test_mode:
mirabal6c600652017-03-16 17:22:57 +0100398 return openflow_conn.OfTestConnector({"name": db_config['type'],
399 "dpid": db_config['dpid'],
400 "of_debug": self.config['log_level_of']})
mirabal580435e2017-03-01 16:17:10 +0100401 temp_dict = {}
402
403 if db_config:
404 temp_dict['of_ip'] = db_config['ip']
405 temp_dict['of_port'] = db_config['port']
406 temp_dict['of_dpid'] = db_config['dpid']
407 temp_dict['of_controller'] = db_config['type']
montesmorenoba1862b2017-04-06 10:07:44 +0000408 temp_dict['of_user'] = db_config.get('user')
409 temp_dict['of_password'] = db_config.get('password')
mirabal580435e2017-03-01 16:17:10 +0100410
411 temp_dict['of_debug'] = self.config['log_level_of']
412
413 if temp_dict['of_controller'] == 'opendaylight':
414 module = "ODL"
415 else:
416 module = temp_dict['of_controller']
417
418 if module not in ovim.of_module:
garciadeblas7fa5a652017-04-26 17:55:43 +0200419 try:
420 pkg = __import__("osm_openvim." + module)
421 of_conn_module = getattr(pkg, module)
422 ovim.of_module[module] = of_conn_module
423 self.logger.debug("Module load from {}".format("osm_openvim." + module))
424 except Exception as e:
tierno29d80242017-04-25 18:07:08 +0200425 self.logger.error("Cannot open openflow controller module of type '%s'", module)
426 raise ovimException("Cannot open openflow controller of type module '{}'"
427 "Revise it is installed".format(module),
428 HTTP_Internal_Server_Error)
mirabal580435e2017-03-01 16:17:10 +0100429 else:
430 of_conn_module = ovim.of_module[module]
tierno29d80242017-04-25 18:07:08 +0200431 return of_conn_module.OF_conn(temp_dict)
432 except Exception as e:
433 self.logger.error("Cannot open the Openflow controller '%s': %s", type(e).__name__, str(e))
434 raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e).__name__, str(e)),
mirabal580435e2017-03-01 16:17:10 +0100435 HTTP_Internal_Server_Error)
436
437 def _create_ofc_thread(self, of_conn, ofc_uuid="Default"):
438 """
439 Create and launch a of thread
440 :return: thread obj
441 """
442 # create openflow thread
443
montesmoreno92827552017-03-30 13:24:17 +0200444 #if 'of_controller_nets_with_same_vlan' in self.config:
445 # ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
446 #else:
447 # ofc_net_same_vlan = False
448 ofc_net_same_vlan = False
mirabal580435e2017-03-01 16:17:10 +0100449
tiernoe0c28c12017-05-04 18:44:40 +0200450 thread = oft.openflow_thread(ofc_uuid, of_conn, of_test=self.of_test_mode, db=self.config["db"],
451 db_lock=self.config["db_lock"],
452 pmp_with_same_vlan=ofc_net_same_vlan,
453 logger_name=self.logger_name + ".ofc." + ofc_uuid,
454 debug=self.config.get('log_level_of'))
mirabal580435e2017-03-01 16:17:10 +0100455 #r, c = thread.OF_connector.obtain_port_correspondence()
456 #if r < 0:
457 # raise ovimException("Cannot get openflow information %s", c)
458 thread.start()
459 return thread
460
tierno57f7bda2017-02-09 12:01:55 +0100461 def stop_service(self):
462 threads = self.config.get('host_threads', {})
463 if 'of_thread' in self.config:
464 threads['of'] = (self.config['of_thread'])
mirabal580435e2017-03-01 16:17:10 +0100465 if 'ofcs_thread' in self.config:
466 ofcs_thread = self.config['ofcs_thread']
467 for ofc in ofcs_thread:
468 threads[ofc] = ofcs_thread[ofc]
469
tierno57f7bda2017-02-09 12:01:55 +0100470 if 'dhcp_thread' in self.config:
471 threads['dhcp'] = (self.config['dhcp_thread'])
472
tiernoa6933042017-05-24 16:54:33 +0200473 for thread_id, thread in threads.items():
474 if thread_id == 'openvim_controller':
475 continue
tierno57f7bda2017-02-09 12:01:55 +0100476 thread.insert_task("exit")
tiernoa6933042017-05-24 16:54:33 +0200477 for thread_id, thread in threads.items():
478 if thread_id == 'openvim_controller':
479 continue
tierno57f7bda2017-02-09 12:01:55 +0100480 thread.join()
tierno57f7bda2017-02-09 12:01:55 +0100481
mirabal9e194592017-02-17 11:03:25 +0100482 def get_networks(self, columns=None, db_filter={}, limit=None):
mirabal65ba8f82017-02-15 12:36:33 +0100483 """
484 Retreive networks available
mirabale9f6f1a2017-02-16 17:57:35 +0100485 :param columns: List with select query parameters
mirabal9e194592017-02-17 11:03:25 +0100486 :param db_filter: List with where query parameters
mirabale9f6f1a2017-02-16 17:57:35 +0100487 :param limit: Query limit result
mirabal65ba8f82017-02-15 12:36:33 +0100488 :return:
489 """
mirabal9e194592017-02-17 11:03:25 +0100490 result, content = self.db.get_table(SELECT=columns, FROM='nets', WHERE=db_filter, LIMIT=limit)
mirabal65ba8f82017-02-15 12:36:33 +0100491
492 if result < 0:
493 raise ovimException(str(content), -result)
494
495 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
496
497 return content
498
mirabal9e194592017-02-17 11:03:25 +0100499 def show_network(self, network_id, db_filter={}):
mirabal65ba8f82017-02-15 12:36:33 +0100500 """
mirabale9f6f1a2017-02-16 17:57:35 +0100501 Get network from DB by id
502 :param network_id: net Id
mirabal9e194592017-02-17 11:03:25 +0100503 :param db_filter: List with where query parameters
mirabal65ba8f82017-02-15 12:36:33 +0100504 :return:
505 """
506 # obtain data
mirabale9f6f1a2017-02-16 17:57:35 +0100507 if not network_id:
508 raise ovimException("Not network id was not found")
mirabal9e194592017-02-17 11:03:25 +0100509 db_filter['uuid'] = network_id
mirabal65ba8f82017-02-15 12:36:33 +0100510
mirabal9e194592017-02-17 11:03:25 +0100511 result, content = self.db.get_table(FROM='nets', WHERE=db_filter, LIMIT=100)
mirabal65ba8f82017-02-15 12:36:33 +0100512
513 if result < 0:
514 raise ovimException(str(content), -result)
515 elif result == 0:
mirabale9f6f1a2017-02-16 17:57:35 +0100516 raise ovimException("show_network network '%s' not found" % network_id, -result)
mirabal65ba8f82017-02-15 12:36:33 +0100517 else:
518 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
mirabale9f6f1a2017-02-16 17:57:35 +0100519 # get ports from DB
mirabal65ba8f82017-02-15 12:36:33 +0100520 result, ports = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
mirabale9f6f1a2017-02-16 17:57:35 +0100521 WHERE={'net_id': network_id}, LIMIT=100)
mirabal65ba8f82017-02-15 12:36:33 +0100522 if len(ports) > 0:
523 content[0]['ports'] = ports
mirabal65ba8f82017-02-15 12:36:33 +0100524
mirabale9f6f1a2017-02-16 17:57:35 +0100525 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
526 return content[0]
527
528 def new_network(self, network):
mirabal65ba8f82017-02-15 12:36:33 +0100529 """
mirabale9f6f1a2017-02-16 17:57:35 +0100530 Create a net in DB
mirabal65ba8f82017-02-15 12:36:33 +0100531 :return:
532 """
533 tenant_id = network.get('tenant_id')
534
535 if tenant_id:
536 result, _ = self.db.get_table(FROM='tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id, "enabled": True})
537 if result <= 0:
538 raise ovimException("set_network error, no tenant founded", -result)
539
540 bridge_net = None
541 # check valid params
542 net_provider = network.get('provider')
543 net_type = network.get('type')
mirabal65ba8f82017-02-15 12:36:33 +0100544 net_vlan = network.get("vlan")
545 net_bind_net = network.get("bind_net")
546 net_bind_type = network.get("bind_type")
tiernoa290d8f2017-05-03 17:42:52 +0200547 net_region = network.get("region")
mirabal65ba8f82017-02-15 12:36:33 +0100548 name = network["name"]
549
550 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
551 vlan_index = name.rfind(":")
552 if not net_bind_net and not net_bind_type and vlan_index > 1:
553 try:
554 vlan_tag = int(name[vlan_index + 1:])
555 if not vlan_tag and vlan_tag < 4096:
556 net_bind_net = name[:vlan_index]
557 net_bind_type = "vlan:" + name[vlan_index + 1:]
558 except:
559 pass
560
561 if net_bind_net:
562 # look for a valid net
563 if self._check_valid_uuid(net_bind_net):
564 net_bind_key = "uuid"
565 else:
566 net_bind_key = "name"
567 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
568 if result < 0:
569 raise ovimException(' getting nets from db ' + content, HTTP_Internal_Server_Error)
570 elif result == 0:
571 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
572 elif result > 1:
573 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
574 network["bind_net"] = content[0]["uuid"]
575
576 if net_bind_type:
577 if net_bind_type[0:5] != "vlan:":
578 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
579 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
580 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
581 HTTP_Bad_Request)
582 network["bind_type"] = net_bind_type
583
584 if net_provider:
585 if net_provider[:9] == "openflow:":
586 if net_type:
587 if net_type != "ptp" and net_type != "data":
588 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
589 HTTP_Bad_Request)
590 else:
591 net_type = 'data'
592 else:
593 if net_type:
594 if net_type != "bridge_man" and net_type != "bridge_data":
595 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
596 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
597 else:
598 net_type = 'bridge_man'
599
600 if not net_type:
601 net_type = 'bridge_man'
602
603 if net_provider:
604 if net_provider[:7] == 'bridge:':
605 # check it is one of the pre-provisioned bridges
606 bridge_net_name = net_provider[7:]
607 for brnet in self.config['bridge_nets']:
608 if brnet[0] == bridge_net_name: # free
tierno11c45e72017-05-17 12:04:05 +0000609 if brnet[3]:
mirabal65ba8f82017-02-15 12:36:33 +0100610 raise ovimException("invalid 'provider:physical', "
611 "bridge '%s' is already used" % bridge_net_name, HTTP_Conflict)
612 bridge_net = brnet
613 net_vlan = brnet[1]
614 break
mirabale9f6f1a2017-02-16 17:57:35 +0100615 # if bridge_net==None:
616 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
617 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
618 # return
619
mirabal65ba8f82017-02-15 12:36:33 +0100620 elif self.config['network_type'] == 'bridge' and (net_type == 'bridge_data' or net_type == 'bridge_man'):
621 # look for a free precreated nets
622 for brnet in self.config['bridge_nets']:
623 if not brnet[3]: # free
624 if not bridge_net:
625 if net_type == 'bridge_man': # look for the smaller speed
626 if brnet[2] < bridge_net[2]:
627 bridge_net = brnet
628 else: # look for the larger speed
629 if brnet[2] > bridge_net[2]:
630 bridge_net = brnet
631 else:
632 bridge_net = brnet
633 net_vlan = brnet[1]
634 if not bridge_net:
635 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
636 "will overcome this limit", HTTP_Bad_Request)
637 else:
mirabale9f6f1a2017-02-16 17:57:35 +0100638 self.logger.debug("using net " + bridge_net)
mirabal65ba8f82017-02-15 12:36:33 +0100639 net_provider = "bridge:" + bridge_net[0]
640 net_vlan = bridge_net[1]
641 elif net_type == 'bridge_data' or net_type == 'bridge_man' and self.config['network_type'] == 'ovs':
642 net_provider = 'OVS'
tiernoa290d8f2017-05-03 17:42:52 +0200643 if not net_region:
644 if net_type == "data" or net_type == "ptp":
645 net_region = "__DATA__"
646 elif net_provider == "OVS":
647 net_region = "__OVS__"
mirabal65ba8f82017-02-15 12:36:33 +0100648 if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
tiernoa290d8f2017-05-03 17:42:52 +0200649 net_vlan = self.db.get_free_net_vlan(net_region)
mirabal65ba8f82017-02-15 12:36:33 +0100650 if net_vlan < 0:
651 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error)
652 if net_provider == 'OVS':
653 net_provider = 'OVS' + ":" + str(net_vlan)
654
655 network['provider'] = net_provider
656 network['type'] = net_type
657 network['vlan'] = net_vlan
tiernoa290d8f2017-05-03 17:42:52 +0200658 network['region'] = net_region
mirabal65ba8f82017-02-15 12:36:33 +0100659 dhcp_integrity = True
660 if 'enable_dhcp' in network and network['enable_dhcp']:
661 dhcp_integrity = self._check_dhcp_data_integrity(network)
mirabal6878e3f2017-06-05 09:19:26 -0500662
663 if network.get('links'):
664 network['links'] = yaml.safe_dump(network['links'], default_flow_style=True, width=256)
665 if network.get('dns'):
666 network['dns'] = yaml.safe_dump(network['dns'], default_flow_style=True, width=256)
667 if network.get('routes'):
668 network['routes'] = yaml.safe_dump(network['routes'], default_flow_style=True, width=256)
mirabal65ba8f82017-02-15 12:36:33 +0100669
670 result, content = self.db.new_row('nets', network, True, True)
671
672 if result >= 0 and dhcp_integrity:
673 if bridge_net:
674 bridge_net[3] = content
675 if self.config.get("dhcp_server") and self.config['network_type'] == 'bridge':
676 if network["name"] in self.config["dhcp_server"].get("nets", ()):
677 self.config["dhcp_nets"].append(content)
mirabale9f6f1a2017-02-16 17:57:35 +0100678 self.logger.debug("dhcp_server: add new net", content)
tierno11c45e72017-05-17 12:04:05 +0000679 elif bridge_net and bridge_net[0] in self.config["dhcp_server"].get("bridge_ifaces", ()):
mirabal65ba8f82017-02-15 12:36:33 +0100680 self.config["dhcp_nets"].append(content)
mirabale9f6f1a2017-02-16 17:57:35 +0100681 self.logger.debug("dhcp_server: add new net", content, content)
mirabal65ba8f82017-02-15 12:36:33 +0100682 return content
683 else:
mirabal65ba8f82017-02-15 12:36:33 +0100684 raise ovimException("Error posting network", HTTP_Internal_Server_Error)
mirabale9f6f1a2017-02-16 17:57:35 +0100685# TODO kei change update->edit
mirabal65ba8f82017-02-15 12:36:33 +0100686
mirabale9f6f1a2017-02-16 17:57:35 +0100687 def edit_network(self, network_id, network):
mirabal65ba8f82017-02-15 12:36:33 +0100688 """
mirabale9f6f1a2017-02-16 17:57:35 +0100689 Update entwork data byt id
mirabal65ba8f82017-02-15 12:36:33 +0100690 :return:
691 """
mirabale9f6f1a2017-02-16 17:57:35 +0100692 # Look for the previous data
693 where_ = {'uuid': network_id}
694 result, network_old = self.db.get_table(FROM='nets', WHERE=where_)
695 if result < 0:
696 raise ovimException("Error updating network %s" % network_old, HTTP_Internal_Server_Error)
697 elif result == 0:
698 raise ovimException('network %s not found' % network_id, HTTP_Not_Found)
699 # get ports
700 nbports, content = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
701 WHERE={'net_id': network_id}, LIMIT=100)
702 if result < 0:
703 raise ovimException("http_put_network_id error %d %s" % (result, network_old), HTTP_Internal_Server_Error)
704 if nbports > 0:
705 if 'type' in network and network['type'] != network_old[0]['type']:
706 raise ovimException("Can not change type of network while having ports attached",
707 HTTP_Method_Not_Allowed)
708 if 'vlan' in network and network['vlan'] != network_old[0]['vlan']:
709 raise ovimException("Can not change vlan of network while having ports attached",
710 HTTP_Method_Not_Allowed)
mirabal65ba8f82017-02-15 12:36:33 +0100711
mirabale9f6f1a2017-02-16 17:57:35 +0100712 # check valid params
713 net_provider = network.get('provider', network_old[0]['provider'])
714 net_type = network.get('type', network_old[0]['type'])
715 net_bind_net = network.get("bind_net")
716 net_bind_type = network.get("bind_type")
717 if net_bind_net:
718 # look for a valid net
719 if self._check_valid_uuid(net_bind_net):
720 net_bind_key = "uuid"
721 else:
722 net_bind_key = "name"
723 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
724 if result < 0:
725 raise ovimException('Getting nets from db ' + content, HTTP_Internal_Server_Error)
726 elif result == 0:
727 raise ovimException("bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
728 elif result > 1:
729 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net),
730 HTTP_Bad_Request)
731 network["bind_net"] = content[0]["uuid"]
732 if net_bind_type:
733 if net_bind_type[0:5] != "vlan:":
734 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
735 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
736 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
737 HTTP_Bad_Request)
738 if net_provider:
739 if net_provider[:9] == "openflow:":
740 if net_type != "ptp" and net_type != "data":
741 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request)
742 else:
743 if net_type != "bridge_man" and net_type != "bridge_data":
744 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
745 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
mirabal65ba8f82017-02-15 12:36:33 +0100746
mirabale9f6f1a2017-02-16 17:57:35 +0100747 # insert in data base
748 result, content = self.db.update_rows('nets', network, WHERE={'uuid': network_id}, log=True)
749 if result >= 0:
750 # if result > 0 and nbports>0 and 'admin_state_up' in network
751 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
752 if result > 0:
mirabal7bbf50e2017-03-13 15:15:18 +0100753
754 try:
tiernoaa941462017-03-29 15:10:28 +0200755 if nbports:
756 self.net_update_ofc_thread(network_id)
mirabal7bbf50e2017-03-13 15:15:18 +0100757 except ovimException as e:
758 raise ovimException("Error while launching openflow rules in network '{}' {}"
759 .format(network_id, str(e)), HTTP_Internal_Server_Error)
760 except Exception as e:
761 raise ovimException("Error while launching openflow rules in network '{}' {}"
762 .format(network_id, str(e)), HTTP_Internal_Server_Error)
763
mirabale9f6f1a2017-02-16 17:57:35 +0100764 if self.config.get("dhcp_server"):
765 if network_id in self.config["dhcp_nets"]:
766 self.config["dhcp_nets"].remove(network_id)
mirabal7bbf50e2017-03-13 15:15:18 +0100767 if network.get("name", network_old[0]["name"]) in self.config["dhcp_server"].get("nets", ()):
mirabale9f6f1a2017-02-16 17:57:35 +0100768 self.config["dhcp_nets"].append(network_id)
769 else:
mirabal7bbf50e2017-03-13 15:15:18 +0100770 net_bind = network.get("bind_type", network_old[0]["bind_type"])
771 if net_bind and net_bind and net_bind[:7] == "bridge:" and net_bind[7:] in self.config["dhcp_server"].get(
mirabale9f6f1a2017-02-16 17:57:35 +0100772 "bridge_ifaces", ()):
773 self.config["dhcp_nets"].append(network_id)
774 return network_id
mirabal65ba8f82017-02-15 12:36:33 +0100775 else:
mirabale9f6f1a2017-02-16 17:57:35 +0100776 raise ovimException(content, -result)
mirabal65ba8f82017-02-15 12:36:33 +0100777
mirabale9f6f1a2017-02-16 17:57:35 +0100778 def delete_network(self, network_id):
mirabal9e194592017-02-17 11:03:25 +0100779 """
780 Delete network by network id
781 :param network_id: network id
782 :return:
783 """
mirabale9f6f1a2017-02-16 17:57:35 +0100784
785 # delete from the data base
786 result, content = self.db.delete_row('nets', network_id)
787
788 if result == 0:
789 raise ovimException("Network %s not found " % network_id, HTTP_Not_Found)
790 elif result > 0:
791 for brnet in self.config['bridge_nets']:
792 if brnet[3] == network_id:
793 brnet[3] = None
794 break
795 if self.config.get("dhcp_server") and network_id in self.config["dhcp_nets"]:
796 self.config["dhcp_nets"].remove(network_id)
797 return content
798 else:
tierno11c45e72017-05-17 12:04:05 +0000799 raise ovimException("Error deleting network '{}': {}".format(network_id, content), -result)
mirabal65ba8f82017-02-15 12:36:33 +0100800
801 def get_openflow_rules(self, network_id=None):
802 """
803 Get openflow id from DB
804 :param network_id: Network id, if none all networks will be retrieved
805 :return: Return a list with Openflow rules per net
806 """
807 # ignore input data
808 if not network_id:
809 where_ = {}
810 else:
811 where_ = {"net_id": network_id}
mirabal65ba8f82017-02-15 12:36:33 +0100812 result, content = self.db.get_table(
mirabalf9a1a8d2017-03-15 12:42:27 +0100813 SELECT=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
mirabal65ba8f82017-02-15 12:36:33 +0100814 WHERE=where_, FROM='of_flows')
815
816 if result < 0:
817 raise ovimException(str(content), -result)
818 return content
819
mirabale9f6f1a2017-02-16 17:57:35 +0100820 def edit_openflow_rules(self, network_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100821
822 """
823 To make actions over the net. The action is to reinstall the openflow rules
824 network_id can be 'all'
825 :param network_id: Network id, if none all networks will be retrieved
826 :return : Number of nets updated
827 """
828
829 # ignore input data
830 if not network_id:
831 where_ = {}
832 else:
833 where_ = {"uuid": network_id}
834 result, content = self.db.get_table(SELECT=("uuid", "type"), WHERE=where_, FROM='nets')
835
836 if result < 0:
837 raise ovimException(str(content), -result)
838
839 for net in content:
840 if net["type"] != "ptp" and net["type"] != "data":
841 result -= 1
842 continue
mirabal7bbf50e2017-03-13 15:15:18 +0100843
844 try:
845 self.net_update_ofc_thread(net['uuid'])
846 except ovimException as e:
847 raise ovimException("Error updating network'{}' {}".format(net['uuid'], str(e)),
848 HTTP_Internal_Server_Error)
849 except Exception as e:
850 raise ovimException("Error updating network '{}' {}".format(net['uuid'], str(e)),
851 HTTP_Internal_Server_Error)
852
mirabal65ba8f82017-02-15 12:36:33 +0100853 return result
854
mirabalf9a1a8d2017-03-15 12:42:27 +0100855 def delete_openflow_rules(self, ofc_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100856 """
857 To make actions over the net. The action is to delete ALL openflow rules
858 :return: return operation result
859 """
mirabalf9a1a8d2017-03-15 12:42:27 +0100860
861 if not ofc_id:
862 if 'Default' in self.config['ofcs_thread']:
863 r, c = self.config['ofcs_thread']['Default'].insert_task("clear-all")
864 else:
865 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
866
867 elif ofc_id in self.config['ofcs_thread']:
868 r, c = self.config['ofcs_thread'][ofc_id].insert_task("clear-all")
869
870 # ignore input data
871 if r < 0:
872 raise ovimException(str(c), -r)
873 else:
874 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
mirabal65ba8f82017-02-15 12:36:33 +0100875 return r
876
mirabalf9a1a8d2017-03-15 12:42:27 +0100877 def get_openflow_ports(self, ofc_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100878 """
879 Obtain switch ports names of openflow controller
880 :return: Return flow ports in DB
881 """
mirabalf9a1a8d2017-03-15 12:42:27 +0100882 if not ofc_id:
883 if 'Default' in self.config['ofcs_thread']:
884 conn = self.config['ofcs_thread']['Default'].OF_connector
885 else:
886 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
887
tierno11c45e72017-05-17 12:04:05 +0000888 elif ofc_id in self.config['ofcs_thread']:
mirabalf9a1a8d2017-03-15 12:42:27 +0100889 conn = self.config['ofcs_thread'][ofc_id].OF_connector
890 else:
891 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
892 return conn.pp2ofi
tierno57f7bda2017-02-09 12:01:55 +0100893
894 def get_ports(self, columns=None, filter={}, limit=None):
895 # result, content = my.db.get_ports(where_)
896 result, content = self.db.get_table(SELECT=columns, WHERE=filter, FROM='ports', LIMIT=limit)
897 if result < 0:
898 self.logger.error("http_get_ports Error %d %s", result, content)
899 raise ovimException(str(content), -result)
900 else:
901 convert_boolean(content, ('admin_state_up',))
902 return content
903
tierno57f7bda2017-02-09 12:01:55 +0100904 def new_port(self, port_data):
905 port_data['type'] = 'external'
906 if port_data.get('net_id'):
907 # check that new net has the correct type
908 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
909 if result < 0:
910 raise ovimException(str(new_net), -result)
911 # insert in data base
912 result, uuid = self.db.new_row('ports', port_data, True, True)
913 if result > 0:
914 if 'net_id' in port_data:
mirabal7bbf50e2017-03-13 15:15:18 +0100915 try:
916 self.net_update_ofc_thread(port_data['net_id'])
917 except ovimException as e:
918 raise ovimException("Cannot insert a task for updating network '{}' {}"
919 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
920 except Exception as e:
921 raise ovimException("Cannot insert a task for updating network '{}' {}"
922 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
923
tierno57f7bda2017-02-09 12:01:55 +0100924 return uuid
925 else:
926 raise ovimException(str(uuid), -result)
927
mirabal37829452017-03-09 14:41:21 +0100928 def new_external_port(self, port_data):
929 """
930 Create new external port and check port mapping correspondence
931 :param port_data: port_data = {
932 'region': 'datacenter region',
933 'compute_node': 'compute node id',
934 'pci': 'pci port address',
935 'vlan': 'net vlan',
936 'net_id': 'net id',
937 'tenant_id': 'tenant id',
938 'mac': 'switch mac',
939 'name': 'port name'
940 'ip_address': 'ip address - optional'}
941 :return:
942 """
943
944 port_data['type'] = 'external'
945
946 if port_data.get('net_id'):
947 # check that new net has the correct type
948 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
949 if result < 0:
950 raise ovimException(str(new_net), -result)
951 # insert in data base
952 db_filter = {}
953
954 if port_data.get('region'):
955 db_filter['region'] = port_data['region']
956 if port_data.get('pci'):
957 db_filter['pci'] = port_data['pci']
958 if port_data.get('compute_node'):
959 db_filter['compute_node'] = port_data['compute_node']
960
961 columns = ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
962 port_mapping_data = self.get_of_port_mappings(columns, db_filter)
963
964 if not len(port_mapping_data):
tierno16007502017-03-27 16:48:32 +0200965 raise ovimException("No port mapping founded for '{}'".format(str(db_filter)),
mirabal37829452017-03-09 14:41:21 +0100966 HTTP_Not_Found)
967 elif len(port_mapping_data) > 1:
968 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
969 HTTP_Conflict)
970
971 port_data['ofc_id'] = port_mapping_data[0]['ofc_id']
972 port_data['switch_dpid'] = port_mapping_data[0]['switch_dpid']
973 port_data['switch_port'] = port_mapping_data[0]['switch_port']
974 port_data['switch_mac'] = port_mapping_data[0]['switch_mac']
975
976 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
montesmoreno275b1992017-03-28 15:45:02 +0200977 if 'region' in port_data:
978 del port_data['region']
979 if 'pci' in port_data:
980 del port_data['pci']
981 if 'compute_node' in port_data:
982 del port_data['compute_node']
mirabal37829452017-03-09 14:41:21 +0100983
984 result, uuid = self.db.new_row('ports', port_data, True, True)
985 if result > 0:
mirabal7bbf50e2017-03-13 15:15:18 +0100986 try:
987 self.net_update_ofc_thread(port_data['net_id'], port_data['ofc_id'])
988 except ovimException as e:
989 raise ovimException("Cannot insert a task for updating network '{}' {}".
990 format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
991 except Exception as e:
992 raise ovimException("Cannot insert a task for updating network '{}' {}"
993 .format(port_data['net_id'], e), HTTP_Internal_Server_Error)
mirabal37829452017-03-09 14:41:21 +0100994 return uuid
995 else:
996 raise ovimException(str(uuid), -result)
997
tiernoaa941462017-03-29 15:10:28 +0200998 def net_update_ofc_thread(self, net_id, ofc_id=None, switch_dpid=None):
mirabal7bbf50e2017-03-13 15:15:18 +0100999 """
1000 Insert a update net task by net id or ofc_id for each ofc thread
1001 :param net_id: network id
1002 :param ofc_id: openflow controller id
tiernoaa941462017-03-29 15:10:28 +02001003 :param switch_dpid: switch dpid
mirabal7bbf50e2017-03-13 15:15:18 +01001004 :return:
1005 """
1006 if not net_id:
1007 raise ovimException("No net_id received", HTTP_Internal_Server_Error)
1008
mirabal7bbf50e2017-03-13 15:15:18 +01001009 r = -1
1010 c = 'No valid ofc_id or switch_dpid received'
1011
1012 if not ofc_id:
1013 ports = self.get_ports(filter={"net_id": net_id})
1014 for port in ports:
1015 port_ofc_id = port.get('ofc_id', None)
1016 if port_ofc_id:
1017 ofc_id = port['ofc_id']
1018 switch_dpid = port['switch_dpid']
1019 break
tiernoaa941462017-03-29 15:10:28 +02001020 #TODO if not ofc_id: look at database table ofcs
1021
mirabal7bbf50e2017-03-13 15:15:18 +01001022
1023 # If no ofc_id found it, default ofc_id is used.
1024 if not ofc_id and not switch_dpid:
1025 ofc_id = "Default"
1026
1027 if ofc_id and ofc_id in self.config['ofcs_thread']:
1028 r, c = self.config['ofcs_thread'][ofc_id].insert_task("update-net", net_id)
1029 elif switch_dpid:
1030
1031 ofcs_dpid_list = self.config['ofcs_thread_dpid']
1032 for ofc_t in ofcs_dpid_list:
1033 if switch_dpid in ofc_t:
1034 r, c = ofc_t[switch_dpid].insert_task("update-net", net_id)
1035
1036 if r < 0:
tierno82232582017-03-15 18:09:16 +01001037 message = "Cannot insert a task for updating network '{}', {}".format(net_id, c)
mirabal7bbf50e2017-03-13 15:15:18 +01001038 self.logger.error(message)
1039 raise ovimException(message, HTTP_Internal_Server_Error)
1040
tierno57f7bda2017-02-09 12:01:55 +01001041 def delete_port(self, port_id):
1042 # Look for the previous port data
1043 result, ports = self.db.get_table(WHERE={'uuid': port_id, "type": "external"}, FROM='ports')
1044 if result < 0:
1045 raise ovimException("Cannot get port info from database: {}".format(ports), http_code=-result)
1046 # delete from the data base
1047 result, content = self.db.delete_row('ports', port_id)
1048 if result == 0:
1049 raise ovimException("External port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1050 elif result < 0:
1051 raise ovimException("Cannot delete port from database: {}".format(content), http_code=-result)
1052 # update network
1053 network = ports[0].get('net_id', None)
1054 if network:
1055 # change of net.
mirabal7bbf50e2017-03-13 15:15:18 +01001056
1057 try:
tiernoaa941462017-03-29 15:10:28 +02001058 self.net_update_ofc_thread(network, ofc_id=ports[0]["ofc_id"], switch_dpid=ports[0]["switch_dpid"])
mirabal7bbf50e2017-03-13 15:15:18 +01001059 except ovimException as e:
1060 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
1061 HTTP_Internal_Server_Error)
1062 except Exception as e:
1063 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
1064 HTTP_Internal_Server_Error)
1065
tierno57f7bda2017-02-09 12:01:55 +01001066 return content
1067
tierno57f7bda2017-02-09 12:01:55 +01001068 def edit_port(self, port_id, port_data, admin=True):
1069 # Look for the previous port data
1070 result, content = self.db.get_table(FROM="ports", WHERE={'uuid': port_id})
1071 if result < 0:
1072 raise ovimException("Cannot get port info from database: {}".format(content), http_code=-result)
1073 elif result == 0:
1074 raise ovimException("Port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1075 port = content[0]
1076 nets = []
1077 host_id = None
1078 result = 1
1079 if 'net_id' in port_data:
1080 # change of net.
1081 old_net = port.get('net_id', None)
1082 new_net = port_data['net_id']
1083 if old_net != new_net:
1084
1085 if new_net:
1086 nets.append(new_net) # put first the new net, so that new openflow rules are created before removing the old ones
1087 if old_net:
1088 nets.append(old_net)
1089 if port['type'] == 'instance:bridge' or port['type'] == 'instance:ovs':
1090 raise ovimException("bridge interfaces cannot be attached to a different net", http_code=HTTP_Forbidden)
1091 elif port['type'] == 'external' and not admin:
1092 raise ovimException("Needed admin privileges",http_code=HTTP_Unauthorized)
1093 if new_net:
1094 # check that new net has the correct type
1095 result, new_net_dict = self.db.check_target_net(new_net, None, port['type'])
1096 if result < 0:
1097 raise ovimException("Error {}".format(new_net_dict), http_code=HTTP_Conflict)
1098 # change VLAN for SR-IOV ports
1099 if result >= 0 and port["type"] == "instance:data" and port["model"] == "VF": # TODO consider also VFnotShared
1100 if new_net:
1101 port_data["vlan"] = None
1102 else:
1103 port_data["vlan"] = new_net_dict["vlan"]
1104 # get host where this VM is allocated
1105 result, content = self.db.get_table(FROM="instances", WHERE={"uuid": port["instance_id"]})
1106 if result > 0:
1107 host_id = content[0]["host_id"]
1108
1109 # insert in data base
1110 if result >= 0:
1111 result, content = self.db.update_rows('ports', port_data, WHERE={'uuid': port_id}, log=False)
tiernoaa941462017-03-29 15:10:28 +02001112 port.update(port_data)
tierno57f7bda2017-02-09 12:01:55 +01001113
1114 # Insert task to complete actions
1115 if result > 0:
1116 for net_id in nets:
mirabal7bbf50e2017-03-13 15:15:18 +01001117 try:
tiernoaa941462017-03-29 15:10:28 +02001118 self.net_update_ofc_thread(net_id, port["ofc_id"], switch_dpid=port["switch_dpid"])
mirabal7bbf50e2017-03-13 15:15:18 +01001119 except ovimException as e:
1120 raise ovimException("Error updating network'{}' {}".format(net_id, str(e)),
1121 HTTP_Internal_Server_Error)
1122 except Exception as e:
1123 raise ovimException("Error updating network '{}' {}".format(net_id, str(e)),
1124 HTTP_Internal_Server_Error)
1125
tierno57f7bda2017-02-09 12:01:55 +01001126 if host_id:
1127 r, v = self.config['host_threads'][host_id].insert_task("edit-iface", port_id, old_net, new_net)
1128 if r < 0:
1129 self.logger.error("Error updating network '{}' {}".format(r,v))
1130 # TODO Do something if fails
1131 if result >= 0:
1132 return port_id
1133 else:
1134 raise ovimException("Error {}".format(content), http_code=-result)
mirabalb716ac52017-02-10 14:47:53 +01001135
mirabal9e194592017-02-17 11:03:25 +01001136 def new_of_controller(self, ofc_data):
1137 """
1138 Create a new openflow controller into DB
1139 :param ofc_data: Dict openflow controller data
1140 :return: openflow controller dpid
1141 """
1142
mirabal580435e2017-03-01 16:17:10 +01001143 result, ofc_uuid = self.db.new_row('ofcs', ofc_data, True, True)
mirabal9e194592017-02-17 11:03:25 +01001144 if result < 0:
mirabal580435e2017-03-01 16:17:10 +01001145 raise ovimException("New ofc Error %s" % ofc_uuid, HTTP_Internal_Server_Error)
1146
1147 ofc_data['uuid'] = ofc_uuid
1148 of_conn = self._load_of_module(ofc_data)
1149 self._create_ofc_task(ofc_uuid, ofc_data['dpid'], of_conn)
1150
1151 return ofc_uuid
mirabal9e194592017-02-17 11:03:25 +01001152
1153 def edit_of_controller(self, of_id, ofc_data):
1154 """
1155 Edit an openflow controller entry from DB
1156 :return:
1157 """
1158 if not ofc_data:
1159 raise ovimException("No data received during uptade OF contorller", http_code=HTTP_Internal_Server_Error)
1160
1161 old_of_controller = self.show_of_controller(of_id)
1162
1163 if old_of_controller:
1164 result, content = self.db.update_rows('ofcs', ofc_data, WHERE={'uuid': of_id}, log=False)
1165 if result >= 0:
1166 return ofc_data
1167 else:
1168 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1169 http_code=-result)
1170 else:
1171 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1172 http_code=HTTP_Internal_Server_Error)
1173
1174 def delete_of_controller(self, of_id):
1175 """
1176 Delete an openflow controller from DB.
1177 :param of_id: openflow controller dpid
1178 :return:
1179 """
1180
mirabal580435e2017-03-01 16:17:10 +01001181 ofc = self.show_of_controller(of_id)
1182
Pablo Montes Moreno5b6f7492017-03-02 16:18:36 +01001183 result, content = self.db.delete_row("ofcs", of_id)
mirabal9e194592017-02-17 11:03:25 +01001184 if result < 0:
1185 raise ovimException("Cannot delete ofc from database: {}".format(content), http_code=-result)
1186 elif result == 0:
1187 raise ovimException("ofc {} not found ".format(content), http_code=HTTP_Not_Found)
mirabal580435e2017-03-01 16:17:10 +01001188
1189 ofc_thread = self.config['ofcs_thread'][of_id]
1190 del self.config['ofcs_thread'][of_id]
1191 for ofc_th in self.config['ofcs_thread_dpid']:
1192 if ofc['dpid'] in ofc_th:
1193 self.config['ofcs_thread_dpid'].remove(ofc_th)
1194
1195 ofc_thread.insert_task("exit")
1196 #ofc_thread.join()
1197
mirabal9e194592017-02-17 11:03:25 +01001198 return content
1199
1200 def show_of_controller(self, uuid):
1201 """
1202 Show an openflow controller by dpid from DB.
1203 :param db_filter: List with where query parameters
1204 :return:
1205 """
1206
1207 result, content = self.db.get_table(FROM='ofcs', WHERE={"uuid": uuid}, LIMIT=100)
1208
1209 if result == 0:
1210 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid),
1211 http_code=HTTP_Not_Found)
1212 elif result < 0:
1213 raise ovimException("Openflow controller with uuid '{}' error".format(uuid),
1214 http_code=HTTP_Internal_Server_Error)
Pablo Montes Moreno5b6f7492017-03-02 16:18:36 +01001215 return content[0]
mirabal9e194592017-02-17 11:03:25 +01001216
mirabalfbfb7972017-02-27 17:36:17 +01001217 def get_of_controllers(self, columns=None, db_filter={}, limit=None):
mirabal9e194592017-02-17 11:03:25 +01001218 """
1219 Show an openflow controllers from DB.
1220 :param columns: List with SELECT query parameters
1221 :param db_filter: List with where query parameters
mirabalfbfb7972017-02-27 17:36:17 +01001222 :param limit: result Limit
mirabal9e194592017-02-17 11:03:25 +01001223 :return:
1224 """
mirabalfbfb7972017-02-27 17:36:17 +01001225 result, content = self.db.get_table(SELECT=columns, FROM='ofcs', WHERE=db_filter, LIMIT=limit)
mirabal9e194592017-02-17 11:03:25 +01001226
1227 if result < 0:
1228 raise ovimException(str(content), -result)
1229
1230 return content
1231
mirabalfbfb7972017-02-27 17:36:17 +01001232 def get_tenants(self, columns=None, db_filter={}, limit=None):
1233 """
1234 Retrieve tenant list from DB
1235 :param columns: List with SELECT query parameters
1236 :param db_filter: List with where query parameters
1237 :param limit: result limit
1238 :return:
1239 """
1240 result, content = self.db.get_table(FROM='tenants', SELECT=columns, WHERE=db_filter, LIMIT=limit)
1241 if result < 0:
1242 raise ovimException('get_tenatns Error {}'.format(str(content)), -result)
1243 else:
1244 convert_boolean(content, ('enabled',))
1245 return content
1246
1247 def show_tenant_id(self, tenant_id):
1248 """
1249 Get tenant from DB by id
1250 :param tenant_id: tenant id
1251 :return:
1252 """
1253 result, content = self.db.get_table(FROM='tenants', SELECT=('uuid', 'name', 'description', 'enabled'),
1254 WHERE={"uuid": tenant_id})
1255 if result < 0:
1256 raise ovimException(str(content), -result)
1257 elif result == 0:
1258 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1259 else:
1260 convert_boolean(content, ('enabled',))
1261 return content[0]
1262
1263 def new_tentant(self, tenant):
1264 """
1265 Create a tenant and store in DB
1266 :param tenant: Dictionary with tenant data
1267 :return: the uuid of created tenant. Raise exception upon error
1268 """
1269
1270 # insert in data base
1271 result, tenant_uuid = self.db.new_tenant(tenant)
1272
1273 if result >= 0:
1274 return tenant_uuid
1275 else:
1276 raise ovimException(str(tenant_uuid), -result)
1277
1278 def delete_tentant(self, tenant_id):
1279 """
1280 Delete a tenant from the database.
1281 :param tenant_id: Tenant id
1282 :return: delete tenant id
1283 """
1284
1285 # check permissions
1286 r, tenants_flavors = self.db.get_table(FROM='tenants_flavors', SELECT=('flavor_id', 'tenant_id'),
1287 WHERE={'tenant_id': tenant_id})
1288 if r <= 0:
1289 tenants_flavors = ()
1290 r, tenants_images = self.db.get_table(FROM='tenants_images', SELECT=('image_id', 'tenant_id'),
1291 WHERE={'tenant_id': tenant_id})
1292 if r <= 0:
1293 tenants_images = ()
1294
1295 result, content = self.db.delete_row('tenants', tenant_id)
1296 if result == 0:
1297 raise ovimException("tenant '%s' not found" % tenant_id, HTTP_Not_Found)
1298 elif result > 0:
1299 for flavor in tenants_flavors:
1300 self.db.delete_row_by_key("flavors", "uuid", flavor['flavor_id'])
1301 for image in tenants_images:
1302 self.db.delete_row_by_key("images", "uuid", image['image_id'])
1303 return content
1304 else:
1305 raise ovimException("Error deleting tenant '%s' " % tenant_id, HTTP_Internal_Server_Error)
1306
1307 def edit_tenant(self, tenant_id, tenant_data):
1308 """
1309 Update a tenant data identified by tenant id
1310 :param tenant_id: tenant id
1311 :param tenant_data: Dictionary with tenant data
1312 :return:
1313 """
1314
1315 # Look for the previous data
1316 result, tenant_data_old = self.db.get_table(FROM='tenants', WHERE={'uuid': tenant_id})
1317 if result < 0:
1318 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id, tenant_data_old),
1319 HTTP_Internal_Server_Error)
1320 elif result == 0:
1321 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1322
1323 # insert in data base
1324 result, content = self.db.update_rows('tenants', tenant_data, WHERE={'uuid': tenant_id}, log=True)
1325 if result >= 0:
1326 return content
1327 else:
1328 raise ovimException(str(content), -result)
1329
mirabal6045a9d2017-03-06 11:36:55 +01001330 def set_of_port_mapping(self, of_maps, ofc_id=None, switch_dpid=None, region=None):
1331 """
1332 Create new port mapping entry
1333 :param of_maps: List with port mapping information
1334 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1335 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1336 :param ofc_id: ofc id
1337 :param switch_dpid: switch dpid
1338 :param region: datacenter region id
1339 :return:
1340 """
1341
1342 for map in of_maps:
1343 if ofc_id:
1344 map['ofc_id'] = ofc_id
1345 if switch_dpid:
1346 map['switch_dpid'] = switch_dpid
1347 if region:
1348 map['region'] = region
1349
1350 for of_map in of_maps:
1351 result, uuid = self.db.new_row('of_port_mappings', of_map, True)
1352 if result > 0:
1353 of_map["uuid"] = uuid
1354 else:
1355 raise ovimException(str(uuid), -result)
1356 return of_maps
1357
1358 def clear_of_port_mapping(self, db_filter={}):
1359 """
1360 Clear port mapping filtering using db_filter dict
1361 :param db_filter: Parameter to filter during remove process
1362 :return:
1363 """
1364 result, content = self.db.delete_row_by_dict(FROM='of_port_mappings', WHERE=db_filter)
1365 # delete_row_by_key
1366 if result >= 0:
1367 return content
1368 else:
1369 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter)),
1370 HTTP_Internal_Server_Error)
1371
1372 def get_of_port_mappings(self, column=None, db_filter=None, db_limit=None):
1373 """
1374 Retrive port mapping from DB
1375 :param column:
1376 :param db_filter:
1377 :return:
1378 """
1379 result, content = self.db.get_table(SELECT=column, WHERE=db_filter, FROM='of_port_mappings', LIMIT=db_limit)
1380
1381 if result < 0:
1382 self.logger.error("get_of_port_mappings Error %d %s", result, content)
1383 raise ovimException(str(content), -result)
1384 else:
1385 return content
1386
mirabalb716ac52017-02-10 14:47:53 +01001387 def get_dhcp_controller(self):
1388 """
1389 Create an host_thread object for manage openvim controller and not create a thread for itself
1390 :return: dhcp_host openvim controller object
1391 """
1392
1393 if 'openvim_controller' in self.config['host_threads']:
1394 return self.config['host_threads']['openvim_controller']
1395
1396 bridge_ifaces = []
1397 controller_ip = self.config['ovs_controller_ip']
tiernoa6933042017-05-24 16:54:33 +02001398 ovs_controller_user = self.config.get('ovs_controller_user')
mirabalb716ac52017-02-10 14:47:53 +01001399
1400 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
1401 host_develop_mode = True if self.config['mode'] == 'development' else False
1402
1403 dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip,
tiernoa6933042017-05-24 16:54:33 +02001404 password=self.config.get('ovs_controller_password'),
1405 keyfile=self.config.get('ovs_controller_keyfile'),
tiernoe0c28c12017-05-04 18:44:40 +02001406 db=self.config["db"], db_lock=self.config["db_lock"], test=host_test_mode,
tiernoa6933042017-05-24 16:54:33 +02001407 image_path=self.config['host_image_path'], version=self.config['version'],
mirabalb716ac52017-02-10 14:47:53 +01001408 host_id='openvim_controller', develop_mode=host_develop_mode,
tiernoe0c28c12017-05-04 18:44:40 +02001409 develop_bridge_iface=bridge_ifaces,
1410 logger_name=self.logger_name + ".host.controller",
tiernof135eff2017-04-19 19:11:53 +02001411 debug=self.config.get('log_level_host'))
tiernoa6933042017-05-24 16:54:33 +02001412 # dhcp_host.start()
mirabalb716ac52017-02-10 14:47:53 +01001413 self.config['host_threads']['openvim_controller'] = dhcp_host
mirabal42ca0092017-06-14 05:42:30 -05001414 try:
1415 dhcp_host.check_connectivity()
1416 except Exception as e:
1417 pass
1418
mirabalb716ac52017-02-10 14:47:53 +01001419 return dhcp_host
1420
mirabal6878e3f2017-06-05 09:19:26 -05001421 def launch_dhcp_server(self, vlan, first_ip, last_ip, cidr, gateway, dns, routes):
mirabalb716ac52017-02-10 14:47:53 +01001422 """
1423 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1424 :param vlan: vlan identifier
1425 :param first_ip: First dhcp range ip
1426 :param last_ip: Last dhcp range ip
1427 :param cidr: net cidr
mirabale9f6f1a2017-02-16 17:57:35 +01001428 :param gateway: net gateway
mirabalb716ac52017-02-10 14:47:53 +01001429 :return:
1430 """
1431 ip_tools = IPNetwork(cidr)
1432 dhcp_netmask = str(ip_tools.netmask)
1433 ip_range = [first_ip, last_ip]
1434
1435 dhcp_path = self.config['ovs_controller_file_path']
1436
1437 controller_host = self.get_dhcp_controller()
mirabale16a6362017-07-10 05:45:56 -05001438
mirabal6878e3f2017-06-05 09:19:26 -05001439 # controller_host.create_linux_bridge(vlan)
1440 controller_host.create_dhcp_interfaces(vlan, first_ip, dhcp_netmask)
1441 dhcp_path = self.config['ovs_controller_file_path']
1442 controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path, gateway, dns, routes)
1443
1444 def launch_link_bridge_to_ovs(self, vlan, gateway, dhcp_cidr, links=None, routes=None):
1445 """
1446 Launch creating of connections (veth) between user bridge (link) and OVS
1447 :param vlan:
1448 :param gateway:
1449 :param links:
1450 :return:
1451 """
1452
1453 if links:
1454 controller_host = self.get_dhcp_controller()
1455 for link in links:
1456 if 'iface' in link and 'nat' not in link:
1457 controller_host.create_link_bridge_to_ovs(vlan, link['iface'])
1458 elif 'nat' in link:
1459 controller_host.create_qrouter_ovs_connection(vlan, gateway, dhcp_cidr)
1460 controller_host.create_qrouter_br_connection(vlan, dhcp_cidr, link)
1461
1462 if len(routes):
1463 controller_host.add_ns_routes(vlan, routes)
1464
1465 def delete_link_bridge_to_ovs(self, vlan, links=None):
1466 """
1467 Delete connections (veth) between user bridge (link) and OVS
1468 :param vlan:
1469 :param links:
1470 :return:
1471 """
1472 if links:
1473 controller_host = self.get_dhcp_controller()
1474
1475 for link in links:
1476 if 'iface' in link and 'nat' not in link:
1477 controller_host.remove_link_bridge_to_ovs(vlan, link['iface'])
1478 elif 'nat' in link:
1479 controller_host.delete_qrouter_connection(vlan, link['iface'])
1480
mirabalb716ac52017-02-10 14:47:53 +01001481
mirabald87877c2017-03-31 15:15:52 +02001482if __name__ == "__main__":
1483
1484 parser = argparse.ArgumentParser()
tierno46ca3a92017-04-05 19:49:24 +02001485 parser.add_argument("-v","--version", help="show ovim library version", action="store_true")
1486 parser.add_argument("--database-version", help="show required database version", action="store_true")
mirabald87877c2017-03-31 15:15:52 +02001487 args = parser.parse_args()
1488 if args.version:
1489 print ('openvimd version {} {}'.format(ovim.get_version(), ovim.get_version_date()))
1490 print ('(c) Copyright Telefonica')
tierno46ca3a92017-04-05 19:49:24 +02001491 elif args.database_version:
1492 print ('required database version: {}'.format(ovim.get_database_version()))
mirabalb716ac52017-02-10 14:47:53 +01001493