blob: 5650cd50707d1d6b43310cea556bcc5b6f00431a [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']
tierno1d5c2292017-07-13 17:50:59 +0200286 if net['status'] != "INACTIVE" and (net_type == 'bridge_data' or net_type == 'bridge_man') and \
tiernoa6933042017-05-24 16:54:33 +0200287 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)
tierno1d5c2292017-07-13 17:50:59 +0200312 if net["status"] == "ERROR":
313 self.db.update_rows("nets", UPDATE={"status": "ACTIVE", "last_error": None},
314 WHERE={"uuid": net["uuid"]})
tiernoa6933042017-05-24 16:54:33 +0200315 except Exception as e:
316 self.logger.error("Fail at launching dhcp server for net_id='%s' net_name='%s': %s",
317 net["uuid"], net["name"], str(e))
tierno1d5c2292017-07-13 17:50:59 +0200318 self.db.update_rows("nets", UPDATE={"status": "ERROR",
tiernoa6933042017-05-24 16:54:33 +0200319 "last_error": "Fail at launching dhcp server: " + str(e)},
tierno1d5c2292017-07-13 17:50:59 +0200320 WHERE={"uuid": net["uuid"]})
mirabalb716ac52017-02-10 14:47:53 +0100321
mirabal580435e2017-03-01 16:17:10 +0100322 def _start_of_db_tasks(self):
323 """
324 Start ofc task for existing ofcs in database
325 :param db_of:
326 :param db_lock:
327 :return:
328 """
329 ofcs = self.get_of_controllers()
330
331 for ofc in ofcs:
332 of_conn = self._load_of_module(ofc)
333 # create ofc thread per of controller
334 self._create_ofc_task(ofc['uuid'], ofc['dpid'], of_conn)
335
336 def _create_ofc_task(self, ofc_uuid, dpid, of_conn):
337 """
338 Create an ofc thread for handle each sdn controllers
339 :param ofc_uuid: sdn controller uuid
340 :param dpid: sdn controller dpid
341 :param of_conn: OF_conn module
342 :return:
343 """
344 if 'ofcs_thread' not in self.config and 'ofcs_thread_dpid' not in self.config:
345 ofcs_threads = {}
346 ofcs_thread_dpid = []
347 else:
348 ofcs_threads = self.config['ofcs_thread']
349 ofcs_thread_dpid = self.config['ofcs_thread_dpid']
350
351 if ofc_uuid not in ofcs_threads:
352 ofc_thread = self._create_ofc_thread(of_conn, ofc_uuid)
353 if ofc_uuid == "Default":
354 self.config['of_thread'] = ofc_thread
355
356 ofcs_threads[ofc_uuid] = ofc_thread
357 self.config['ofcs_thread'] = ofcs_threads
358
359 ofcs_thread_dpid.append({dpid: ofc_thread})
360 self.config['ofcs_thread_dpid'] = ofcs_thread_dpid
361
362 def _start_ofc_default_task(self):
363 """
364 Create default ofc thread
365 """
366 if 'of_controller' not in self.config \
367 and 'of_controller_ip' not in self.config \
368 and 'of_controller_port' not in self.config \
369 and 'of_controller_dpid' not in self.config:
370 return
371
372 # OF THREAD
373 db_config = {}
374 db_config['ip'] = self.config.get('of_controller_ip')
375 db_config['port'] = self.config.get('of_controller_port')
376 db_config['dpid'] = self.config.get('of_controller_dpid')
377 db_config['type'] = self.config.get('of_controller')
378 db_config['user'] = self.config.get('of_user')
379 db_config['password'] = self.config.get('of_password')
380
381 # create connector to the openflow controller
382 # load other parameters starting by of_ from config dict in a temporal dict
383
384 of_conn = self._load_of_module(db_config)
385 # create openflow thread
386 self._create_ofc_task("Default", db_config['dpid'], of_conn)
387
388 def _load_of_module(self, db_config):
389 """
390 import python module for each SDN controller supported
mirabalf9a1a8d2017-03-15 12:42:27 +0100391 :param db_config: SDN dn information
mirabal580435e2017-03-01 16:17:10 +0100392 :return: Module
393 """
394 if not db_config:
395 raise ovimException("No module found it", HTTP_Internal_Server_Error)
396
397 module_info = None
398
399 try:
400 if self.of_test_mode:
mirabal6c600652017-03-16 17:22:57 +0100401 return openflow_conn.OfTestConnector({"name": db_config['type'],
402 "dpid": db_config['dpid'],
403 "of_debug": self.config['log_level_of']})
mirabal580435e2017-03-01 16:17:10 +0100404 temp_dict = {}
405
406 if db_config:
407 temp_dict['of_ip'] = db_config['ip']
408 temp_dict['of_port'] = db_config['port']
409 temp_dict['of_dpid'] = db_config['dpid']
410 temp_dict['of_controller'] = db_config['type']
montesmorenoba1862b2017-04-06 10:07:44 +0000411 temp_dict['of_user'] = db_config.get('user')
412 temp_dict['of_password'] = db_config.get('password')
mirabal580435e2017-03-01 16:17:10 +0100413
414 temp_dict['of_debug'] = self.config['log_level_of']
415
416 if temp_dict['of_controller'] == 'opendaylight':
417 module = "ODL"
418 else:
419 module = temp_dict['of_controller']
420
421 if module not in ovim.of_module:
garciadeblas7fa5a652017-04-26 17:55:43 +0200422 try:
423 pkg = __import__("osm_openvim." + module)
424 of_conn_module = getattr(pkg, module)
425 ovim.of_module[module] = of_conn_module
426 self.logger.debug("Module load from {}".format("osm_openvim." + module))
427 except Exception as e:
tierno29d80242017-04-25 18:07:08 +0200428 self.logger.error("Cannot open openflow controller module of type '%s'", module)
429 raise ovimException("Cannot open openflow controller of type module '{}'"
430 "Revise it is installed".format(module),
431 HTTP_Internal_Server_Error)
mirabal580435e2017-03-01 16:17:10 +0100432 else:
433 of_conn_module = ovim.of_module[module]
tierno29d80242017-04-25 18:07:08 +0200434 return of_conn_module.OF_conn(temp_dict)
435 except Exception as e:
436 self.logger.error("Cannot open the Openflow controller '%s': %s", type(e).__name__, str(e))
437 raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e).__name__, str(e)),
mirabal580435e2017-03-01 16:17:10 +0100438 HTTP_Internal_Server_Error)
439
440 def _create_ofc_thread(self, of_conn, ofc_uuid="Default"):
441 """
442 Create and launch a of thread
443 :return: thread obj
444 """
445 # create openflow thread
446
montesmoreno92827552017-03-30 13:24:17 +0200447 #if 'of_controller_nets_with_same_vlan' in self.config:
448 # ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
449 #else:
450 # ofc_net_same_vlan = False
451 ofc_net_same_vlan = False
mirabal580435e2017-03-01 16:17:10 +0100452
tiernoe0c28c12017-05-04 18:44:40 +0200453 thread = oft.openflow_thread(ofc_uuid, of_conn, of_test=self.of_test_mode, db=self.config["db"],
454 db_lock=self.config["db_lock"],
455 pmp_with_same_vlan=ofc_net_same_vlan,
456 logger_name=self.logger_name + ".ofc." + ofc_uuid,
457 debug=self.config.get('log_level_of'))
mirabal580435e2017-03-01 16:17:10 +0100458 #r, c = thread.OF_connector.obtain_port_correspondence()
459 #if r < 0:
460 # raise ovimException("Cannot get openflow information %s", c)
461 thread.start()
462 return thread
463
tierno57f7bda2017-02-09 12:01:55 +0100464 def stop_service(self):
465 threads = self.config.get('host_threads', {})
466 if 'of_thread' in self.config:
467 threads['of'] = (self.config['of_thread'])
mirabal580435e2017-03-01 16:17:10 +0100468 if 'ofcs_thread' in self.config:
469 ofcs_thread = self.config['ofcs_thread']
470 for ofc in ofcs_thread:
471 threads[ofc] = ofcs_thread[ofc]
472
tierno57f7bda2017-02-09 12:01:55 +0100473 if 'dhcp_thread' in self.config:
474 threads['dhcp'] = (self.config['dhcp_thread'])
475
tiernoa6933042017-05-24 16:54:33 +0200476 for thread_id, thread in threads.items():
477 if thread_id == 'openvim_controller':
478 continue
tierno57f7bda2017-02-09 12:01:55 +0100479 thread.insert_task("exit")
tiernoa6933042017-05-24 16:54:33 +0200480 for thread_id, thread in threads.items():
481 if thread_id == 'openvim_controller':
482 continue
tierno57f7bda2017-02-09 12:01:55 +0100483 thread.join()
tierno57f7bda2017-02-09 12:01:55 +0100484
mirabal9e194592017-02-17 11:03:25 +0100485 def get_networks(self, columns=None, db_filter={}, limit=None):
mirabal65ba8f82017-02-15 12:36:33 +0100486 """
487 Retreive networks available
mirabale9f6f1a2017-02-16 17:57:35 +0100488 :param columns: List with select query parameters
mirabal9e194592017-02-17 11:03:25 +0100489 :param db_filter: List with where query parameters
mirabale9f6f1a2017-02-16 17:57:35 +0100490 :param limit: Query limit result
mirabal65ba8f82017-02-15 12:36:33 +0100491 :return:
492 """
mirabal9e194592017-02-17 11:03:25 +0100493 result, content = self.db.get_table(SELECT=columns, FROM='nets', WHERE=db_filter, LIMIT=limit)
mirabal65ba8f82017-02-15 12:36:33 +0100494
495 if result < 0:
496 raise ovimException(str(content), -result)
497
498 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
499
500 return content
501
mirabal9e194592017-02-17 11:03:25 +0100502 def show_network(self, network_id, db_filter={}):
mirabal65ba8f82017-02-15 12:36:33 +0100503 """
mirabale9f6f1a2017-02-16 17:57:35 +0100504 Get network from DB by id
505 :param network_id: net Id
mirabal9e194592017-02-17 11:03:25 +0100506 :param db_filter: List with where query parameters
mirabal65ba8f82017-02-15 12:36:33 +0100507 :return:
508 """
509 # obtain data
mirabale9f6f1a2017-02-16 17:57:35 +0100510 if not network_id:
511 raise ovimException("Not network id was not found")
mirabal9e194592017-02-17 11:03:25 +0100512 db_filter['uuid'] = network_id
mirabal65ba8f82017-02-15 12:36:33 +0100513
mirabal9e194592017-02-17 11:03:25 +0100514 result, content = self.db.get_table(FROM='nets', WHERE=db_filter, LIMIT=100)
mirabal65ba8f82017-02-15 12:36:33 +0100515
516 if result < 0:
517 raise ovimException(str(content), -result)
518 elif result == 0:
mirabale9f6f1a2017-02-16 17:57:35 +0100519 raise ovimException("show_network network '%s' not found" % network_id, -result)
mirabal65ba8f82017-02-15 12:36:33 +0100520 else:
521 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
mirabale9f6f1a2017-02-16 17:57:35 +0100522 # get ports from DB
mirabal65ba8f82017-02-15 12:36:33 +0100523 result, ports = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
mirabale9f6f1a2017-02-16 17:57:35 +0100524 WHERE={'net_id': network_id}, LIMIT=100)
mirabal65ba8f82017-02-15 12:36:33 +0100525 if len(ports) > 0:
526 content[0]['ports'] = ports
mirabal65ba8f82017-02-15 12:36:33 +0100527
mirabale9f6f1a2017-02-16 17:57:35 +0100528 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
529 return content[0]
530
531 def new_network(self, network):
mirabal65ba8f82017-02-15 12:36:33 +0100532 """
mirabale9f6f1a2017-02-16 17:57:35 +0100533 Create a net in DB
mirabal65ba8f82017-02-15 12:36:33 +0100534 :return:
535 """
536 tenant_id = network.get('tenant_id')
537
538 if tenant_id:
539 result, _ = self.db.get_table(FROM='tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id, "enabled": True})
540 if result <= 0:
541 raise ovimException("set_network error, no tenant founded", -result)
542
543 bridge_net = None
544 # check valid params
545 net_provider = network.get('provider')
546 net_type = network.get('type')
mirabal65ba8f82017-02-15 12:36:33 +0100547 net_vlan = network.get("vlan")
548 net_bind_net = network.get("bind_net")
549 net_bind_type = network.get("bind_type")
tiernoa290d8f2017-05-03 17:42:52 +0200550 net_region = network.get("region")
mirabal65ba8f82017-02-15 12:36:33 +0100551 name = network["name"]
552
553 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
554 vlan_index = name.rfind(":")
555 if not net_bind_net and not net_bind_type and vlan_index > 1:
556 try:
557 vlan_tag = int(name[vlan_index + 1:])
558 if not vlan_tag and vlan_tag < 4096:
559 net_bind_net = name[:vlan_index]
560 net_bind_type = "vlan:" + name[vlan_index + 1:]
561 except:
562 pass
563
564 if net_bind_net:
565 # look for a valid net
566 if self._check_valid_uuid(net_bind_net):
567 net_bind_key = "uuid"
568 else:
569 net_bind_key = "name"
570 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
571 if result < 0:
572 raise ovimException(' getting nets from db ' + content, HTTP_Internal_Server_Error)
573 elif result == 0:
574 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
575 elif result > 1:
576 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
577 network["bind_net"] = content[0]["uuid"]
578
579 if net_bind_type:
580 if net_bind_type[0:5] != "vlan:":
581 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
582 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
583 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
584 HTTP_Bad_Request)
585 network["bind_type"] = net_bind_type
586
587 if net_provider:
588 if net_provider[:9] == "openflow:":
589 if net_type:
590 if net_type != "ptp" and net_type != "data":
591 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
592 HTTP_Bad_Request)
593 else:
594 net_type = 'data'
595 else:
596 if net_type:
597 if net_type != "bridge_man" and net_type != "bridge_data":
598 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
599 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
600 else:
601 net_type = 'bridge_man'
602
603 if not net_type:
604 net_type = 'bridge_man'
605
606 if net_provider:
607 if net_provider[:7] == 'bridge:':
608 # check it is one of the pre-provisioned bridges
609 bridge_net_name = net_provider[7:]
610 for brnet in self.config['bridge_nets']:
611 if brnet[0] == bridge_net_name: # free
tierno11c45e72017-05-17 12:04:05 +0000612 if brnet[3]:
mirabal65ba8f82017-02-15 12:36:33 +0100613 raise ovimException("invalid 'provider:physical', "
614 "bridge '%s' is already used" % bridge_net_name, HTTP_Conflict)
615 bridge_net = brnet
616 net_vlan = brnet[1]
617 break
mirabale9f6f1a2017-02-16 17:57:35 +0100618 # if bridge_net==None:
619 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
620 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
621 # return
622
mirabal65ba8f82017-02-15 12:36:33 +0100623 elif self.config['network_type'] == 'bridge' and (net_type == 'bridge_data' or net_type == 'bridge_man'):
624 # look for a free precreated nets
625 for brnet in self.config['bridge_nets']:
626 if not brnet[3]: # free
627 if not bridge_net:
628 if net_type == 'bridge_man': # look for the smaller speed
629 if brnet[2] < bridge_net[2]:
630 bridge_net = brnet
631 else: # look for the larger speed
632 if brnet[2] > bridge_net[2]:
633 bridge_net = brnet
634 else:
635 bridge_net = brnet
636 net_vlan = brnet[1]
637 if not bridge_net:
638 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
639 "will overcome this limit", HTTP_Bad_Request)
640 else:
mirabale9f6f1a2017-02-16 17:57:35 +0100641 self.logger.debug("using net " + bridge_net)
mirabal65ba8f82017-02-15 12:36:33 +0100642 net_provider = "bridge:" + bridge_net[0]
643 net_vlan = bridge_net[1]
644 elif net_type == 'bridge_data' or net_type == 'bridge_man' and self.config['network_type'] == 'ovs':
645 net_provider = 'OVS'
tiernoa290d8f2017-05-03 17:42:52 +0200646 if not net_region:
647 if net_type == "data" or net_type == "ptp":
648 net_region = "__DATA__"
649 elif net_provider == "OVS":
650 net_region = "__OVS__"
mirabal65ba8f82017-02-15 12:36:33 +0100651 if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
tiernoa290d8f2017-05-03 17:42:52 +0200652 net_vlan = self.db.get_free_net_vlan(net_region)
mirabal65ba8f82017-02-15 12:36:33 +0100653 if net_vlan < 0:
654 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error)
655 if net_provider == 'OVS':
656 net_provider = 'OVS' + ":" + str(net_vlan)
657
658 network['provider'] = net_provider
659 network['type'] = net_type
660 network['vlan'] = net_vlan
tiernoa290d8f2017-05-03 17:42:52 +0200661 network['region'] = net_region
mirabal65ba8f82017-02-15 12:36:33 +0100662 dhcp_integrity = True
663 if 'enable_dhcp' in network and network['enable_dhcp']:
664 dhcp_integrity = self._check_dhcp_data_integrity(network)
mirabal6878e3f2017-06-05 09:19:26 -0500665
666 if network.get('links'):
667 network['links'] = yaml.safe_dump(network['links'], default_flow_style=True, width=256)
668 if network.get('dns'):
669 network['dns'] = yaml.safe_dump(network['dns'], default_flow_style=True, width=256)
670 if network.get('routes'):
671 network['routes'] = yaml.safe_dump(network['routes'], default_flow_style=True, width=256)
mirabal65ba8f82017-02-15 12:36:33 +0100672
673 result, content = self.db.new_row('nets', network, True, True)
674
675 if result >= 0 and dhcp_integrity:
676 if bridge_net:
677 bridge_net[3] = content
678 if self.config.get("dhcp_server") and self.config['network_type'] == 'bridge':
679 if network["name"] in self.config["dhcp_server"].get("nets", ()):
680 self.config["dhcp_nets"].append(content)
mirabale9f6f1a2017-02-16 17:57:35 +0100681 self.logger.debug("dhcp_server: add new net", content)
tierno11c45e72017-05-17 12:04:05 +0000682 elif bridge_net and bridge_net[0] in self.config["dhcp_server"].get("bridge_ifaces", ()):
mirabal65ba8f82017-02-15 12:36:33 +0100683 self.config["dhcp_nets"].append(content)
mirabale9f6f1a2017-02-16 17:57:35 +0100684 self.logger.debug("dhcp_server: add new net", content, content)
mirabal65ba8f82017-02-15 12:36:33 +0100685 return content
686 else:
mirabal65ba8f82017-02-15 12:36:33 +0100687 raise ovimException("Error posting network", HTTP_Internal_Server_Error)
mirabale9f6f1a2017-02-16 17:57:35 +0100688# TODO kei change update->edit
mirabal65ba8f82017-02-15 12:36:33 +0100689
mirabale9f6f1a2017-02-16 17:57:35 +0100690 def edit_network(self, network_id, network):
mirabal65ba8f82017-02-15 12:36:33 +0100691 """
mirabale9f6f1a2017-02-16 17:57:35 +0100692 Update entwork data byt id
mirabal65ba8f82017-02-15 12:36:33 +0100693 :return:
694 """
mirabale9f6f1a2017-02-16 17:57:35 +0100695 # Look for the previous data
696 where_ = {'uuid': network_id}
697 result, network_old = self.db.get_table(FROM='nets', WHERE=where_)
698 if result < 0:
699 raise ovimException("Error updating network %s" % network_old, HTTP_Internal_Server_Error)
700 elif result == 0:
701 raise ovimException('network %s not found' % network_id, HTTP_Not_Found)
702 # get ports
703 nbports, content = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
704 WHERE={'net_id': network_id}, LIMIT=100)
705 if result < 0:
706 raise ovimException("http_put_network_id error %d %s" % (result, network_old), HTTP_Internal_Server_Error)
707 if nbports > 0:
708 if 'type' in network and network['type'] != network_old[0]['type']:
709 raise ovimException("Can not change type of network while having ports attached",
710 HTTP_Method_Not_Allowed)
711 if 'vlan' in network and network['vlan'] != network_old[0]['vlan']:
712 raise ovimException("Can not change vlan of network while having ports attached",
713 HTTP_Method_Not_Allowed)
mirabal65ba8f82017-02-15 12:36:33 +0100714
mirabale9f6f1a2017-02-16 17:57:35 +0100715 # check valid params
716 net_provider = network.get('provider', network_old[0]['provider'])
717 net_type = network.get('type', network_old[0]['type'])
718 net_bind_net = network.get("bind_net")
719 net_bind_type = network.get("bind_type")
720 if net_bind_net:
721 # look for a valid net
722 if self._check_valid_uuid(net_bind_net):
723 net_bind_key = "uuid"
724 else:
725 net_bind_key = "name"
726 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
727 if result < 0:
728 raise ovimException('Getting nets from db ' + content, HTTP_Internal_Server_Error)
729 elif result == 0:
730 raise ovimException("bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
731 elif result > 1:
732 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net),
733 HTTP_Bad_Request)
734 network["bind_net"] = content[0]["uuid"]
735 if net_bind_type:
736 if net_bind_type[0:5] != "vlan:":
737 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
738 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
739 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
740 HTTP_Bad_Request)
741 if net_provider:
742 if net_provider[:9] == "openflow:":
743 if net_type != "ptp" and net_type != "data":
744 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request)
745 else:
746 if net_type != "bridge_man" and net_type != "bridge_data":
747 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
748 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
mirabal65ba8f82017-02-15 12:36:33 +0100749
mirabale9f6f1a2017-02-16 17:57:35 +0100750 # insert in data base
751 result, content = self.db.update_rows('nets', network, WHERE={'uuid': network_id}, log=True)
752 if result >= 0:
753 # if result > 0 and nbports>0 and 'admin_state_up' in network
754 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
755 if result > 0:
mirabal7bbf50e2017-03-13 15:15:18 +0100756
757 try:
tiernoaa941462017-03-29 15:10:28 +0200758 if nbports:
759 self.net_update_ofc_thread(network_id)
mirabal7bbf50e2017-03-13 15:15:18 +0100760 except ovimException as e:
761 raise ovimException("Error while launching openflow rules in network '{}' {}"
762 .format(network_id, str(e)), HTTP_Internal_Server_Error)
763 except Exception as e:
764 raise ovimException("Error while launching openflow rules in network '{}' {}"
765 .format(network_id, str(e)), HTTP_Internal_Server_Error)
766
mirabale9f6f1a2017-02-16 17:57:35 +0100767 if self.config.get("dhcp_server"):
768 if network_id in self.config["dhcp_nets"]:
769 self.config["dhcp_nets"].remove(network_id)
mirabal7bbf50e2017-03-13 15:15:18 +0100770 if network.get("name", network_old[0]["name"]) in self.config["dhcp_server"].get("nets", ()):
mirabale9f6f1a2017-02-16 17:57:35 +0100771 self.config["dhcp_nets"].append(network_id)
772 else:
mirabal7bbf50e2017-03-13 15:15:18 +0100773 net_bind = network.get("bind_type", network_old[0]["bind_type"])
774 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 +0100775 "bridge_ifaces", ()):
776 self.config["dhcp_nets"].append(network_id)
777 return network_id
mirabal65ba8f82017-02-15 12:36:33 +0100778 else:
mirabale9f6f1a2017-02-16 17:57:35 +0100779 raise ovimException(content, -result)
mirabal65ba8f82017-02-15 12:36:33 +0100780
mirabale9f6f1a2017-02-16 17:57:35 +0100781 def delete_network(self, network_id):
mirabal9e194592017-02-17 11:03:25 +0100782 """
783 Delete network by network id
784 :param network_id: network id
785 :return:
786 """
mirabale9f6f1a2017-02-16 17:57:35 +0100787
788 # delete from the data base
789 result, content = self.db.delete_row('nets', network_id)
790
791 if result == 0:
792 raise ovimException("Network %s not found " % network_id, HTTP_Not_Found)
793 elif result > 0:
794 for brnet in self.config['bridge_nets']:
795 if brnet[3] == network_id:
796 brnet[3] = None
797 break
798 if self.config.get("dhcp_server") and network_id in self.config["dhcp_nets"]:
799 self.config["dhcp_nets"].remove(network_id)
800 return content
801 else:
tierno11c45e72017-05-17 12:04:05 +0000802 raise ovimException("Error deleting network '{}': {}".format(network_id, content), -result)
mirabal65ba8f82017-02-15 12:36:33 +0100803
804 def get_openflow_rules(self, network_id=None):
805 """
806 Get openflow id from DB
807 :param network_id: Network id, if none all networks will be retrieved
808 :return: Return a list with Openflow rules per net
809 """
810 # ignore input data
811 if not network_id:
812 where_ = {}
813 else:
814 where_ = {"net_id": network_id}
mirabal65ba8f82017-02-15 12:36:33 +0100815 result, content = self.db.get_table(
mirabalf9a1a8d2017-03-15 12:42:27 +0100816 SELECT=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
mirabal65ba8f82017-02-15 12:36:33 +0100817 WHERE=where_, FROM='of_flows')
818
819 if result < 0:
820 raise ovimException(str(content), -result)
821 return content
822
mirabale9f6f1a2017-02-16 17:57:35 +0100823 def edit_openflow_rules(self, network_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100824
825 """
826 To make actions over the net. The action is to reinstall the openflow rules
827 network_id can be 'all'
828 :param network_id: Network id, if none all networks will be retrieved
829 :return : Number of nets updated
830 """
831
832 # ignore input data
833 if not network_id:
834 where_ = {}
835 else:
836 where_ = {"uuid": network_id}
837 result, content = self.db.get_table(SELECT=("uuid", "type"), WHERE=where_, FROM='nets')
838
839 if result < 0:
840 raise ovimException(str(content), -result)
841
842 for net in content:
843 if net["type"] != "ptp" and net["type"] != "data":
844 result -= 1
845 continue
mirabal7bbf50e2017-03-13 15:15:18 +0100846
847 try:
848 self.net_update_ofc_thread(net['uuid'])
849 except ovimException as e:
850 raise ovimException("Error updating network'{}' {}".format(net['uuid'], str(e)),
851 HTTP_Internal_Server_Error)
852 except Exception as e:
853 raise ovimException("Error updating network '{}' {}".format(net['uuid'], str(e)),
854 HTTP_Internal_Server_Error)
855
mirabal65ba8f82017-02-15 12:36:33 +0100856 return result
857
mirabalf9a1a8d2017-03-15 12:42:27 +0100858 def delete_openflow_rules(self, ofc_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100859 """
860 To make actions over the net. The action is to delete ALL openflow rules
861 :return: return operation result
862 """
mirabalf9a1a8d2017-03-15 12:42:27 +0100863
864 if not ofc_id:
865 if 'Default' in self.config['ofcs_thread']:
866 r, c = self.config['ofcs_thread']['Default'].insert_task("clear-all")
867 else:
868 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
869
870 elif ofc_id in self.config['ofcs_thread']:
871 r, c = self.config['ofcs_thread'][ofc_id].insert_task("clear-all")
872
873 # ignore input data
874 if r < 0:
875 raise ovimException(str(c), -r)
876 else:
877 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
mirabal65ba8f82017-02-15 12:36:33 +0100878 return r
879
mirabalf9a1a8d2017-03-15 12:42:27 +0100880 def get_openflow_ports(self, ofc_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100881 """
882 Obtain switch ports names of openflow controller
883 :return: Return flow ports in DB
884 """
mirabalf9a1a8d2017-03-15 12:42:27 +0100885 if not ofc_id:
886 if 'Default' in self.config['ofcs_thread']:
887 conn = self.config['ofcs_thread']['Default'].OF_connector
888 else:
889 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
890
tierno11c45e72017-05-17 12:04:05 +0000891 elif ofc_id in self.config['ofcs_thread']:
mirabalf9a1a8d2017-03-15 12:42:27 +0100892 conn = self.config['ofcs_thread'][ofc_id].OF_connector
893 else:
894 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
895 return conn.pp2ofi
tierno57f7bda2017-02-09 12:01:55 +0100896
897 def get_ports(self, columns=None, filter={}, limit=None):
898 # result, content = my.db.get_ports(where_)
899 result, content = self.db.get_table(SELECT=columns, WHERE=filter, FROM='ports', LIMIT=limit)
900 if result < 0:
901 self.logger.error("http_get_ports Error %d %s", result, content)
902 raise ovimException(str(content), -result)
903 else:
904 convert_boolean(content, ('admin_state_up',))
905 return content
906
tierno57f7bda2017-02-09 12:01:55 +0100907 def new_port(self, port_data):
908 port_data['type'] = 'external'
909 if port_data.get('net_id'):
910 # check that new net has the correct type
911 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
912 if result < 0:
913 raise ovimException(str(new_net), -result)
914 # insert in data base
915 result, uuid = self.db.new_row('ports', port_data, True, True)
916 if result > 0:
917 if 'net_id' in port_data:
mirabal7bbf50e2017-03-13 15:15:18 +0100918 try:
919 self.net_update_ofc_thread(port_data['net_id'])
920 except ovimException 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 except Exception as e:
924 raise ovimException("Cannot insert a task for updating network '{}' {}"
925 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
926
tierno57f7bda2017-02-09 12:01:55 +0100927 return uuid
928 else:
929 raise ovimException(str(uuid), -result)
930
mirabal37829452017-03-09 14:41:21 +0100931 def new_external_port(self, port_data):
932 """
933 Create new external port and check port mapping correspondence
934 :param port_data: port_data = {
935 'region': 'datacenter region',
936 'compute_node': 'compute node id',
937 'pci': 'pci port address',
938 'vlan': 'net vlan',
939 'net_id': 'net id',
940 'tenant_id': 'tenant id',
941 'mac': 'switch mac',
942 'name': 'port name'
943 'ip_address': 'ip address - optional'}
944 :return:
945 """
946
947 port_data['type'] = 'external'
948
949 if port_data.get('net_id'):
950 # check that new net has the correct type
951 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
952 if result < 0:
953 raise ovimException(str(new_net), -result)
954 # insert in data base
955 db_filter = {}
956
957 if port_data.get('region'):
958 db_filter['region'] = port_data['region']
959 if port_data.get('pci'):
960 db_filter['pci'] = port_data['pci']
961 if port_data.get('compute_node'):
962 db_filter['compute_node'] = port_data['compute_node']
963
964 columns = ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
965 port_mapping_data = self.get_of_port_mappings(columns, db_filter)
966
967 if not len(port_mapping_data):
tierno16007502017-03-27 16:48:32 +0200968 raise ovimException("No port mapping founded for '{}'".format(str(db_filter)),
mirabal37829452017-03-09 14:41:21 +0100969 HTTP_Not_Found)
970 elif len(port_mapping_data) > 1:
971 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
972 HTTP_Conflict)
973
974 port_data['ofc_id'] = port_mapping_data[0]['ofc_id']
975 port_data['switch_dpid'] = port_mapping_data[0]['switch_dpid']
976 port_data['switch_port'] = port_mapping_data[0]['switch_port']
977 port_data['switch_mac'] = port_mapping_data[0]['switch_mac']
978
979 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
montesmoreno275b1992017-03-28 15:45:02 +0200980 if 'region' in port_data:
981 del port_data['region']
982 if 'pci' in port_data:
983 del port_data['pci']
984 if 'compute_node' in port_data:
985 del port_data['compute_node']
mirabal37829452017-03-09 14:41:21 +0100986
987 result, uuid = self.db.new_row('ports', port_data, True, True)
988 if result > 0:
mirabal7bbf50e2017-03-13 15:15:18 +0100989 try:
990 self.net_update_ofc_thread(port_data['net_id'], port_data['ofc_id'])
991 except ovimException as e:
992 raise ovimException("Cannot insert a task for updating network '{}' {}".
993 format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
994 except Exception as e:
995 raise ovimException("Cannot insert a task for updating network '{}' {}"
996 .format(port_data['net_id'], e), HTTP_Internal_Server_Error)
mirabal37829452017-03-09 14:41:21 +0100997 return uuid
998 else:
999 raise ovimException(str(uuid), -result)
1000
tiernoaa941462017-03-29 15:10:28 +02001001 def net_update_ofc_thread(self, net_id, ofc_id=None, switch_dpid=None):
mirabal7bbf50e2017-03-13 15:15:18 +01001002 """
1003 Insert a update net task by net id or ofc_id for each ofc thread
1004 :param net_id: network id
1005 :param ofc_id: openflow controller id
tiernoaa941462017-03-29 15:10:28 +02001006 :param switch_dpid: switch dpid
mirabal7bbf50e2017-03-13 15:15:18 +01001007 :return:
1008 """
1009 if not net_id:
1010 raise ovimException("No net_id received", HTTP_Internal_Server_Error)
1011
mirabal7bbf50e2017-03-13 15:15:18 +01001012 r = -1
1013 c = 'No valid ofc_id or switch_dpid received'
1014
1015 if not ofc_id:
1016 ports = self.get_ports(filter={"net_id": net_id})
1017 for port in ports:
1018 port_ofc_id = port.get('ofc_id', None)
1019 if port_ofc_id:
1020 ofc_id = port['ofc_id']
1021 switch_dpid = port['switch_dpid']
1022 break
tiernoaa941462017-03-29 15:10:28 +02001023 #TODO if not ofc_id: look at database table ofcs
1024
mirabal7bbf50e2017-03-13 15:15:18 +01001025
1026 # If no ofc_id found it, default ofc_id is used.
1027 if not ofc_id and not switch_dpid:
1028 ofc_id = "Default"
1029
1030 if ofc_id and ofc_id in self.config['ofcs_thread']:
1031 r, c = self.config['ofcs_thread'][ofc_id].insert_task("update-net", net_id)
1032 elif switch_dpid:
1033
1034 ofcs_dpid_list = self.config['ofcs_thread_dpid']
1035 for ofc_t in ofcs_dpid_list:
1036 if switch_dpid in ofc_t:
1037 r, c = ofc_t[switch_dpid].insert_task("update-net", net_id)
1038
1039 if r < 0:
tierno82232582017-03-15 18:09:16 +01001040 message = "Cannot insert a task for updating network '{}', {}".format(net_id, c)
mirabal7bbf50e2017-03-13 15:15:18 +01001041 self.logger.error(message)
1042 raise ovimException(message, HTTP_Internal_Server_Error)
1043
tierno57f7bda2017-02-09 12:01:55 +01001044 def delete_port(self, port_id):
1045 # Look for the previous port data
1046 result, ports = self.db.get_table(WHERE={'uuid': port_id, "type": "external"}, FROM='ports')
1047 if result < 0:
1048 raise ovimException("Cannot get port info from database: {}".format(ports), http_code=-result)
1049 # delete from the data base
1050 result, content = self.db.delete_row('ports', port_id)
1051 if result == 0:
1052 raise ovimException("External port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1053 elif result < 0:
1054 raise ovimException("Cannot delete port from database: {}".format(content), http_code=-result)
1055 # update network
1056 network = ports[0].get('net_id', None)
1057 if network:
1058 # change of net.
mirabal7bbf50e2017-03-13 15:15:18 +01001059
1060 try:
tiernoaa941462017-03-29 15:10:28 +02001061 self.net_update_ofc_thread(network, ofc_id=ports[0]["ofc_id"], switch_dpid=ports[0]["switch_dpid"])
mirabal7bbf50e2017-03-13 15:15:18 +01001062 except ovimException as e:
1063 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
1064 HTTP_Internal_Server_Error)
1065 except Exception as e:
1066 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
1067 HTTP_Internal_Server_Error)
1068
tierno57f7bda2017-02-09 12:01:55 +01001069 return content
1070
tierno57f7bda2017-02-09 12:01:55 +01001071 def edit_port(self, port_id, port_data, admin=True):
1072 # Look for the previous port data
1073 result, content = self.db.get_table(FROM="ports", WHERE={'uuid': port_id})
1074 if result < 0:
1075 raise ovimException("Cannot get port info from database: {}".format(content), http_code=-result)
1076 elif result == 0:
1077 raise ovimException("Port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1078 port = content[0]
1079 nets = []
1080 host_id = None
1081 result = 1
1082 if 'net_id' in port_data:
1083 # change of net.
1084 old_net = port.get('net_id', None)
1085 new_net = port_data['net_id']
1086 if old_net != new_net:
1087
1088 if new_net:
1089 nets.append(new_net) # put first the new net, so that new openflow rules are created before removing the old ones
1090 if old_net:
1091 nets.append(old_net)
1092 if port['type'] == 'instance:bridge' or port['type'] == 'instance:ovs':
1093 raise ovimException("bridge interfaces cannot be attached to a different net", http_code=HTTP_Forbidden)
1094 elif port['type'] == 'external' and not admin:
1095 raise ovimException("Needed admin privileges",http_code=HTTP_Unauthorized)
1096 if new_net:
1097 # check that new net has the correct type
1098 result, new_net_dict = self.db.check_target_net(new_net, None, port['type'])
1099 if result < 0:
1100 raise ovimException("Error {}".format(new_net_dict), http_code=HTTP_Conflict)
1101 # change VLAN for SR-IOV ports
1102 if result >= 0 and port["type"] == "instance:data" and port["model"] == "VF": # TODO consider also VFnotShared
1103 if new_net:
1104 port_data["vlan"] = None
1105 else:
1106 port_data["vlan"] = new_net_dict["vlan"]
1107 # get host where this VM is allocated
1108 result, content = self.db.get_table(FROM="instances", WHERE={"uuid": port["instance_id"]})
1109 if result > 0:
1110 host_id = content[0]["host_id"]
1111
1112 # insert in data base
1113 if result >= 0:
1114 result, content = self.db.update_rows('ports', port_data, WHERE={'uuid': port_id}, log=False)
tiernoaa941462017-03-29 15:10:28 +02001115 port.update(port_data)
tierno57f7bda2017-02-09 12:01:55 +01001116
1117 # Insert task to complete actions
1118 if result > 0:
1119 for net_id in nets:
mirabal7bbf50e2017-03-13 15:15:18 +01001120 try:
tiernoaa941462017-03-29 15:10:28 +02001121 self.net_update_ofc_thread(net_id, port["ofc_id"], switch_dpid=port["switch_dpid"])
mirabal7bbf50e2017-03-13 15:15:18 +01001122 except ovimException as e:
1123 raise ovimException("Error updating network'{}' {}".format(net_id, str(e)),
1124 HTTP_Internal_Server_Error)
1125 except Exception as e:
1126 raise ovimException("Error updating network '{}' {}".format(net_id, str(e)),
1127 HTTP_Internal_Server_Error)
1128
tierno57f7bda2017-02-09 12:01:55 +01001129 if host_id:
1130 r, v = self.config['host_threads'][host_id].insert_task("edit-iface", port_id, old_net, new_net)
1131 if r < 0:
1132 self.logger.error("Error updating network '{}' {}".format(r,v))
1133 # TODO Do something if fails
1134 if result >= 0:
1135 return port_id
1136 else:
1137 raise ovimException("Error {}".format(content), http_code=-result)
mirabalb716ac52017-02-10 14:47:53 +01001138
mirabal9e194592017-02-17 11:03:25 +01001139 def new_of_controller(self, ofc_data):
1140 """
1141 Create a new openflow controller into DB
1142 :param ofc_data: Dict openflow controller data
1143 :return: openflow controller dpid
1144 """
1145
mirabal580435e2017-03-01 16:17:10 +01001146 result, ofc_uuid = self.db.new_row('ofcs', ofc_data, True, True)
mirabal9e194592017-02-17 11:03:25 +01001147 if result < 0:
mirabal580435e2017-03-01 16:17:10 +01001148 raise ovimException("New ofc Error %s" % ofc_uuid, HTTP_Internal_Server_Error)
1149
1150 ofc_data['uuid'] = ofc_uuid
1151 of_conn = self._load_of_module(ofc_data)
1152 self._create_ofc_task(ofc_uuid, ofc_data['dpid'], of_conn)
1153
1154 return ofc_uuid
mirabal9e194592017-02-17 11:03:25 +01001155
1156 def edit_of_controller(self, of_id, ofc_data):
1157 """
1158 Edit an openflow controller entry from DB
1159 :return:
1160 """
1161 if not ofc_data:
1162 raise ovimException("No data received during uptade OF contorller", http_code=HTTP_Internal_Server_Error)
1163
1164 old_of_controller = self.show_of_controller(of_id)
1165
1166 if old_of_controller:
1167 result, content = self.db.update_rows('ofcs', ofc_data, WHERE={'uuid': of_id}, log=False)
1168 if result >= 0:
1169 return ofc_data
1170 else:
1171 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1172 http_code=-result)
1173 else:
1174 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1175 http_code=HTTP_Internal_Server_Error)
1176
1177 def delete_of_controller(self, of_id):
1178 """
1179 Delete an openflow controller from DB.
1180 :param of_id: openflow controller dpid
1181 :return:
1182 """
1183
mirabal580435e2017-03-01 16:17:10 +01001184 ofc = self.show_of_controller(of_id)
1185
Pablo Montes Moreno5b6f7492017-03-02 16:18:36 +01001186 result, content = self.db.delete_row("ofcs", of_id)
mirabal9e194592017-02-17 11:03:25 +01001187 if result < 0:
1188 raise ovimException("Cannot delete ofc from database: {}".format(content), http_code=-result)
1189 elif result == 0:
1190 raise ovimException("ofc {} not found ".format(content), http_code=HTTP_Not_Found)
mirabal580435e2017-03-01 16:17:10 +01001191
1192 ofc_thread = self.config['ofcs_thread'][of_id]
1193 del self.config['ofcs_thread'][of_id]
1194 for ofc_th in self.config['ofcs_thread_dpid']:
1195 if ofc['dpid'] in ofc_th:
1196 self.config['ofcs_thread_dpid'].remove(ofc_th)
1197
1198 ofc_thread.insert_task("exit")
1199 #ofc_thread.join()
1200
mirabal9e194592017-02-17 11:03:25 +01001201 return content
1202
1203 def show_of_controller(self, uuid):
1204 """
1205 Show an openflow controller by dpid from DB.
1206 :param db_filter: List with where query parameters
1207 :return:
1208 """
1209
1210 result, content = self.db.get_table(FROM='ofcs', WHERE={"uuid": uuid}, LIMIT=100)
1211
1212 if result == 0:
1213 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid),
1214 http_code=HTTP_Not_Found)
1215 elif result < 0:
1216 raise ovimException("Openflow controller with uuid '{}' error".format(uuid),
1217 http_code=HTTP_Internal_Server_Error)
Pablo Montes Moreno5b6f7492017-03-02 16:18:36 +01001218 return content[0]
mirabal9e194592017-02-17 11:03:25 +01001219
mirabalfbfb7972017-02-27 17:36:17 +01001220 def get_of_controllers(self, columns=None, db_filter={}, limit=None):
mirabal9e194592017-02-17 11:03:25 +01001221 """
1222 Show an openflow controllers from DB.
1223 :param columns: List with SELECT query parameters
1224 :param db_filter: List with where query parameters
mirabalfbfb7972017-02-27 17:36:17 +01001225 :param limit: result Limit
mirabal9e194592017-02-17 11:03:25 +01001226 :return:
1227 """
mirabalfbfb7972017-02-27 17:36:17 +01001228 result, content = self.db.get_table(SELECT=columns, FROM='ofcs', WHERE=db_filter, LIMIT=limit)
mirabal9e194592017-02-17 11:03:25 +01001229
1230 if result < 0:
1231 raise ovimException(str(content), -result)
1232
1233 return content
1234
mirabalfbfb7972017-02-27 17:36:17 +01001235 def get_tenants(self, columns=None, db_filter={}, limit=None):
1236 """
1237 Retrieve tenant list from DB
1238 :param columns: List with SELECT query parameters
1239 :param db_filter: List with where query parameters
1240 :param limit: result limit
1241 :return:
1242 """
1243 result, content = self.db.get_table(FROM='tenants', SELECT=columns, WHERE=db_filter, LIMIT=limit)
1244 if result < 0:
1245 raise ovimException('get_tenatns Error {}'.format(str(content)), -result)
1246 else:
1247 convert_boolean(content, ('enabled',))
1248 return content
1249
1250 def show_tenant_id(self, tenant_id):
1251 """
1252 Get tenant from DB by id
1253 :param tenant_id: tenant id
1254 :return:
1255 """
1256 result, content = self.db.get_table(FROM='tenants', SELECT=('uuid', 'name', 'description', 'enabled'),
1257 WHERE={"uuid": tenant_id})
1258 if result < 0:
1259 raise ovimException(str(content), -result)
1260 elif result == 0:
1261 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1262 else:
1263 convert_boolean(content, ('enabled',))
1264 return content[0]
1265
1266 def new_tentant(self, tenant):
1267 """
1268 Create a tenant and store in DB
1269 :param tenant: Dictionary with tenant data
1270 :return: the uuid of created tenant. Raise exception upon error
1271 """
1272
1273 # insert in data base
1274 result, tenant_uuid = self.db.new_tenant(tenant)
1275
1276 if result >= 0:
1277 return tenant_uuid
1278 else:
1279 raise ovimException(str(tenant_uuid), -result)
1280
1281 def delete_tentant(self, tenant_id):
1282 """
1283 Delete a tenant from the database.
1284 :param tenant_id: Tenant id
1285 :return: delete tenant id
1286 """
1287
1288 # check permissions
1289 r, tenants_flavors = self.db.get_table(FROM='tenants_flavors', SELECT=('flavor_id', 'tenant_id'),
1290 WHERE={'tenant_id': tenant_id})
1291 if r <= 0:
1292 tenants_flavors = ()
1293 r, tenants_images = self.db.get_table(FROM='tenants_images', SELECT=('image_id', 'tenant_id'),
1294 WHERE={'tenant_id': tenant_id})
1295 if r <= 0:
1296 tenants_images = ()
1297
1298 result, content = self.db.delete_row('tenants', tenant_id)
1299 if result == 0:
1300 raise ovimException("tenant '%s' not found" % tenant_id, HTTP_Not_Found)
1301 elif result > 0:
1302 for flavor in tenants_flavors:
1303 self.db.delete_row_by_key("flavors", "uuid", flavor['flavor_id'])
1304 for image in tenants_images:
1305 self.db.delete_row_by_key("images", "uuid", image['image_id'])
1306 return content
1307 else:
1308 raise ovimException("Error deleting tenant '%s' " % tenant_id, HTTP_Internal_Server_Error)
1309
1310 def edit_tenant(self, tenant_id, tenant_data):
1311 """
1312 Update a tenant data identified by tenant id
1313 :param tenant_id: tenant id
1314 :param tenant_data: Dictionary with tenant data
1315 :return:
1316 """
1317
1318 # Look for the previous data
1319 result, tenant_data_old = self.db.get_table(FROM='tenants', WHERE={'uuid': tenant_id})
1320 if result < 0:
1321 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id, tenant_data_old),
1322 HTTP_Internal_Server_Error)
1323 elif result == 0:
1324 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1325
1326 # insert in data base
1327 result, content = self.db.update_rows('tenants', tenant_data, WHERE={'uuid': tenant_id}, log=True)
1328 if result >= 0:
1329 return content
1330 else:
1331 raise ovimException(str(content), -result)
1332
mirabal6045a9d2017-03-06 11:36:55 +01001333 def set_of_port_mapping(self, of_maps, ofc_id=None, switch_dpid=None, region=None):
1334 """
1335 Create new port mapping entry
1336 :param of_maps: List with port mapping information
1337 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1338 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1339 :param ofc_id: ofc id
1340 :param switch_dpid: switch dpid
1341 :param region: datacenter region id
1342 :return:
1343 """
1344
1345 for map in of_maps:
1346 if ofc_id:
1347 map['ofc_id'] = ofc_id
1348 if switch_dpid:
1349 map['switch_dpid'] = switch_dpid
1350 if region:
1351 map['region'] = region
1352
1353 for of_map in of_maps:
1354 result, uuid = self.db.new_row('of_port_mappings', of_map, True)
1355 if result > 0:
1356 of_map["uuid"] = uuid
1357 else:
1358 raise ovimException(str(uuid), -result)
1359 return of_maps
1360
1361 def clear_of_port_mapping(self, db_filter={}):
1362 """
1363 Clear port mapping filtering using db_filter dict
1364 :param db_filter: Parameter to filter during remove process
1365 :return:
1366 """
1367 result, content = self.db.delete_row_by_dict(FROM='of_port_mappings', WHERE=db_filter)
1368 # delete_row_by_key
1369 if result >= 0:
1370 return content
1371 else:
1372 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter)),
1373 HTTP_Internal_Server_Error)
1374
1375 def get_of_port_mappings(self, column=None, db_filter=None, db_limit=None):
1376 """
1377 Retrive port mapping from DB
1378 :param column:
1379 :param db_filter:
1380 :return:
1381 """
1382 result, content = self.db.get_table(SELECT=column, WHERE=db_filter, FROM='of_port_mappings', LIMIT=db_limit)
1383
1384 if result < 0:
1385 self.logger.error("get_of_port_mappings Error %d %s", result, content)
1386 raise ovimException(str(content), -result)
1387 else:
1388 return content
1389
mirabalb716ac52017-02-10 14:47:53 +01001390 def get_dhcp_controller(self):
1391 """
1392 Create an host_thread object for manage openvim controller and not create a thread for itself
1393 :return: dhcp_host openvim controller object
1394 """
1395
1396 if 'openvim_controller' in self.config['host_threads']:
1397 return self.config['host_threads']['openvim_controller']
1398
1399 bridge_ifaces = []
1400 controller_ip = self.config['ovs_controller_ip']
tiernoa6933042017-05-24 16:54:33 +02001401 ovs_controller_user = self.config.get('ovs_controller_user')
mirabalb716ac52017-02-10 14:47:53 +01001402
1403 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
1404 host_develop_mode = True if self.config['mode'] == 'development' else False
1405
1406 dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip,
tiernoa6933042017-05-24 16:54:33 +02001407 password=self.config.get('ovs_controller_password'),
1408 keyfile=self.config.get('ovs_controller_keyfile'),
tiernoe0c28c12017-05-04 18:44:40 +02001409 db=self.config["db"], db_lock=self.config["db_lock"], test=host_test_mode,
tiernoa6933042017-05-24 16:54:33 +02001410 image_path=self.config['host_image_path'], version=self.config['version'],
mirabalb716ac52017-02-10 14:47:53 +01001411 host_id='openvim_controller', develop_mode=host_develop_mode,
tiernoe0c28c12017-05-04 18:44:40 +02001412 develop_bridge_iface=bridge_ifaces,
1413 logger_name=self.logger_name + ".host.controller",
tiernof135eff2017-04-19 19:11:53 +02001414 debug=self.config.get('log_level_host'))
tiernoa6933042017-05-24 16:54:33 +02001415 # dhcp_host.start()
mirabalb716ac52017-02-10 14:47:53 +01001416 self.config['host_threads']['openvim_controller'] = dhcp_host
mirabal42ca0092017-06-14 05:42:30 -05001417 try:
1418 dhcp_host.check_connectivity()
1419 except Exception as e:
1420 pass
1421
mirabalb716ac52017-02-10 14:47:53 +01001422 return dhcp_host
1423
mirabal6878e3f2017-06-05 09:19:26 -05001424 def launch_dhcp_server(self, vlan, first_ip, last_ip, cidr, gateway, dns, routes):
mirabalb716ac52017-02-10 14:47:53 +01001425 """
1426 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1427 :param vlan: vlan identifier
1428 :param first_ip: First dhcp range ip
1429 :param last_ip: Last dhcp range ip
1430 :param cidr: net cidr
mirabale9f6f1a2017-02-16 17:57:35 +01001431 :param gateway: net gateway
mirabalb716ac52017-02-10 14:47:53 +01001432 :return:
1433 """
1434 ip_tools = IPNetwork(cidr)
1435 dhcp_netmask = str(ip_tools.netmask)
1436 ip_range = [first_ip, last_ip]
1437
1438 dhcp_path = self.config['ovs_controller_file_path']
1439
1440 controller_host = self.get_dhcp_controller()
mirabale16a6362017-07-10 05:45:56 -05001441
mirabal6878e3f2017-06-05 09:19:26 -05001442 # controller_host.create_linux_bridge(vlan)
1443 controller_host.create_dhcp_interfaces(vlan, first_ip, dhcp_netmask)
1444 dhcp_path = self.config['ovs_controller_file_path']
1445 controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path, gateway, dns, routes)
1446
1447 def launch_link_bridge_to_ovs(self, vlan, gateway, dhcp_cidr, links=None, routes=None):
1448 """
1449 Launch creating of connections (veth) between user bridge (link) and OVS
1450 :param vlan:
1451 :param gateway:
1452 :param links:
1453 :return:
1454 """
1455
1456 if links:
1457 controller_host = self.get_dhcp_controller()
1458 for link in links:
1459 if 'iface' in link and 'nat' not in link:
1460 controller_host.create_link_bridge_to_ovs(vlan, link['iface'])
1461 elif 'nat' in link:
1462 controller_host.create_qrouter_ovs_connection(vlan, gateway, dhcp_cidr)
1463 controller_host.create_qrouter_br_connection(vlan, dhcp_cidr, link)
1464
1465 if len(routes):
1466 controller_host.add_ns_routes(vlan, routes)
1467
1468 def delete_link_bridge_to_ovs(self, vlan, links=None):
1469 """
1470 Delete connections (veth) between user bridge (link) and OVS
1471 :param vlan:
1472 :param links:
1473 :return:
1474 """
1475 if links:
1476 controller_host = self.get_dhcp_controller()
1477
1478 for link in links:
1479 if 'iface' in link and 'nat' not in link:
1480 controller_host.remove_link_bridge_to_ovs(vlan, link['iface'])
1481 elif 'nat' in link:
1482 controller_host.delete_qrouter_connection(vlan, link['iface'])
1483
mirabalb716ac52017-02-10 14:47:53 +01001484
mirabald87877c2017-03-31 15:15:52 +02001485if __name__ == "__main__":
1486
1487 parser = argparse.ArgumentParser()
tierno46ca3a92017-04-05 19:49:24 +02001488 parser.add_argument("-v","--version", help="show ovim library version", action="store_true")
1489 parser.add_argument("--database-version", help="show required database version", action="store_true")
mirabald87877c2017-03-31 15:15:52 +02001490 args = parser.parse_args()
1491 if args.version:
1492 print ('openvimd version {} {}'.format(ovim.get_version(), ovim.get_version_date()))
1493 print ('(c) Copyright Telefonica')
tierno46ca3a92017-04-05 19:49:24 +02001494 elif args.database_version:
1495 print ('required database version: {}'.format(ovim.get_database_version()))
mirabalb716ac52017-02-10 14:47:53 +01001496