blob: e3581b74a8f19de3f0a919eeeb6b286863806499 [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$"
tiernobd15be42018-07-19 14:23:08 +020046__version__ = "0.5.28-r548"
tierno9a8846d2018-06-28 15:42:25 +020047version_date = "Jul 2018"
Paolo Lungaroni423a4082018-02-14 18:05:02 +010048database_version = 23 #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
Paolo Lungaroni423a4082018-02-14 18:05:02 +0100202 r, hosts = self.db.get_table(SELECT=('name', 'ip_name', 'user', 'uuid', 'hypervisors', 'password', 'keyfile'),
203 FROM='hosts', WHERE={'status': 'ok'}) #Unikernels extension
mirabal42ca0092017-06-14 05:42:30 -0500204 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,
Paolo Lungaroni423a4082018-02-14 18:05:02 +0100218 hypervisors=host['hypervisors'], #Unikernels extension
mirabal42ca0092017-06-14 05:42:30 -0500219 logger_name=self.logger_name + ".host." + host['name'],
220 debug=self.config.get('log_level_host'))
221
222 try:
223 thread.check_connectivity()
224 except Exception as e:
225 self.logger.critical('Error detected for compute = {} with ip = {}'
226 .format(host['name'], host['ip_name']))
mirabald48f4f92017-06-29 10:04:21 -0500227 thread.start()
mirabal42ca0092017-06-14 05:42:30 -0500228 self.config['host_threads'][host['uuid']] = thread
229
mirabal580435e2017-03-01 16:17:10 +0100230 # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge,
231 # speed in Gbit/s
232
tierno57f7bda2017-02-09 12:01:55 +0100233 self.config['dhcp_nets'] = []
234 self.config['bridge_nets'] = []
235 for bridge, vlan_speed in self.config["bridge_ifaces"].items():
mirabal580435e2017-03-01 16:17:10 +0100236 # skip 'development_bridge'
tierno57f7bda2017-02-09 12:01:55 +0100237 if self.config['mode'] == 'development' and self.config['development_bridge'] == bridge:
238 continue
239 self.config['bridge_nets'].append([bridge, vlan_speed[0], vlan_speed[1], None])
240
241 # check if this bridge is already used (present at database) for a network)
242 used_bridge_nets = []
243 for brnet in self.config['bridge_nets']:
tierno686b3952017-03-10 13:57:24 +0100244 r, nets = self.db.get_table(SELECT=('uuid',), FROM='nets', WHERE={'provider': "bridge:" + brnet[0]})
tierno57f7bda2017-02-09 12:01:55 +0100245 if r > 0:
246 brnet[3] = nets[0]['uuid']
247 used_bridge_nets.append(brnet[0])
248 if self.config.get("dhcp_server"):
249 if brnet[0] in self.config["dhcp_server"]["bridge_ifaces"]:
250 self.config['dhcp_nets'].append(nets[0]['uuid'])
251 if len(used_bridge_nets) > 0:
252 self.logger.info("found used bridge nets: " + ",".join(used_bridge_nets))
253 # get nets used by dhcp
254 if self.config.get("dhcp_server"):
255 for net in self.config["dhcp_server"].get("nets", ()):
tierno686b3952017-03-10 13:57:24 +0100256 r, nets = self.db.get_table(SELECT=('uuid',), FROM='nets', WHERE={'name': net})
tierno57f7bda2017-02-09 12:01:55 +0100257 if r > 0:
258 self.config['dhcp_nets'].append(nets[0]['uuid'])
259
mirabal580435e2017-03-01 16:17:10 +0100260 # OFC default
261 self._start_ofc_default_task()
tierno57f7bda2017-02-09 12:01:55 +0100262
mirabal580435e2017-03-01 16:17:10 +0100263 # OFC per tenant in DB
264 self._start_of_db_tasks()
tierno57f7bda2017-02-09 12:01:55 +0100265
266 # create dhcp_server thread
267 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
268 dhcp_params = self.config.get("dhcp_server")
269 if dhcp_params:
270 thread = dt.dhcp_thread(dhcp_params=dhcp_params, test=host_test_mode, dhcp_nets=self.config["dhcp_nets"],
tiernoe0c28c12017-05-04 18:44:40 +0200271 db=self.config["db"], db_lock=self.config["db_lock"],
272 logger_name=self.logger_name + ".dhcp",
tierno43044b02017-04-06 18:58:24 +0200273 debug=self.config.get('log_level_of'))
tierno57f7bda2017-02-09 12:01:55 +0100274 thread.start()
275 self.config['dhcp_thread'] = thread
276
mirabal580435e2017-03-01 16:17:10 +0100277
tierno57f7bda2017-02-09 12:01:55 +0100278
mirabalb716ac52017-02-10 14:47:53 +0100279 # create ovs dhcp thread
280 result, content = self.db.get_table(FROM='nets')
281 if result < 0:
282 self.logger.error("http_get_ports Error %d %s", result, content)
283 raise ovimException(str(content), -result)
284
285 for net in content:
286 net_type = net['type']
tierno1d5c2292017-07-13 17:50:59 +0200287 if net['status'] != "INACTIVE" and (net_type == 'bridge_data' or net_type == 'bridge_man') and \
tiernoa6933042017-05-24 16:54:33 +0200288 net["provider"][:4] == 'OVS:' and net["enable_dhcp"] == "true":
289 try:
mirabale16a6362017-07-10 05:45:56 -0500290 config_routes = net.get('routes')
291 if config_routes:
292 routes = yaml.safe_load(config_routes)
293 else:
294 routes = None
295
296 config_dns = net.get('dns')
297 if config_dns:
298 dns = yaml.safe_load(config_dns)
299 else:
300 dns = None
301
302 links = net.get('links')
303 if links:
304 links = yaml.safe_load(net.get('links'))
mirabal0ec17ec2017-07-19 08:43:09 -0500305 if net.get('enable_dhcp'):
306 self.launch_dhcp_server(net.get('vlan'),
307 net.get('dhcp_first_ip'),
308 net.get('dhcp_last_ip'),
309 net.get('cidr'),
310 net.get('gateway_ip'),
311 dns,
312 routes)
mirabale16a6362017-07-10 05:45:56 -0500313 self.launch_link_bridge_to_ovs(net['vlan'], net.get('gateway_ip'), net.get('cidr'), links, routes)
tierno1d5c2292017-07-13 17:50:59 +0200314 if net["status"] == "ERROR":
315 self.db.update_rows("nets", UPDATE={"status": "ACTIVE", "last_error": None},
316 WHERE={"uuid": net["uuid"]})
tiernoa6933042017-05-24 16:54:33 +0200317 except Exception as e:
318 self.logger.error("Fail at launching dhcp server for net_id='%s' net_name='%s': %s",
319 net["uuid"], net["name"], str(e))
tierno1d5c2292017-07-13 17:50:59 +0200320 self.db.update_rows("nets", UPDATE={"status": "ERROR",
tiernoa6933042017-05-24 16:54:33 +0200321 "last_error": "Fail at launching dhcp server: " + str(e)},
tierno1d5c2292017-07-13 17:50:59 +0200322 WHERE={"uuid": net["uuid"]})
mirabalb716ac52017-02-10 14:47:53 +0100323
mirabal580435e2017-03-01 16:17:10 +0100324 def _start_of_db_tasks(self):
325 """
326 Start ofc task for existing ofcs in database
327 :param db_of:
328 :param db_lock:
329 :return:
330 """
331 ofcs = self.get_of_controllers()
332
333 for ofc in ofcs:
334 of_conn = self._load_of_module(ofc)
335 # create ofc thread per of controller
336 self._create_ofc_task(ofc['uuid'], ofc['dpid'], of_conn)
337
338 def _create_ofc_task(self, ofc_uuid, dpid, of_conn):
339 """
340 Create an ofc thread for handle each sdn controllers
341 :param ofc_uuid: sdn controller uuid
342 :param dpid: sdn controller dpid
343 :param of_conn: OF_conn module
344 :return:
345 """
346 if 'ofcs_thread' not in self.config and 'ofcs_thread_dpid' not in self.config:
347 ofcs_threads = {}
348 ofcs_thread_dpid = []
349 else:
350 ofcs_threads = self.config['ofcs_thread']
351 ofcs_thread_dpid = self.config['ofcs_thread_dpid']
352
353 if ofc_uuid not in ofcs_threads:
354 ofc_thread = self._create_ofc_thread(of_conn, ofc_uuid)
355 if ofc_uuid == "Default":
356 self.config['of_thread'] = ofc_thread
357
358 ofcs_threads[ofc_uuid] = ofc_thread
359 self.config['ofcs_thread'] = ofcs_threads
360
361 ofcs_thread_dpid.append({dpid: ofc_thread})
362 self.config['ofcs_thread_dpid'] = ofcs_thread_dpid
363
364 def _start_ofc_default_task(self):
365 """
366 Create default ofc thread
367 """
368 if 'of_controller' not in self.config \
369 and 'of_controller_ip' not in self.config \
370 and 'of_controller_port' not in self.config \
371 and 'of_controller_dpid' not in self.config:
372 return
373
374 # OF THREAD
375 db_config = {}
376 db_config['ip'] = self.config.get('of_controller_ip')
377 db_config['port'] = self.config.get('of_controller_port')
378 db_config['dpid'] = self.config.get('of_controller_dpid')
379 db_config['type'] = self.config.get('of_controller')
380 db_config['user'] = self.config.get('of_user')
381 db_config['password'] = self.config.get('of_password')
382
383 # create connector to the openflow controller
384 # load other parameters starting by of_ from config dict in a temporal dict
385
386 of_conn = self._load_of_module(db_config)
387 # create openflow thread
388 self._create_ofc_task("Default", db_config['dpid'], of_conn)
389
390 def _load_of_module(self, db_config):
391 """
392 import python module for each SDN controller supported
mirabalf9a1a8d2017-03-15 12:42:27 +0100393 :param db_config: SDN dn information
mirabal580435e2017-03-01 16:17:10 +0100394 :return: Module
395 """
396 if not db_config:
397 raise ovimException("No module found it", HTTP_Internal_Server_Error)
398
399 module_info = None
400
401 try:
402 if self.of_test_mode:
mirabal6c600652017-03-16 17:22:57 +0100403 return openflow_conn.OfTestConnector({"name": db_config['type'],
404 "dpid": db_config['dpid'],
405 "of_debug": self.config['log_level_of']})
mirabal580435e2017-03-01 16:17:10 +0100406 temp_dict = {}
407
408 if db_config:
409 temp_dict['of_ip'] = db_config['ip']
410 temp_dict['of_port'] = db_config['port']
411 temp_dict['of_dpid'] = db_config['dpid']
412 temp_dict['of_controller'] = db_config['type']
montesmorenoba1862b2017-04-06 10:07:44 +0000413 temp_dict['of_user'] = db_config.get('user')
414 temp_dict['of_password'] = db_config.get('password')
mirabal580435e2017-03-01 16:17:10 +0100415
416 temp_dict['of_debug'] = self.config['log_level_of']
417
418 if temp_dict['of_controller'] == 'opendaylight':
419 module = "ODL"
420 else:
421 module = temp_dict['of_controller']
422
423 if module not in ovim.of_module:
garciadeblas7fa5a652017-04-26 17:55:43 +0200424 try:
425 pkg = __import__("osm_openvim." + module)
426 of_conn_module = getattr(pkg, module)
427 ovim.of_module[module] = of_conn_module
428 self.logger.debug("Module load from {}".format("osm_openvim." + module))
429 except Exception as e:
tierno29d80242017-04-25 18:07:08 +0200430 self.logger.error("Cannot open openflow controller module of type '%s'", module)
431 raise ovimException("Cannot open openflow controller of type module '{}'"
432 "Revise it is installed".format(module),
433 HTTP_Internal_Server_Error)
mirabal580435e2017-03-01 16:17:10 +0100434 else:
435 of_conn_module = ovim.of_module[module]
tierno29d80242017-04-25 18:07:08 +0200436 return of_conn_module.OF_conn(temp_dict)
437 except Exception as e:
438 self.logger.error("Cannot open the Openflow controller '%s': %s", type(e).__name__, str(e))
439 raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e).__name__, str(e)),
mirabal580435e2017-03-01 16:17:10 +0100440 HTTP_Internal_Server_Error)
441
442 def _create_ofc_thread(self, of_conn, ofc_uuid="Default"):
443 """
444 Create and launch a of thread
445 :return: thread obj
446 """
447 # create openflow thread
448
montesmoreno92827552017-03-30 13:24:17 +0200449 #if 'of_controller_nets_with_same_vlan' in self.config:
450 # ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
451 #else:
452 # ofc_net_same_vlan = False
453 ofc_net_same_vlan = False
mirabal580435e2017-03-01 16:17:10 +0100454
tiernoe0c28c12017-05-04 18:44:40 +0200455 thread = oft.openflow_thread(ofc_uuid, of_conn, of_test=self.of_test_mode, db=self.config["db"],
456 db_lock=self.config["db_lock"],
457 pmp_with_same_vlan=ofc_net_same_vlan,
458 logger_name=self.logger_name + ".ofc." + ofc_uuid,
459 debug=self.config.get('log_level_of'))
mirabal580435e2017-03-01 16:17:10 +0100460 #r, c = thread.OF_connector.obtain_port_correspondence()
461 #if r < 0:
462 # raise ovimException("Cannot get openflow information %s", c)
463 thread.start()
464 return thread
465
tierno57f7bda2017-02-09 12:01:55 +0100466 def stop_service(self):
467 threads = self.config.get('host_threads', {})
468 if 'of_thread' in self.config:
469 threads['of'] = (self.config['of_thread'])
mirabal580435e2017-03-01 16:17:10 +0100470 if 'ofcs_thread' in self.config:
471 ofcs_thread = self.config['ofcs_thread']
472 for ofc in ofcs_thread:
473 threads[ofc] = ofcs_thread[ofc]
474
tierno57f7bda2017-02-09 12:01:55 +0100475 if 'dhcp_thread' in self.config:
476 threads['dhcp'] = (self.config['dhcp_thread'])
477
tiernoa6933042017-05-24 16:54:33 +0200478 for thread_id, thread in threads.items():
479 if thread_id == 'openvim_controller':
480 continue
tierno57f7bda2017-02-09 12:01:55 +0100481 thread.insert_task("exit")
tiernoa6933042017-05-24 16:54:33 +0200482 for thread_id, thread in threads.items():
483 if thread_id == 'openvim_controller':
484 continue
tierno57f7bda2017-02-09 12:01:55 +0100485 thread.join()
tierno57f7bda2017-02-09 12:01:55 +0100486
mirabal9e194592017-02-17 11:03:25 +0100487 def get_networks(self, columns=None, db_filter={}, limit=None):
mirabal65ba8f82017-02-15 12:36:33 +0100488 """
489 Retreive networks available
mirabale9f6f1a2017-02-16 17:57:35 +0100490 :param columns: List with select query parameters
mirabal9e194592017-02-17 11:03:25 +0100491 :param db_filter: List with where query parameters
mirabale9f6f1a2017-02-16 17:57:35 +0100492 :param limit: Query limit result
mirabal65ba8f82017-02-15 12:36:33 +0100493 :return:
494 """
mirabal9e194592017-02-17 11:03:25 +0100495 result, content = self.db.get_table(SELECT=columns, FROM='nets', WHERE=db_filter, LIMIT=limit)
mirabal65ba8f82017-02-15 12:36:33 +0100496
497 if result < 0:
498 raise ovimException(str(content), -result)
499
500 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
501
502 return content
503
tiernobd15be42018-07-19 14:23:08 +0200504 def show_network(self, network_id, db_filter={}, skip_on_not_found=False):
mirabal65ba8f82017-02-15 12:36:33 +0100505 """
mirabale9f6f1a2017-02-16 17:57:35 +0100506 Get network from DB by id
507 :param network_id: net Id
mirabal9e194592017-02-17 11:03:25 +0100508 :param db_filter: List with where query parameters
mirabal65ba8f82017-02-15 12:36:33 +0100509 :return:
510 """
511 # obtain data
mirabale9f6f1a2017-02-16 17:57:35 +0100512 if not network_id:
513 raise ovimException("Not network id was not found")
mirabal9e194592017-02-17 11:03:25 +0100514 db_filter['uuid'] = network_id
mirabal65ba8f82017-02-15 12:36:33 +0100515
mirabal9e194592017-02-17 11:03:25 +0100516 result, content = self.db.get_table(FROM='nets', WHERE=db_filter, LIMIT=100)
mirabal65ba8f82017-02-15 12:36:33 +0100517
518 if result < 0:
519 raise ovimException(str(content), -result)
520 elif result == 0:
tiernobd15be42018-07-19 14:23:08 +0200521 if skip_on_not_found:
522 return
523 raise ovimException("show_network network '%s' not found" % network_id, HTTP_Not_Found)
mirabal65ba8f82017-02-15 12:36:33 +0100524 else:
525 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
mirabale9f6f1a2017-02-16 17:57:35 +0100526 # get ports from DB
mirabal65ba8f82017-02-15 12:36:33 +0100527 result, ports = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
mirabale9f6f1a2017-02-16 17:57:35 +0100528 WHERE={'net_id': network_id}, LIMIT=100)
mirabal65ba8f82017-02-15 12:36:33 +0100529 if len(ports) > 0:
530 content[0]['ports'] = ports
mirabale9f6f1a2017-02-16 17:57:35 +0100531 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
tierno9a8846d2018-06-28 15:42:25 +0200532
533 result, flows = self.db.get_table(FROM='of_flows', SELECT=('priority', 'vlan_id', 'ingress_port', 'src_mac', 'dst_mac', 'actions'),
534 WHERE={'net_id': network_id}, LIMIT=100)
535 if len(flows) > 0:
536 content[0]['flows'] = flows
mirabale9f6f1a2017-02-16 17:57:35 +0100537 return content[0]
538
539 def new_network(self, network):
mirabal65ba8f82017-02-15 12:36:33 +0100540 """
mirabale9f6f1a2017-02-16 17:57:35 +0100541 Create a net in DB
mirabal65ba8f82017-02-15 12:36:33 +0100542 :return:
543 """
544 tenant_id = network.get('tenant_id')
545
546 if tenant_id:
547 result, _ = self.db.get_table(FROM='tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id, "enabled": True})
548 if result <= 0:
549 raise ovimException("set_network error, no tenant founded", -result)
550
551 bridge_net = None
552 # check valid params
553 net_provider = network.get('provider')
554 net_type = network.get('type')
mirabal65ba8f82017-02-15 12:36:33 +0100555 net_vlan = network.get("vlan")
556 net_bind_net = network.get("bind_net")
557 net_bind_type = network.get("bind_type")
tiernoa290d8f2017-05-03 17:42:52 +0200558 net_region = network.get("region")
mirabal65ba8f82017-02-15 12:36:33 +0100559 name = network["name"]
560
561 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
562 vlan_index = name.rfind(":")
563 if not net_bind_net and not net_bind_type and vlan_index > 1:
564 try:
565 vlan_tag = int(name[vlan_index + 1:])
566 if not vlan_tag and vlan_tag < 4096:
567 net_bind_net = name[:vlan_index]
568 net_bind_type = "vlan:" + name[vlan_index + 1:]
569 except:
570 pass
571
572 if net_bind_net:
573 # look for a valid net
574 if self._check_valid_uuid(net_bind_net):
575 net_bind_key = "uuid"
576 else:
577 net_bind_key = "name"
578 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
579 if result < 0:
580 raise ovimException(' getting nets from db ' + content, HTTP_Internal_Server_Error)
581 elif result == 0:
582 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
583 elif result > 1:
584 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
585 network["bind_net"] = content[0]["uuid"]
586
587 if net_bind_type:
588 if net_bind_type[0:5] != "vlan:":
589 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
590 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
591 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
592 HTTP_Bad_Request)
593 network["bind_type"] = net_bind_type
594
595 if net_provider:
596 if net_provider[:9] == "openflow:":
597 if net_type:
598 if net_type != "ptp" and net_type != "data":
599 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
600 HTTP_Bad_Request)
601 else:
602 net_type = 'data'
603 else:
604 if net_type:
605 if net_type != "bridge_man" and net_type != "bridge_data":
606 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
607 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
608 else:
609 net_type = 'bridge_man'
610
611 if not net_type:
612 net_type = 'bridge_man'
613
614 if net_provider:
615 if net_provider[:7] == 'bridge:':
616 # check it is one of the pre-provisioned bridges
617 bridge_net_name = net_provider[7:]
618 for brnet in self.config['bridge_nets']:
619 if brnet[0] == bridge_net_name: # free
tierno11c45e72017-05-17 12:04:05 +0000620 if brnet[3]:
mirabal65ba8f82017-02-15 12:36:33 +0100621 raise ovimException("invalid 'provider:physical', "
622 "bridge '%s' is already used" % bridge_net_name, HTTP_Conflict)
623 bridge_net = brnet
624 net_vlan = brnet[1]
625 break
mirabale9f6f1a2017-02-16 17:57:35 +0100626 # if bridge_net==None:
627 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
628 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
629 # return
630
mirabal65ba8f82017-02-15 12:36:33 +0100631 elif self.config['network_type'] == 'bridge' and (net_type == 'bridge_data' or net_type == 'bridge_man'):
632 # look for a free precreated nets
633 for brnet in self.config['bridge_nets']:
634 if not brnet[3]: # free
635 if not bridge_net:
636 if net_type == 'bridge_man': # look for the smaller speed
637 if brnet[2] < bridge_net[2]:
638 bridge_net = brnet
639 else: # look for the larger speed
640 if brnet[2] > bridge_net[2]:
641 bridge_net = brnet
642 else:
643 bridge_net = brnet
644 net_vlan = brnet[1]
645 if not bridge_net:
646 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
647 "will overcome this limit", HTTP_Bad_Request)
648 else:
mirabale9f6f1a2017-02-16 17:57:35 +0100649 self.logger.debug("using net " + bridge_net)
mirabal65ba8f82017-02-15 12:36:33 +0100650 net_provider = "bridge:" + bridge_net[0]
651 net_vlan = bridge_net[1]
652 elif net_type == 'bridge_data' or net_type == 'bridge_man' and self.config['network_type'] == 'ovs':
653 net_provider = 'OVS'
tiernoa290d8f2017-05-03 17:42:52 +0200654 if not net_region:
655 if net_type == "data" or net_type == "ptp":
656 net_region = "__DATA__"
657 elif net_provider == "OVS":
658 net_region = "__OVS__"
mirabal65ba8f82017-02-15 12:36:33 +0100659 if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
tiernoa290d8f2017-05-03 17:42:52 +0200660 net_vlan = self.db.get_free_net_vlan(net_region)
mirabal65ba8f82017-02-15 12:36:33 +0100661 if net_vlan < 0:
662 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error)
663 if net_provider == 'OVS':
664 net_provider = 'OVS' + ":" + str(net_vlan)
665
666 network['provider'] = net_provider
667 network['type'] = net_type
668 network['vlan'] = net_vlan
tiernoa290d8f2017-05-03 17:42:52 +0200669 network['region'] = net_region
mirabal65ba8f82017-02-15 12:36:33 +0100670 dhcp_integrity = True
tierno5f79a262017-11-28 11:53:01 +0100671 if network.get('enable_dhcp'):
mirabal65ba8f82017-02-15 12:36:33 +0100672 dhcp_integrity = self._check_dhcp_data_integrity(network)
mirabal6878e3f2017-06-05 09:19:26 -0500673
674 if network.get('links'):
675 network['links'] = yaml.safe_dump(network['links'], default_flow_style=True, width=256)
676 if network.get('dns'):
677 network['dns'] = yaml.safe_dump(network['dns'], default_flow_style=True, width=256)
678 if network.get('routes'):
679 network['routes'] = yaml.safe_dump(network['routes'], default_flow_style=True, width=256)
mirabal65ba8f82017-02-15 12:36:33 +0100680
681 result, content = self.db.new_row('nets', network, True, True)
tierno5f79a262017-11-28 11:53:01 +0100682 if result >= 0: # and dhcp_integrity:
mirabal65ba8f82017-02-15 12:36:33 +0100683 if bridge_net:
684 bridge_net[3] = content
tierno5f79a262017-11-28 11:53:01 +0100685 if self.config.get("dhcp_server") and self.config['network_type'] == 'bridge':
mirabal65ba8f82017-02-15 12:36:33 +0100686 if network["name"] in self.config["dhcp_server"].get("nets", ()):
687 self.config["dhcp_nets"].append(content)
mirabale9f6f1a2017-02-16 17:57:35 +0100688 self.logger.debug("dhcp_server: add new net", content)
tierno11c45e72017-05-17 12:04:05 +0000689 elif bridge_net and bridge_net[0] in self.config["dhcp_server"].get("bridge_ifaces", ()):
mirabal65ba8f82017-02-15 12:36:33 +0100690 self.config["dhcp_nets"].append(content)
mirabale9f6f1a2017-02-16 17:57:35 +0100691 self.logger.debug("dhcp_server: add new net", content, content)
mirabal65ba8f82017-02-15 12:36:33 +0100692 return content
693 else:
tierno5f79a262017-11-28 11:53:01 +0100694 raise ovimException("Error creating network: {}".format(content), -result)
695
mirabale9f6f1a2017-02-16 17:57:35 +0100696# TODO kei change update->edit
mirabal65ba8f82017-02-15 12:36:33 +0100697
mirabale9f6f1a2017-02-16 17:57:35 +0100698 def edit_network(self, network_id, network):
mirabal65ba8f82017-02-15 12:36:33 +0100699 """
mirabale9f6f1a2017-02-16 17:57:35 +0100700 Update entwork data byt id
mirabal65ba8f82017-02-15 12:36:33 +0100701 :return:
702 """
mirabale9f6f1a2017-02-16 17:57:35 +0100703 # Look for the previous data
704 where_ = {'uuid': network_id}
705 result, network_old = self.db.get_table(FROM='nets', WHERE=where_)
706 if result < 0:
707 raise ovimException("Error updating network %s" % network_old, HTTP_Internal_Server_Error)
708 elif result == 0:
709 raise ovimException('network %s not found' % network_id, HTTP_Not_Found)
710 # get ports
711 nbports, content = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
712 WHERE={'net_id': network_id}, LIMIT=100)
713 if result < 0:
714 raise ovimException("http_put_network_id error %d %s" % (result, network_old), HTTP_Internal_Server_Error)
715 if nbports > 0:
716 if 'type' in network and network['type'] != network_old[0]['type']:
717 raise ovimException("Can not change type of network while having ports attached",
718 HTTP_Method_Not_Allowed)
719 if 'vlan' in network and network['vlan'] != network_old[0]['vlan']:
720 raise ovimException("Can not change vlan of network while having ports attached",
721 HTTP_Method_Not_Allowed)
mirabal65ba8f82017-02-15 12:36:33 +0100722
mirabale9f6f1a2017-02-16 17:57:35 +0100723 # check valid params
724 net_provider = network.get('provider', network_old[0]['provider'])
725 net_type = network.get('type', network_old[0]['type'])
726 net_bind_net = network.get("bind_net")
727 net_bind_type = network.get("bind_type")
728 if net_bind_net:
729 # look for a valid net
730 if self._check_valid_uuid(net_bind_net):
731 net_bind_key = "uuid"
732 else:
733 net_bind_key = "name"
734 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
735 if result < 0:
736 raise ovimException('Getting nets from db ' + content, HTTP_Internal_Server_Error)
737 elif result == 0:
738 raise ovimException("bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
739 elif result > 1:
740 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net),
741 HTTP_Bad_Request)
742 network["bind_net"] = content[0]["uuid"]
743 if net_bind_type:
744 if net_bind_type[0:5] != "vlan:":
745 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
746 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
747 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
748 HTTP_Bad_Request)
749 if net_provider:
750 if net_provider[:9] == "openflow:":
751 if net_type != "ptp" and net_type != "data":
752 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request)
753 else:
754 if net_type != "bridge_man" and net_type != "bridge_data":
755 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
756 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
mirabal65ba8f82017-02-15 12:36:33 +0100757
mirabale9f6f1a2017-02-16 17:57:35 +0100758 # insert in data base
759 result, content = self.db.update_rows('nets', network, WHERE={'uuid': network_id}, log=True)
760 if result >= 0:
761 # if result > 0 and nbports>0 and 'admin_state_up' in network
762 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
763 if result > 0:
mirabal7bbf50e2017-03-13 15:15:18 +0100764
765 try:
tiernoaa941462017-03-29 15:10:28 +0200766 if nbports:
767 self.net_update_ofc_thread(network_id)
mirabal7bbf50e2017-03-13 15:15:18 +0100768 except ovimException as e:
769 raise ovimException("Error while launching openflow rules in network '{}' {}"
770 .format(network_id, str(e)), HTTP_Internal_Server_Error)
771 except Exception as e:
772 raise ovimException("Error while launching openflow rules in network '{}' {}"
773 .format(network_id, str(e)), HTTP_Internal_Server_Error)
774
mirabale9f6f1a2017-02-16 17:57:35 +0100775 if self.config.get("dhcp_server"):
776 if network_id in self.config["dhcp_nets"]:
777 self.config["dhcp_nets"].remove(network_id)
mirabal7bbf50e2017-03-13 15:15:18 +0100778 if network.get("name", network_old[0]["name"]) in self.config["dhcp_server"].get("nets", ()):
mirabale9f6f1a2017-02-16 17:57:35 +0100779 self.config["dhcp_nets"].append(network_id)
780 else:
mirabal7bbf50e2017-03-13 15:15:18 +0100781 net_bind = network.get("bind_type", network_old[0]["bind_type"])
782 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 +0100783 "bridge_ifaces", ()):
784 self.config["dhcp_nets"].append(network_id)
785 return network_id
mirabal65ba8f82017-02-15 12:36:33 +0100786 else:
mirabale9f6f1a2017-02-16 17:57:35 +0100787 raise ovimException(content, -result)
mirabal65ba8f82017-02-15 12:36:33 +0100788
tiernobd15be42018-07-19 14:23:08 +0200789 def delete_network(self, network_id, idempotent=True):
mirabal9e194592017-02-17 11:03:25 +0100790 """
791 Delete network by network id
792 :param network_id: network id
793 :return:
794 """
tiernobd15be42018-07-19 14:23:08 +0200795 net_data = self.show_network(network_id, skip_on_not_found=idempotent)
796 if not net_data: # network does not exist
797 return
mirabale9f6f1a2017-02-16 17:57:35 +0100798
799 # delete from the data base
800 result, content = self.db.delete_row('nets', network_id)
801
802 if result == 0:
803 raise ovimException("Network %s not found " % network_id, HTTP_Not_Found)
804 elif result > 0:
805 for brnet in self.config['bridge_nets']:
806 if brnet[3] == network_id:
807 brnet[3] = None
808 break
809 if self.config.get("dhcp_server") and network_id in self.config["dhcp_nets"]:
810 self.config["dhcp_nets"].remove(network_id)
mirabal0ec17ec2017-07-19 08:43:09 -0500811
812 if net_data.get('enable_dhcp'):
813 dhcp_path = self.config['ovs_controller_file_path']
814 dhcp_controller = self.get_dhcp_controller()
815 dhcp_controller.delete_dhcp_server(net_data['vlan'], network_id, dhcp_path)
816 dhcp_controller.delete_dhcp_port(net_data['vlan'], network_id, dhcp_path)
817 links = yaml.load(net_data.get('links'))
818 if links:
819 links = yaml.load(net_data.get('links'))
820 self.delete_link_bridge_to_ovs(net_data['vlan'], links)
821
822 return content
mirabale9f6f1a2017-02-16 17:57:35 +0100823 else:
tierno11c45e72017-05-17 12:04:05 +0000824 raise ovimException("Error deleting network '{}': {}".format(network_id, content), -result)
mirabal65ba8f82017-02-15 12:36:33 +0100825
826 def get_openflow_rules(self, network_id=None):
827 """
828 Get openflow id from DB
829 :param network_id: Network id, if none all networks will be retrieved
830 :return: Return a list with Openflow rules per net
831 """
832 # ignore input data
833 if not network_id:
834 where_ = {}
835 else:
836 where_ = {"net_id": network_id}
mirabal65ba8f82017-02-15 12:36:33 +0100837 result, content = self.db.get_table(
mirabalf9a1a8d2017-03-15 12:42:27 +0100838 SELECT=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
mirabal65ba8f82017-02-15 12:36:33 +0100839 WHERE=where_, FROM='of_flows')
840
841 if result < 0:
842 raise ovimException(str(content), -result)
843 return content
844
mirabale9f6f1a2017-02-16 17:57:35 +0100845 def edit_openflow_rules(self, network_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100846
847 """
848 To make actions over the net. The action is to reinstall the openflow rules
849 network_id can be 'all'
850 :param network_id: Network id, if none all networks will be retrieved
851 :return : Number of nets updated
852 """
853
854 # ignore input data
855 if not network_id:
856 where_ = {}
857 else:
858 where_ = {"uuid": network_id}
859 result, content = self.db.get_table(SELECT=("uuid", "type"), WHERE=where_, FROM='nets')
860
861 if result < 0:
862 raise ovimException(str(content), -result)
863
864 for net in content:
865 if net["type"] != "ptp" and net["type"] != "data":
866 result -= 1
867 continue
mirabal7bbf50e2017-03-13 15:15:18 +0100868
869 try:
870 self.net_update_ofc_thread(net['uuid'])
871 except ovimException as e:
872 raise ovimException("Error updating network'{}' {}".format(net['uuid'], str(e)),
873 HTTP_Internal_Server_Error)
874 except Exception as e:
875 raise ovimException("Error updating network '{}' {}".format(net['uuid'], str(e)),
876 HTTP_Internal_Server_Error)
877
mirabal65ba8f82017-02-15 12:36:33 +0100878 return result
879
mirabalf9a1a8d2017-03-15 12:42:27 +0100880 def delete_openflow_rules(self, ofc_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100881 """
882 To make actions over the net. The action is to delete ALL openflow rules
883 :return: return operation result
884 """
mirabalf9a1a8d2017-03-15 12:42:27 +0100885
886 if not ofc_id:
887 if 'Default' in self.config['ofcs_thread']:
888 r, c = self.config['ofcs_thread']['Default'].insert_task("clear-all")
889 else:
890 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
891
892 elif ofc_id in self.config['ofcs_thread']:
893 r, c = self.config['ofcs_thread'][ofc_id].insert_task("clear-all")
894
895 # ignore input data
896 if r < 0:
897 raise ovimException(str(c), -r)
898 else:
899 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
mirabal65ba8f82017-02-15 12:36:33 +0100900 return r
901
mirabalf9a1a8d2017-03-15 12:42:27 +0100902 def get_openflow_ports(self, ofc_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100903 """
904 Obtain switch ports names of openflow controller
905 :return: Return flow ports in DB
906 """
mirabalf9a1a8d2017-03-15 12:42:27 +0100907 if not ofc_id:
908 if 'Default' in self.config['ofcs_thread']:
909 conn = self.config['ofcs_thread']['Default'].OF_connector
910 else:
911 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
912
tierno11c45e72017-05-17 12:04:05 +0000913 elif ofc_id in self.config['ofcs_thread']:
mirabalf9a1a8d2017-03-15 12:42:27 +0100914 conn = self.config['ofcs_thread'][ofc_id].OF_connector
915 else:
916 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
917 return conn.pp2ofi
tierno57f7bda2017-02-09 12:01:55 +0100918
919 def get_ports(self, columns=None, filter={}, limit=None):
920 # result, content = my.db.get_ports(where_)
921 result, content = self.db.get_table(SELECT=columns, WHERE=filter, FROM='ports', LIMIT=limit)
922 if result < 0:
923 self.logger.error("http_get_ports Error %d %s", result, content)
924 raise ovimException(str(content), -result)
925 else:
926 convert_boolean(content, ('admin_state_up',))
927 return content
928
tierno57f7bda2017-02-09 12:01:55 +0100929 def new_port(self, port_data):
930 port_data['type'] = 'external'
931 if port_data.get('net_id'):
932 # check that new net has the correct type
933 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
934 if result < 0:
935 raise ovimException(str(new_net), -result)
936 # insert in data base
937 result, uuid = self.db.new_row('ports', port_data, True, True)
938 if result > 0:
939 if 'net_id' in port_data:
mirabal7bbf50e2017-03-13 15:15:18 +0100940 try:
941 self.net_update_ofc_thread(port_data['net_id'])
942 except ovimException as e:
943 raise ovimException("Cannot insert a task for updating network '{}' {}"
944 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
945 except Exception as e:
946 raise ovimException("Cannot insert a task for updating network '{}' {}"
947 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
948
tierno57f7bda2017-02-09 12:01:55 +0100949 return uuid
950 else:
951 raise ovimException(str(uuid), -result)
952
mirabal37829452017-03-09 14:41:21 +0100953 def new_external_port(self, port_data):
954 """
955 Create new external port and check port mapping correspondence
956 :param port_data: port_data = {
957 'region': 'datacenter region',
958 'compute_node': 'compute node id',
959 'pci': 'pci port address',
960 'vlan': 'net vlan',
961 'net_id': 'net id',
962 'tenant_id': 'tenant id',
963 'mac': 'switch mac',
964 'name': 'port name'
965 'ip_address': 'ip address - optional'}
966 :return:
967 """
968
969 port_data['type'] = 'external'
970
971 if port_data.get('net_id'):
972 # check that new net has the correct type
973 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
974 if result < 0:
975 raise ovimException(str(new_net), -result)
976 # insert in data base
977 db_filter = {}
978
979 if port_data.get('region'):
980 db_filter['region'] = port_data['region']
981 if port_data.get('pci'):
982 db_filter['pci'] = port_data['pci']
983 if port_data.get('compute_node'):
984 db_filter['compute_node'] = port_data['compute_node']
985
986 columns = ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
987 port_mapping_data = self.get_of_port_mappings(columns, db_filter)
988
989 if not len(port_mapping_data):
tierno16007502017-03-27 16:48:32 +0200990 raise ovimException("No port mapping founded for '{}'".format(str(db_filter)),
mirabal37829452017-03-09 14:41:21 +0100991 HTTP_Not_Found)
992 elif len(port_mapping_data) > 1:
993 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
994 HTTP_Conflict)
995
996 port_data['ofc_id'] = port_mapping_data[0]['ofc_id']
997 port_data['switch_dpid'] = port_mapping_data[0]['switch_dpid']
998 port_data['switch_port'] = port_mapping_data[0]['switch_port']
999 port_data['switch_mac'] = port_mapping_data[0]['switch_mac']
1000
1001 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
montesmoreno275b1992017-03-28 15:45:02 +02001002 if 'region' in port_data:
1003 del port_data['region']
1004 if 'pci' in port_data:
1005 del port_data['pci']
1006 if 'compute_node' in port_data:
1007 del port_data['compute_node']
mirabal37829452017-03-09 14:41:21 +01001008
1009 result, uuid = self.db.new_row('ports', port_data, True, True)
tiernobd7d70e2018-07-17 10:35:44 +02001010 # set net status to BUILD
1011 self.db.update_rows('nets', {"status": "BUILD"}, WHERE={'uuid': port_data['net_id']})
mirabal37829452017-03-09 14:41:21 +01001012 if result > 0:
mirabal7bbf50e2017-03-13 15:15:18 +01001013 try:
1014 self.net_update_ofc_thread(port_data['net_id'], port_data['ofc_id'])
1015 except ovimException as e:
1016 raise ovimException("Cannot insert a task for updating network '{}' {}".
1017 format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
1018 except Exception as e:
1019 raise ovimException("Cannot insert a task for updating network '{}' {}"
1020 .format(port_data['net_id'], e), HTTP_Internal_Server_Error)
mirabal37829452017-03-09 14:41:21 +01001021 return uuid
1022 else:
1023 raise ovimException(str(uuid), -result)
1024
tiernoaa941462017-03-29 15:10:28 +02001025 def net_update_ofc_thread(self, net_id, ofc_id=None, switch_dpid=None):
mirabal7bbf50e2017-03-13 15:15:18 +01001026 """
1027 Insert a update net task by net id or ofc_id for each ofc thread
1028 :param net_id: network id
1029 :param ofc_id: openflow controller id
tiernoaa941462017-03-29 15:10:28 +02001030 :param switch_dpid: switch dpid
mirabal7bbf50e2017-03-13 15:15:18 +01001031 :return:
1032 """
1033 if not net_id:
1034 raise ovimException("No net_id received", HTTP_Internal_Server_Error)
1035
mirabal7bbf50e2017-03-13 15:15:18 +01001036 r = -1
1037 c = 'No valid ofc_id or switch_dpid received'
1038
1039 if not ofc_id:
1040 ports = self.get_ports(filter={"net_id": net_id})
1041 for port in ports:
1042 port_ofc_id = port.get('ofc_id', None)
1043 if port_ofc_id:
1044 ofc_id = port['ofc_id']
1045 switch_dpid = port['switch_dpid']
1046 break
tiernoaa941462017-03-29 15:10:28 +02001047 #TODO if not ofc_id: look at database table ofcs
1048
mirabal7bbf50e2017-03-13 15:15:18 +01001049
1050 # If no ofc_id found it, default ofc_id is used.
1051 if not ofc_id and not switch_dpid:
1052 ofc_id = "Default"
1053
1054 if ofc_id and ofc_id in self.config['ofcs_thread']:
1055 r, c = self.config['ofcs_thread'][ofc_id].insert_task("update-net", net_id)
1056 elif switch_dpid:
1057
1058 ofcs_dpid_list = self.config['ofcs_thread_dpid']
1059 for ofc_t in ofcs_dpid_list:
1060 if switch_dpid in ofc_t:
1061 r, c = ofc_t[switch_dpid].insert_task("update-net", net_id)
1062
1063 if r < 0:
tierno82232582017-03-15 18:09:16 +01001064 message = "Cannot insert a task for updating network '{}', {}".format(net_id, c)
mirabal7bbf50e2017-03-13 15:15:18 +01001065 self.logger.error(message)
1066 raise ovimException(message, HTTP_Internal_Server_Error)
1067
tiernobd15be42018-07-19 14:23:08 +02001068 def delete_port(self, port_id, idempotent=False):
tierno57f7bda2017-02-09 12:01:55 +01001069 # Look for the previous port data
1070 result, ports = self.db.get_table(WHERE={'uuid': port_id, "type": "external"}, FROM='ports')
1071 if result < 0:
1072 raise ovimException("Cannot get port info from database: {}".format(ports), http_code=-result)
1073 # delete from the data base
1074 result, content = self.db.delete_row('ports', port_id)
1075 if result == 0:
tiernobd15be42018-07-19 14:23:08 +02001076 if idempotent:
1077 return
tierno57f7bda2017-02-09 12:01:55 +01001078 raise ovimException("External port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1079 elif result < 0:
1080 raise ovimException("Cannot delete port from database: {}".format(content), http_code=-result)
1081 # update network
tiernobd7d70e2018-07-17 10:35:44 +02001082 net_id = ports[0].get('net_id', None)
1083 if net_id:
tierno57f7bda2017-02-09 12:01:55 +01001084 # change of net.
mirabal7bbf50e2017-03-13 15:15:18 +01001085
tiernobd7d70e2018-07-17 10:35:44 +02001086 # set net status to BUILD
1087 self.db.update_rows('nets', {"status": "BUILD"}, WHERE={'uuid': net_id})
mirabal7bbf50e2017-03-13 15:15:18 +01001088 try:
tiernobd7d70e2018-07-17 10:35:44 +02001089 self.net_update_ofc_thread(net_id, ofc_id=ports[0]["ofc_id"], switch_dpid=ports[0]["switch_dpid"])
mirabal7bbf50e2017-03-13 15:15:18 +01001090 except ovimException as e:
tiernobd7d70e2018-07-17 10:35:44 +02001091 raise ovimException("Cannot insert a task for delete network '{}' {}".format(net_id, str(e)),
mirabal7bbf50e2017-03-13 15:15:18 +01001092 HTTP_Internal_Server_Error)
1093 except Exception as e:
tiernobd7d70e2018-07-17 10:35:44 +02001094 raise ovimException("Cannot insert a task for delete network '{}' {}".format(net_id, str(e)),
mirabal7bbf50e2017-03-13 15:15:18 +01001095 HTTP_Internal_Server_Error)
1096
tierno57f7bda2017-02-09 12:01:55 +01001097 return content
1098
tierno57f7bda2017-02-09 12:01:55 +01001099 def edit_port(self, port_id, port_data, admin=True):
1100 # Look for the previous port data
1101 result, content = self.db.get_table(FROM="ports", WHERE={'uuid': port_id})
1102 if result < 0:
1103 raise ovimException("Cannot get port info from database: {}".format(content), http_code=-result)
1104 elif result == 0:
1105 raise ovimException("Port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1106 port = content[0]
1107 nets = []
1108 host_id = None
1109 result = 1
1110 if 'net_id' in port_data:
1111 # change of net.
1112 old_net = port.get('net_id', None)
1113 new_net = port_data['net_id']
1114 if old_net != new_net:
1115
1116 if new_net:
1117 nets.append(new_net) # put first the new net, so that new openflow rules are created before removing the old ones
1118 if old_net:
1119 nets.append(old_net)
1120 if port['type'] == 'instance:bridge' or port['type'] == 'instance:ovs':
1121 raise ovimException("bridge interfaces cannot be attached to a different net", http_code=HTTP_Forbidden)
1122 elif port['type'] == 'external' and not admin:
1123 raise ovimException("Needed admin privileges",http_code=HTTP_Unauthorized)
1124 if new_net:
1125 # check that new net has the correct type
1126 result, new_net_dict = self.db.check_target_net(new_net, None, port['type'])
1127 if result < 0:
1128 raise ovimException("Error {}".format(new_net_dict), http_code=HTTP_Conflict)
1129 # change VLAN for SR-IOV ports
1130 if result >= 0 and port["type"] == "instance:data" and port["model"] == "VF": # TODO consider also VFnotShared
1131 if new_net:
1132 port_data["vlan"] = None
1133 else:
1134 port_data["vlan"] = new_net_dict["vlan"]
1135 # get host where this VM is allocated
1136 result, content = self.db.get_table(FROM="instances", WHERE={"uuid": port["instance_id"]})
1137 if result > 0:
1138 host_id = content[0]["host_id"]
1139
1140 # insert in data base
1141 if result >= 0:
1142 result, content = self.db.update_rows('ports', port_data, WHERE={'uuid': port_id}, log=False)
tiernoaa941462017-03-29 15:10:28 +02001143 port.update(port_data)
tierno57f7bda2017-02-09 12:01:55 +01001144
1145 # Insert task to complete actions
1146 if result > 0:
1147 for net_id in nets:
mirabal7bbf50e2017-03-13 15:15:18 +01001148 try:
tiernoaa941462017-03-29 15:10:28 +02001149 self.net_update_ofc_thread(net_id, port["ofc_id"], switch_dpid=port["switch_dpid"])
mirabal7bbf50e2017-03-13 15:15:18 +01001150 except ovimException as e:
1151 raise ovimException("Error updating network'{}' {}".format(net_id, str(e)),
1152 HTTP_Internal_Server_Error)
1153 except Exception as e:
1154 raise ovimException("Error updating network '{}' {}".format(net_id, str(e)),
1155 HTTP_Internal_Server_Error)
1156
tierno57f7bda2017-02-09 12:01:55 +01001157 if host_id:
1158 r, v = self.config['host_threads'][host_id].insert_task("edit-iface", port_id, old_net, new_net)
1159 if r < 0:
1160 self.logger.error("Error updating network '{}' {}".format(r,v))
1161 # TODO Do something if fails
1162 if result >= 0:
1163 return port_id
1164 else:
1165 raise ovimException("Error {}".format(content), http_code=-result)
mirabalb716ac52017-02-10 14:47:53 +01001166
mirabal9e194592017-02-17 11:03:25 +01001167 def new_of_controller(self, ofc_data):
1168 """
1169 Create a new openflow controller into DB
1170 :param ofc_data: Dict openflow controller data
1171 :return: openflow controller dpid
1172 """
1173
mirabal580435e2017-03-01 16:17:10 +01001174 result, ofc_uuid = self.db.new_row('ofcs', ofc_data, True, True)
mirabal9e194592017-02-17 11:03:25 +01001175 if result < 0:
mirabal580435e2017-03-01 16:17:10 +01001176 raise ovimException("New ofc Error %s" % ofc_uuid, HTTP_Internal_Server_Error)
1177
1178 ofc_data['uuid'] = ofc_uuid
1179 of_conn = self._load_of_module(ofc_data)
1180 self._create_ofc_task(ofc_uuid, ofc_data['dpid'], of_conn)
1181
1182 return ofc_uuid
mirabal9e194592017-02-17 11:03:25 +01001183
1184 def edit_of_controller(self, of_id, ofc_data):
1185 """
1186 Edit an openflow controller entry from DB
1187 :return:
1188 """
1189 if not ofc_data:
1190 raise ovimException("No data received during uptade OF contorller", http_code=HTTP_Internal_Server_Error)
1191
1192 old_of_controller = self.show_of_controller(of_id)
1193
1194 if old_of_controller:
1195 result, content = self.db.update_rows('ofcs', ofc_data, WHERE={'uuid': of_id}, log=False)
1196 if result >= 0:
1197 return ofc_data
1198 else:
1199 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1200 http_code=-result)
1201 else:
1202 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1203 http_code=HTTP_Internal_Server_Error)
1204
1205 def delete_of_controller(self, of_id):
1206 """
1207 Delete an openflow controller from DB.
1208 :param of_id: openflow controller dpid
1209 :return:
1210 """
1211
mirabal580435e2017-03-01 16:17:10 +01001212 ofc = self.show_of_controller(of_id)
1213
Pablo Montes Moreno5b6f7492017-03-02 16:18:36 +01001214 result, content = self.db.delete_row("ofcs", of_id)
mirabal9e194592017-02-17 11:03:25 +01001215 if result < 0:
1216 raise ovimException("Cannot delete ofc from database: {}".format(content), http_code=-result)
1217 elif result == 0:
1218 raise ovimException("ofc {} not found ".format(content), http_code=HTTP_Not_Found)
mirabal580435e2017-03-01 16:17:10 +01001219
1220 ofc_thread = self.config['ofcs_thread'][of_id]
1221 del self.config['ofcs_thread'][of_id]
1222 for ofc_th in self.config['ofcs_thread_dpid']:
1223 if ofc['dpid'] in ofc_th:
1224 self.config['ofcs_thread_dpid'].remove(ofc_th)
1225
1226 ofc_thread.insert_task("exit")
1227 #ofc_thread.join()
1228
mirabal9e194592017-02-17 11:03:25 +01001229 return content
1230
1231 def show_of_controller(self, uuid):
1232 """
1233 Show an openflow controller by dpid from DB.
1234 :param db_filter: List with where query parameters
1235 :return:
1236 """
1237
1238 result, content = self.db.get_table(FROM='ofcs', WHERE={"uuid": uuid}, LIMIT=100)
1239
1240 if result == 0:
1241 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid),
1242 http_code=HTTP_Not_Found)
1243 elif result < 0:
1244 raise ovimException("Openflow controller with uuid '{}' error".format(uuid),
1245 http_code=HTTP_Internal_Server_Error)
Pablo Montes Moreno5b6f7492017-03-02 16:18:36 +01001246 return content[0]
mirabal9e194592017-02-17 11:03:25 +01001247
mirabalfbfb7972017-02-27 17:36:17 +01001248 def get_of_controllers(self, columns=None, db_filter={}, limit=None):
mirabal9e194592017-02-17 11:03:25 +01001249 """
1250 Show an openflow controllers from DB.
1251 :param columns: List with SELECT query parameters
1252 :param db_filter: List with where query parameters
mirabalfbfb7972017-02-27 17:36:17 +01001253 :param limit: result Limit
mirabal9e194592017-02-17 11:03:25 +01001254 :return:
1255 """
mirabalfbfb7972017-02-27 17:36:17 +01001256 result, content = self.db.get_table(SELECT=columns, FROM='ofcs', WHERE=db_filter, LIMIT=limit)
mirabal9e194592017-02-17 11:03:25 +01001257
1258 if result < 0:
1259 raise ovimException(str(content), -result)
1260
1261 return content
1262
mirabalfbfb7972017-02-27 17:36:17 +01001263 def get_tenants(self, columns=None, db_filter={}, limit=None):
1264 """
1265 Retrieve tenant list from DB
1266 :param columns: List with SELECT query parameters
1267 :param db_filter: List with where query parameters
1268 :param limit: result limit
1269 :return:
1270 """
1271 result, content = self.db.get_table(FROM='tenants', SELECT=columns, WHERE=db_filter, LIMIT=limit)
1272 if result < 0:
1273 raise ovimException('get_tenatns Error {}'.format(str(content)), -result)
1274 else:
1275 convert_boolean(content, ('enabled',))
1276 return content
1277
1278 def show_tenant_id(self, tenant_id):
1279 """
1280 Get tenant from DB by id
1281 :param tenant_id: tenant id
1282 :return:
1283 """
1284 result, content = self.db.get_table(FROM='tenants', SELECT=('uuid', 'name', 'description', 'enabled'),
1285 WHERE={"uuid": tenant_id})
1286 if result < 0:
1287 raise ovimException(str(content), -result)
1288 elif result == 0:
1289 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1290 else:
1291 convert_boolean(content, ('enabled',))
1292 return content[0]
1293
1294 def new_tentant(self, tenant):
1295 """
1296 Create a tenant and store in DB
1297 :param tenant: Dictionary with tenant data
1298 :return: the uuid of created tenant. Raise exception upon error
1299 """
1300
1301 # insert in data base
1302 result, tenant_uuid = self.db.new_tenant(tenant)
1303
1304 if result >= 0:
1305 return tenant_uuid
1306 else:
1307 raise ovimException(str(tenant_uuid), -result)
1308
1309 def delete_tentant(self, tenant_id):
1310 """
1311 Delete a tenant from the database.
1312 :param tenant_id: Tenant id
1313 :return: delete tenant id
1314 """
1315
1316 # check permissions
1317 r, tenants_flavors = self.db.get_table(FROM='tenants_flavors', SELECT=('flavor_id', 'tenant_id'),
1318 WHERE={'tenant_id': tenant_id})
1319 if r <= 0:
1320 tenants_flavors = ()
1321 r, tenants_images = self.db.get_table(FROM='tenants_images', SELECT=('image_id', 'tenant_id'),
1322 WHERE={'tenant_id': tenant_id})
1323 if r <= 0:
1324 tenants_images = ()
1325
1326 result, content = self.db.delete_row('tenants', tenant_id)
1327 if result == 0:
1328 raise ovimException("tenant '%s' not found" % tenant_id, HTTP_Not_Found)
1329 elif result > 0:
1330 for flavor in tenants_flavors:
1331 self.db.delete_row_by_key("flavors", "uuid", flavor['flavor_id'])
1332 for image in tenants_images:
1333 self.db.delete_row_by_key("images", "uuid", image['image_id'])
1334 return content
1335 else:
1336 raise ovimException("Error deleting tenant '%s' " % tenant_id, HTTP_Internal_Server_Error)
1337
1338 def edit_tenant(self, tenant_id, tenant_data):
1339 """
1340 Update a tenant data identified by tenant id
1341 :param tenant_id: tenant id
1342 :param tenant_data: Dictionary with tenant data
1343 :return:
1344 """
1345
1346 # Look for the previous data
1347 result, tenant_data_old = self.db.get_table(FROM='tenants', WHERE={'uuid': tenant_id})
1348 if result < 0:
1349 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id, tenant_data_old),
1350 HTTP_Internal_Server_Error)
1351 elif result == 0:
1352 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1353
1354 # insert in data base
1355 result, content = self.db.update_rows('tenants', tenant_data, WHERE={'uuid': tenant_id}, log=True)
1356 if result >= 0:
1357 return content
1358 else:
1359 raise ovimException(str(content), -result)
1360
mirabal6045a9d2017-03-06 11:36:55 +01001361 def set_of_port_mapping(self, of_maps, ofc_id=None, switch_dpid=None, region=None):
1362 """
1363 Create new port mapping entry
1364 :param of_maps: List with port mapping information
1365 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1366 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1367 :param ofc_id: ofc id
1368 :param switch_dpid: switch dpid
1369 :param region: datacenter region id
1370 :return:
1371 """
1372
1373 for map in of_maps:
1374 if ofc_id:
1375 map['ofc_id'] = ofc_id
1376 if switch_dpid:
1377 map['switch_dpid'] = switch_dpid
1378 if region:
1379 map['region'] = region
tierno338e9982017-09-08 12:44:15 +02001380 if map.get("pci"):
1381 map["pci"] = map["pci"].lower()
mirabal6045a9d2017-03-06 11:36:55 +01001382
1383 for of_map in of_maps:
1384 result, uuid = self.db.new_row('of_port_mappings', of_map, True)
1385 if result > 0:
1386 of_map["uuid"] = uuid
1387 else:
1388 raise ovimException(str(uuid), -result)
1389 return of_maps
1390
1391 def clear_of_port_mapping(self, db_filter={}):
1392 """
1393 Clear port mapping filtering using db_filter dict
1394 :param db_filter: Parameter to filter during remove process
1395 :return:
1396 """
1397 result, content = self.db.delete_row_by_dict(FROM='of_port_mappings', WHERE=db_filter)
1398 # delete_row_by_key
1399 if result >= 0:
1400 return content
1401 else:
1402 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter)),
1403 HTTP_Internal_Server_Error)
1404
1405 def get_of_port_mappings(self, column=None, db_filter=None, db_limit=None):
1406 """
1407 Retrive port mapping from DB
1408 :param column:
1409 :param db_filter:
1410 :return:
1411 """
1412 result, content = self.db.get_table(SELECT=column, WHERE=db_filter, FROM='of_port_mappings', LIMIT=db_limit)
1413
1414 if result < 0:
1415 self.logger.error("get_of_port_mappings Error %d %s", result, content)
1416 raise ovimException(str(content), -result)
1417 else:
1418 return content
1419
mirabalb716ac52017-02-10 14:47:53 +01001420 def get_dhcp_controller(self):
1421 """
1422 Create an host_thread object for manage openvim controller and not create a thread for itself
1423 :return: dhcp_host openvim controller object
1424 """
1425
1426 if 'openvim_controller' in self.config['host_threads']:
1427 return self.config['host_threads']['openvim_controller']
1428
1429 bridge_ifaces = []
1430 controller_ip = self.config['ovs_controller_ip']
tiernoa6933042017-05-24 16:54:33 +02001431 ovs_controller_user = self.config.get('ovs_controller_user')
mirabalb716ac52017-02-10 14:47:53 +01001432
1433 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
1434 host_develop_mode = True if self.config['mode'] == 'development' else False
1435
1436 dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip,
tiernoa6933042017-05-24 16:54:33 +02001437 password=self.config.get('ovs_controller_password'),
1438 keyfile=self.config.get('ovs_controller_keyfile'),
tiernoe0c28c12017-05-04 18:44:40 +02001439 db=self.config["db"], db_lock=self.config["db_lock"], test=host_test_mode,
tiernoa6933042017-05-24 16:54:33 +02001440 image_path=self.config['host_image_path'], version=self.config['version'],
mirabalb716ac52017-02-10 14:47:53 +01001441 host_id='openvim_controller', develop_mode=host_develop_mode,
tiernoe0c28c12017-05-04 18:44:40 +02001442 develop_bridge_iface=bridge_ifaces,
1443 logger_name=self.logger_name + ".host.controller",
tiernof135eff2017-04-19 19:11:53 +02001444 debug=self.config.get('log_level_host'))
tiernoa6933042017-05-24 16:54:33 +02001445 # dhcp_host.start()
mirabalb716ac52017-02-10 14:47:53 +01001446 self.config['host_threads']['openvim_controller'] = dhcp_host
mirabal42ca0092017-06-14 05:42:30 -05001447 try:
1448 dhcp_host.check_connectivity()
1449 except Exception as e:
1450 pass
1451
mirabalb716ac52017-02-10 14:47:53 +01001452 return dhcp_host
1453
mirabal6878e3f2017-06-05 09:19:26 -05001454 def launch_dhcp_server(self, vlan, first_ip, last_ip, cidr, gateway, dns, routes):
mirabalb716ac52017-02-10 14:47:53 +01001455 """
1456 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1457 :param vlan: vlan identifier
1458 :param first_ip: First dhcp range ip
1459 :param last_ip: Last dhcp range ip
1460 :param cidr: net cidr
mirabale9f6f1a2017-02-16 17:57:35 +01001461 :param gateway: net gateway
mirabalb716ac52017-02-10 14:47:53 +01001462 :return:
1463 """
1464 ip_tools = IPNetwork(cidr)
1465 dhcp_netmask = str(ip_tools.netmask)
1466 ip_range = [first_ip, last_ip]
1467
1468 dhcp_path = self.config['ovs_controller_file_path']
1469
1470 controller_host = self.get_dhcp_controller()
mirabale16a6362017-07-10 05:45:56 -05001471
mirabal6878e3f2017-06-05 09:19:26 -05001472 # controller_host.create_linux_bridge(vlan)
1473 controller_host.create_dhcp_interfaces(vlan, first_ip, dhcp_netmask)
1474 dhcp_path = self.config['ovs_controller_file_path']
1475 controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path, gateway, dns, routes)
1476
1477 def launch_link_bridge_to_ovs(self, vlan, gateway, dhcp_cidr, links=None, routes=None):
1478 """
1479 Launch creating of connections (veth) between user bridge (link) and OVS
1480 :param vlan:
1481 :param gateway:
1482 :param links:
1483 :return:
1484 """
1485
1486 if links:
1487 controller_host = self.get_dhcp_controller()
1488 for link in links:
1489 if 'iface' in link and 'nat' not in link:
1490 controller_host.create_link_bridge_to_ovs(vlan, link['iface'])
1491 elif 'nat' in link:
1492 controller_host.create_qrouter_ovs_connection(vlan, gateway, dhcp_cidr)
1493 controller_host.create_qrouter_br_connection(vlan, dhcp_cidr, link)
1494
1495 if len(routes):
1496 controller_host.add_ns_routes(vlan, routes)
1497
1498 def delete_link_bridge_to_ovs(self, vlan, links=None):
1499 """
1500 Delete connections (veth) between user bridge (link) and OVS
1501 :param vlan:
1502 :param links:
1503 :return:
1504 """
1505 if links:
1506 controller_host = self.get_dhcp_controller()
1507
1508 for link in links:
1509 if 'iface' in link and 'nat' not in link:
1510 controller_host.remove_link_bridge_to_ovs(vlan, link['iface'])
1511 elif 'nat' in link:
1512 controller_host.delete_qrouter_connection(vlan, link['iface'])
1513
mirabalb716ac52017-02-10 14:47:53 +01001514
mirabald87877c2017-03-31 15:15:52 +02001515if __name__ == "__main__":
1516
1517 parser = argparse.ArgumentParser()
tierno46ca3a92017-04-05 19:49:24 +02001518 parser.add_argument("-v","--version", help="show ovim library version", action="store_true")
1519 parser.add_argument("--database-version", help="show required database version", action="store_true")
mirabald87877c2017-03-31 15:15:52 +02001520 args = parser.parse_args()
1521 if args.version:
1522 print ('openvimd version {} {}'.format(ovim.get_version(), ovim.get_version_date()))
1523 print ('(c) Copyright Telefonica')
tierno46ca3a92017-04-05 19:49:24 +02001524 elif args.database_version:
1525 print ('required database version: {}'.format(ovim.get_database_version()))
mirabalb716ac52017-02-10 14:47:53 +01001526