blob: 6b9545604322cf09827e4ce378cb6c96f391921e [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$"
tierno9a8846d2018-06-28 15:42:25 +020046__version__ = "0.5.25-r545"
47version_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
mirabal9e194592017-02-17 11:03:25 +0100504 def show_network(self, network_id, db_filter={}):
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:
mirabale9f6f1a2017-02-16 17:57:35 +0100521 raise ovimException("show_network network '%s' not found" % network_id, -result)
mirabal65ba8f82017-02-15 12:36:33 +0100522 else:
523 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
mirabale9f6f1a2017-02-16 17:57:35 +0100524 # get ports from DB
mirabal65ba8f82017-02-15 12:36:33 +0100525 result, ports = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
mirabale9f6f1a2017-02-16 17:57:35 +0100526 WHERE={'net_id': network_id}, LIMIT=100)
mirabal65ba8f82017-02-15 12:36:33 +0100527 if len(ports) > 0:
528 content[0]['ports'] = ports
mirabale9f6f1a2017-02-16 17:57:35 +0100529 convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
tierno9a8846d2018-06-28 15:42:25 +0200530
531 result, flows = self.db.get_table(FROM='of_flows', SELECT=('priority', 'vlan_id', 'ingress_port', 'src_mac', 'dst_mac', 'actions'),
532 WHERE={'net_id': network_id}, LIMIT=100)
533 if len(flows) > 0:
534 content[0]['flows'] = flows
mirabale9f6f1a2017-02-16 17:57:35 +0100535 return content[0]
536
537 def new_network(self, network):
mirabal65ba8f82017-02-15 12:36:33 +0100538 """
mirabale9f6f1a2017-02-16 17:57:35 +0100539 Create a net in DB
mirabal65ba8f82017-02-15 12:36:33 +0100540 :return:
541 """
542 tenant_id = network.get('tenant_id')
543
544 if tenant_id:
545 result, _ = self.db.get_table(FROM='tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id, "enabled": True})
546 if result <= 0:
547 raise ovimException("set_network error, no tenant founded", -result)
548
549 bridge_net = None
550 # check valid params
551 net_provider = network.get('provider')
552 net_type = network.get('type')
mirabal65ba8f82017-02-15 12:36:33 +0100553 net_vlan = network.get("vlan")
554 net_bind_net = network.get("bind_net")
555 net_bind_type = network.get("bind_type")
tiernoa290d8f2017-05-03 17:42:52 +0200556 net_region = network.get("region")
mirabal65ba8f82017-02-15 12:36:33 +0100557 name = network["name"]
558
559 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
560 vlan_index = name.rfind(":")
561 if not net_bind_net and not net_bind_type and vlan_index > 1:
562 try:
563 vlan_tag = int(name[vlan_index + 1:])
564 if not vlan_tag and vlan_tag < 4096:
565 net_bind_net = name[:vlan_index]
566 net_bind_type = "vlan:" + name[vlan_index + 1:]
567 except:
568 pass
569
570 if net_bind_net:
571 # look for a valid net
572 if self._check_valid_uuid(net_bind_net):
573 net_bind_key = "uuid"
574 else:
575 net_bind_key = "name"
576 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
577 if result < 0:
578 raise ovimException(' getting nets from db ' + content, HTTP_Internal_Server_Error)
579 elif result == 0:
580 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
581 elif result > 1:
582 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
583 network["bind_net"] = content[0]["uuid"]
584
585 if net_bind_type:
586 if net_bind_type[0:5] != "vlan:":
587 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
588 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
589 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
590 HTTP_Bad_Request)
591 network["bind_type"] = net_bind_type
592
593 if net_provider:
594 if net_provider[:9] == "openflow:":
595 if net_type:
596 if net_type != "ptp" and net_type != "data":
597 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
598 HTTP_Bad_Request)
599 else:
600 net_type = 'data'
601 else:
602 if net_type:
603 if net_type != "bridge_man" and net_type != "bridge_data":
604 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
605 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
606 else:
607 net_type = 'bridge_man'
608
609 if not net_type:
610 net_type = 'bridge_man'
611
612 if net_provider:
613 if net_provider[:7] == 'bridge:':
614 # check it is one of the pre-provisioned bridges
615 bridge_net_name = net_provider[7:]
616 for brnet in self.config['bridge_nets']:
617 if brnet[0] == bridge_net_name: # free
tierno11c45e72017-05-17 12:04:05 +0000618 if brnet[3]:
mirabal65ba8f82017-02-15 12:36:33 +0100619 raise ovimException("invalid 'provider:physical', "
620 "bridge '%s' is already used" % bridge_net_name, HTTP_Conflict)
621 bridge_net = brnet
622 net_vlan = brnet[1]
623 break
mirabale9f6f1a2017-02-16 17:57:35 +0100624 # if bridge_net==None:
625 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
626 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
627 # return
628
mirabal65ba8f82017-02-15 12:36:33 +0100629 elif self.config['network_type'] == 'bridge' and (net_type == 'bridge_data' or net_type == 'bridge_man'):
630 # look for a free precreated nets
631 for brnet in self.config['bridge_nets']:
632 if not brnet[3]: # free
633 if not bridge_net:
634 if net_type == 'bridge_man': # look for the smaller speed
635 if brnet[2] < bridge_net[2]:
636 bridge_net = brnet
637 else: # look for the larger speed
638 if brnet[2] > bridge_net[2]:
639 bridge_net = brnet
640 else:
641 bridge_net = brnet
642 net_vlan = brnet[1]
643 if not bridge_net:
644 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
645 "will overcome this limit", HTTP_Bad_Request)
646 else:
mirabale9f6f1a2017-02-16 17:57:35 +0100647 self.logger.debug("using net " + bridge_net)
mirabal65ba8f82017-02-15 12:36:33 +0100648 net_provider = "bridge:" + bridge_net[0]
649 net_vlan = bridge_net[1]
650 elif net_type == 'bridge_data' or net_type == 'bridge_man' and self.config['network_type'] == 'ovs':
651 net_provider = 'OVS'
tiernoa290d8f2017-05-03 17:42:52 +0200652 if not net_region:
653 if net_type == "data" or net_type == "ptp":
654 net_region = "__DATA__"
655 elif net_provider == "OVS":
656 net_region = "__OVS__"
mirabal65ba8f82017-02-15 12:36:33 +0100657 if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
tiernoa290d8f2017-05-03 17:42:52 +0200658 net_vlan = self.db.get_free_net_vlan(net_region)
mirabal65ba8f82017-02-15 12:36:33 +0100659 if net_vlan < 0:
660 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error)
661 if net_provider == 'OVS':
662 net_provider = 'OVS' + ":" + str(net_vlan)
663
664 network['provider'] = net_provider
665 network['type'] = net_type
666 network['vlan'] = net_vlan
tiernoa290d8f2017-05-03 17:42:52 +0200667 network['region'] = net_region
mirabal65ba8f82017-02-15 12:36:33 +0100668 dhcp_integrity = True
tierno5f79a262017-11-28 11:53:01 +0100669 if network.get('enable_dhcp'):
mirabal65ba8f82017-02-15 12:36:33 +0100670 dhcp_integrity = self._check_dhcp_data_integrity(network)
mirabal6878e3f2017-06-05 09:19:26 -0500671
672 if network.get('links'):
673 network['links'] = yaml.safe_dump(network['links'], default_flow_style=True, width=256)
674 if network.get('dns'):
675 network['dns'] = yaml.safe_dump(network['dns'], default_flow_style=True, width=256)
676 if network.get('routes'):
677 network['routes'] = yaml.safe_dump(network['routes'], default_flow_style=True, width=256)
mirabal65ba8f82017-02-15 12:36:33 +0100678
679 result, content = self.db.new_row('nets', network, True, True)
tierno5f79a262017-11-28 11:53:01 +0100680 if result >= 0: # and dhcp_integrity:
mirabal65ba8f82017-02-15 12:36:33 +0100681 if bridge_net:
682 bridge_net[3] = content
tierno5f79a262017-11-28 11:53:01 +0100683 if self.config.get("dhcp_server") and self.config['network_type'] == 'bridge':
mirabal65ba8f82017-02-15 12:36:33 +0100684 if network["name"] in self.config["dhcp_server"].get("nets", ()):
685 self.config["dhcp_nets"].append(content)
mirabale9f6f1a2017-02-16 17:57:35 +0100686 self.logger.debug("dhcp_server: add new net", content)
tierno11c45e72017-05-17 12:04:05 +0000687 elif bridge_net and bridge_net[0] in self.config["dhcp_server"].get("bridge_ifaces", ()):
mirabal65ba8f82017-02-15 12:36:33 +0100688 self.config["dhcp_nets"].append(content)
mirabale9f6f1a2017-02-16 17:57:35 +0100689 self.logger.debug("dhcp_server: add new net", content, content)
mirabal65ba8f82017-02-15 12:36:33 +0100690 return content
691 else:
tierno5f79a262017-11-28 11:53:01 +0100692 raise ovimException("Error creating network: {}".format(content), -result)
693
mirabale9f6f1a2017-02-16 17:57:35 +0100694# TODO kei change update->edit
mirabal65ba8f82017-02-15 12:36:33 +0100695
mirabale9f6f1a2017-02-16 17:57:35 +0100696 def edit_network(self, network_id, network):
mirabal65ba8f82017-02-15 12:36:33 +0100697 """
mirabale9f6f1a2017-02-16 17:57:35 +0100698 Update entwork data byt id
mirabal65ba8f82017-02-15 12:36:33 +0100699 :return:
700 """
mirabale9f6f1a2017-02-16 17:57:35 +0100701 # Look for the previous data
702 where_ = {'uuid': network_id}
703 result, network_old = self.db.get_table(FROM='nets', WHERE=where_)
704 if result < 0:
705 raise ovimException("Error updating network %s" % network_old, HTTP_Internal_Server_Error)
706 elif result == 0:
707 raise ovimException('network %s not found' % network_id, HTTP_Not_Found)
708 # get ports
709 nbports, content = self.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
710 WHERE={'net_id': network_id}, LIMIT=100)
711 if result < 0:
712 raise ovimException("http_put_network_id error %d %s" % (result, network_old), HTTP_Internal_Server_Error)
713 if nbports > 0:
714 if 'type' in network and network['type'] != network_old[0]['type']:
715 raise ovimException("Can not change type of network while having ports attached",
716 HTTP_Method_Not_Allowed)
717 if 'vlan' in network and network['vlan'] != network_old[0]['vlan']:
718 raise ovimException("Can not change vlan of network while having ports attached",
719 HTTP_Method_Not_Allowed)
mirabal65ba8f82017-02-15 12:36:33 +0100720
mirabale9f6f1a2017-02-16 17:57:35 +0100721 # check valid params
722 net_provider = network.get('provider', network_old[0]['provider'])
723 net_type = network.get('type', network_old[0]['type'])
724 net_bind_net = network.get("bind_net")
725 net_bind_type = network.get("bind_type")
726 if net_bind_net:
727 # look for a valid net
728 if self._check_valid_uuid(net_bind_net):
729 net_bind_key = "uuid"
730 else:
731 net_bind_key = "name"
732 result, content = self.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net})
733 if result < 0:
734 raise ovimException('Getting nets from db ' + content, HTTP_Internal_Server_Error)
735 elif result == 0:
736 raise ovimException("bind_net %s '%s'not found" % (net_bind_key, net_bind_net), HTTP_Bad_Request)
737 elif result > 1:
738 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net),
739 HTTP_Bad_Request)
740 network["bind_net"] = content[0]["uuid"]
741 if net_bind_type:
742 if net_bind_type[0:5] != "vlan:":
743 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request)
744 if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:]) <= 0:
745 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
746 HTTP_Bad_Request)
747 if net_provider:
748 if net_provider[:9] == "openflow:":
749 if net_type != "ptp" and net_type != "data":
750 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request)
751 else:
752 if net_type != "bridge_man" and net_type != "bridge_data":
753 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
754 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request)
mirabal65ba8f82017-02-15 12:36:33 +0100755
mirabale9f6f1a2017-02-16 17:57:35 +0100756 # insert in data base
757 result, content = self.db.update_rows('nets', network, WHERE={'uuid': network_id}, log=True)
758 if result >= 0:
759 # if result > 0 and nbports>0 and 'admin_state_up' in network
760 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
761 if result > 0:
mirabal7bbf50e2017-03-13 15:15:18 +0100762
763 try:
tiernoaa941462017-03-29 15:10:28 +0200764 if nbports:
765 self.net_update_ofc_thread(network_id)
mirabal7bbf50e2017-03-13 15:15:18 +0100766 except ovimException as e:
767 raise ovimException("Error while launching openflow rules in network '{}' {}"
768 .format(network_id, str(e)), HTTP_Internal_Server_Error)
769 except Exception as e:
770 raise ovimException("Error while launching openflow rules in network '{}' {}"
771 .format(network_id, str(e)), HTTP_Internal_Server_Error)
772
mirabale9f6f1a2017-02-16 17:57:35 +0100773 if self.config.get("dhcp_server"):
774 if network_id in self.config["dhcp_nets"]:
775 self.config["dhcp_nets"].remove(network_id)
mirabal7bbf50e2017-03-13 15:15:18 +0100776 if network.get("name", network_old[0]["name"]) in self.config["dhcp_server"].get("nets", ()):
mirabale9f6f1a2017-02-16 17:57:35 +0100777 self.config["dhcp_nets"].append(network_id)
778 else:
mirabal7bbf50e2017-03-13 15:15:18 +0100779 net_bind = network.get("bind_type", network_old[0]["bind_type"])
780 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 +0100781 "bridge_ifaces", ()):
782 self.config["dhcp_nets"].append(network_id)
783 return network_id
mirabal65ba8f82017-02-15 12:36:33 +0100784 else:
mirabale9f6f1a2017-02-16 17:57:35 +0100785 raise ovimException(content, -result)
mirabal65ba8f82017-02-15 12:36:33 +0100786
mirabale9f6f1a2017-02-16 17:57:35 +0100787 def delete_network(self, network_id):
mirabal9e194592017-02-17 11:03:25 +0100788 """
789 Delete network by network id
790 :param network_id: network id
791 :return:
792 """
mirabal0ec17ec2017-07-19 08:43:09 -0500793 net_data = self.show_network(network_id)
mirabale9f6f1a2017-02-16 17:57:35 +0100794
795 # delete from the data base
796 result, content = self.db.delete_row('nets', network_id)
797
798 if result == 0:
799 raise ovimException("Network %s not found " % network_id, HTTP_Not_Found)
800 elif result > 0:
801 for brnet in self.config['bridge_nets']:
802 if brnet[3] == network_id:
803 brnet[3] = None
804 break
805 if self.config.get("dhcp_server") and network_id in self.config["dhcp_nets"]:
806 self.config["dhcp_nets"].remove(network_id)
mirabal0ec17ec2017-07-19 08:43:09 -0500807
808 if net_data.get('enable_dhcp'):
809 dhcp_path = self.config['ovs_controller_file_path']
810 dhcp_controller = self.get_dhcp_controller()
811 dhcp_controller.delete_dhcp_server(net_data['vlan'], network_id, dhcp_path)
812 dhcp_controller.delete_dhcp_port(net_data['vlan'], network_id, dhcp_path)
813 links = yaml.load(net_data.get('links'))
814 if links:
815 links = yaml.load(net_data.get('links'))
816 self.delete_link_bridge_to_ovs(net_data['vlan'], links)
817
818 return content
mirabale9f6f1a2017-02-16 17:57:35 +0100819 else:
tierno11c45e72017-05-17 12:04:05 +0000820 raise ovimException("Error deleting network '{}': {}".format(network_id, content), -result)
mirabal65ba8f82017-02-15 12:36:33 +0100821
822 def get_openflow_rules(self, network_id=None):
823 """
824 Get openflow id from DB
825 :param network_id: Network id, if none all networks will be retrieved
826 :return: Return a list with Openflow rules per net
827 """
828 # ignore input data
829 if not network_id:
830 where_ = {}
831 else:
832 where_ = {"net_id": network_id}
mirabal65ba8f82017-02-15 12:36:33 +0100833 result, content = self.db.get_table(
mirabalf9a1a8d2017-03-15 12:42:27 +0100834 SELECT=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
mirabal65ba8f82017-02-15 12:36:33 +0100835 WHERE=where_, FROM='of_flows')
836
837 if result < 0:
838 raise ovimException(str(content), -result)
839 return content
840
mirabale9f6f1a2017-02-16 17:57:35 +0100841 def edit_openflow_rules(self, network_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100842
843 """
844 To make actions over the net. The action is to reinstall the openflow rules
845 network_id can be 'all'
846 :param network_id: Network id, if none all networks will be retrieved
847 :return : Number of nets updated
848 """
849
850 # ignore input data
851 if not network_id:
852 where_ = {}
853 else:
854 where_ = {"uuid": network_id}
855 result, content = self.db.get_table(SELECT=("uuid", "type"), WHERE=where_, FROM='nets')
856
857 if result < 0:
858 raise ovimException(str(content), -result)
859
860 for net in content:
861 if net["type"] != "ptp" and net["type"] != "data":
862 result -= 1
863 continue
mirabal7bbf50e2017-03-13 15:15:18 +0100864
865 try:
866 self.net_update_ofc_thread(net['uuid'])
867 except ovimException as e:
868 raise ovimException("Error updating network'{}' {}".format(net['uuid'], str(e)),
869 HTTP_Internal_Server_Error)
870 except Exception as e:
871 raise ovimException("Error updating network '{}' {}".format(net['uuid'], str(e)),
872 HTTP_Internal_Server_Error)
873
mirabal65ba8f82017-02-15 12:36:33 +0100874 return result
875
mirabalf9a1a8d2017-03-15 12:42:27 +0100876 def delete_openflow_rules(self, ofc_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100877 """
878 To make actions over the net. The action is to delete ALL openflow rules
879 :return: return operation result
880 """
mirabalf9a1a8d2017-03-15 12:42:27 +0100881
882 if not ofc_id:
883 if 'Default' in self.config['ofcs_thread']:
884 r, c = self.config['ofcs_thread']['Default'].insert_task("clear-all")
885 else:
886 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
887
888 elif ofc_id in self.config['ofcs_thread']:
889 r, c = self.config['ofcs_thread'][ofc_id].insert_task("clear-all")
890
891 # ignore input data
892 if r < 0:
893 raise ovimException(str(c), -r)
894 else:
895 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
mirabal65ba8f82017-02-15 12:36:33 +0100896 return r
897
mirabalf9a1a8d2017-03-15 12:42:27 +0100898 def get_openflow_ports(self, ofc_id=None):
mirabal65ba8f82017-02-15 12:36:33 +0100899 """
900 Obtain switch ports names of openflow controller
901 :return: Return flow ports in DB
902 """
mirabalf9a1a8d2017-03-15 12:42:27 +0100903 if not ofc_id:
904 if 'Default' in self.config['ofcs_thread']:
905 conn = self.config['ofcs_thread']['Default'].OF_connector
906 else:
907 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found)
908
tierno11c45e72017-05-17 12:04:05 +0000909 elif ofc_id in self.config['ofcs_thread']:
mirabalf9a1a8d2017-03-15 12:42:27 +0100910 conn = self.config['ofcs_thread'][ofc_id].OF_connector
911 else:
912 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id), HTTP_Not_Found)
913 return conn.pp2ofi
tierno57f7bda2017-02-09 12:01:55 +0100914
915 def get_ports(self, columns=None, filter={}, limit=None):
916 # result, content = my.db.get_ports(where_)
917 result, content = self.db.get_table(SELECT=columns, WHERE=filter, FROM='ports', LIMIT=limit)
918 if result < 0:
919 self.logger.error("http_get_ports Error %d %s", result, content)
920 raise ovimException(str(content), -result)
921 else:
922 convert_boolean(content, ('admin_state_up',))
923 return content
924
tierno57f7bda2017-02-09 12:01:55 +0100925 def new_port(self, port_data):
926 port_data['type'] = 'external'
927 if port_data.get('net_id'):
928 # check that new net has the correct type
929 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
930 if result < 0:
931 raise ovimException(str(new_net), -result)
932 # insert in data base
933 result, uuid = self.db.new_row('ports', port_data, True, True)
934 if result > 0:
935 if 'net_id' in port_data:
mirabal7bbf50e2017-03-13 15:15:18 +0100936 try:
937 self.net_update_ofc_thread(port_data['net_id'])
938 except ovimException as e:
939 raise ovimException("Cannot insert a task for updating network '{}' {}"
940 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
941 except Exception as e:
942 raise ovimException("Cannot insert a task for updating network '{}' {}"
943 .format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
944
tierno57f7bda2017-02-09 12:01:55 +0100945 return uuid
946 else:
947 raise ovimException(str(uuid), -result)
948
mirabal37829452017-03-09 14:41:21 +0100949 def new_external_port(self, port_data):
950 """
951 Create new external port and check port mapping correspondence
952 :param port_data: port_data = {
953 'region': 'datacenter region',
954 'compute_node': 'compute node id',
955 'pci': 'pci port address',
956 'vlan': 'net vlan',
957 'net_id': 'net id',
958 'tenant_id': 'tenant id',
959 'mac': 'switch mac',
960 'name': 'port name'
961 'ip_address': 'ip address - optional'}
962 :return:
963 """
964
965 port_data['type'] = 'external'
966
967 if port_data.get('net_id'):
968 # check that new net has the correct type
969 result, new_net = self.db.check_target_net(port_data['net_id'], None, 'external')
970 if result < 0:
971 raise ovimException(str(new_net), -result)
972 # insert in data base
973 db_filter = {}
974
975 if port_data.get('region'):
976 db_filter['region'] = port_data['region']
977 if port_data.get('pci'):
978 db_filter['pci'] = port_data['pci']
979 if port_data.get('compute_node'):
980 db_filter['compute_node'] = port_data['compute_node']
981
982 columns = ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
983 port_mapping_data = self.get_of_port_mappings(columns, db_filter)
984
985 if not len(port_mapping_data):
tierno16007502017-03-27 16:48:32 +0200986 raise ovimException("No port mapping founded for '{}'".format(str(db_filter)),
mirabal37829452017-03-09 14:41:21 +0100987 HTTP_Not_Found)
988 elif len(port_mapping_data) > 1:
989 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
990 HTTP_Conflict)
991
992 port_data['ofc_id'] = port_mapping_data[0]['ofc_id']
993 port_data['switch_dpid'] = port_mapping_data[0]['switch_dpid']
994 port_data['switch_port'] = port_mapping_data[0]['switch_port']
995 port_data['switch_mac'] = port_mapping_data[0]['switch_mac']
996
997 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
montesmoreno275b1992017-03-28 15:45:02 +0200998 if 'region' in port_data:
999 del port_data['region']
1000 if 'pci' in port_data:
1001 del port_data['pci']
1002 if 'compute_node' in port_data:
1003 del port_data['compute_node']
mirabal37829452017-03-09 14:41:21 +01001004
1005 result, uuid = self.db.new_row('ports', port_data, True, True)
1006 if result > 0:
mirabal7bbf50e2017-03-13 15:15:18 +01001007 try:
1008 self.net_update_ofc_thread(port_data['net_id'], port_data['ofc_id'])
1009 except ovimException as e:
1010 raise ovimException("Cannot insert a task for updating network '{}' {}".
1011 format(port_data['net_id'], str(e)), HTTP_Internal_Server_Error)
1012 except Exception as e:
1013 raise ovimException("Cannot insert a task for updating network '{}' {}"
1014 .format(port_data['net_id'], e), HTTP_Internal_Server_Error)
mirabal37829452017-03-09 14:41:21 +01001015 return uuid
1016 else:
1017 raise ovimException(str(uuid), -result)
1018
tiernoaa941462017-03-29 15:10:28 +02001019 def net_update_ofc_thread(self, net_id, ofc_id=None, switch_dpid=None):
mirabal7bbf50e2017-03-13 15:15:18 +01001020 """
1021 Insert a update net task by net id or ofc_id for each ofc thread
1022 :param net_id: network id
1023 :param ofc_id: openflow controller id
tiernoaa941462017-03-29 15:10:28 +02001024 :param switch_dpid: switch dpid
mirabal7bbf50e2017-03-13 15:15:18 +01001025 :return:
1026 """
1027 if not net_id:
1028 raise ovimException("No net_id received", HTTP_Internal_Server_Error)
1029
mirabal7bbf50e2017-03-13 15:15:18 +01001030 r = -1
1031 c = 'No valid ofc_id or switch_dpid received'
1032
1033 if not ofc_id:
1034 ports = self.get_ports(filter={"net_id": net_id})
1035 for port in ports:
1036 port_ofc_id = port.get('ofc_id', None)
1037 if port_ofc_id:
1038 ofc_id = port['ofc_id']
1039 switch_dpid = port['switch_dpid']
1040 break
tiernoaa941462017-03-29 15:10:28 +02001041 #TODO if not ofc_id: look at database table ofcs
1042
mirabal7bbf50e2017-03-13 15:15:18 +01001043
1044 # If no ofc_id found it, default ofc_id is used.
1045 if not ofc_id and not switch_dpid:
1046 ofc_id = "Default"
1047
1048 if ofc_id and ofc_id in self.config['ofcs_thread']:
1049 r, c = self.config['ofcs_thread'][ofc_id].insert_task("update-net", net_id)
1050 elif switch_dpid:
1051
1052 ofcs_dpid_list = self.config['ofcs_thread_dpid']
1053 for ofc_t in ofcs_dpid_list:
1054 if switch_dpid in ofc_t:
1055 r, c = ofc_t[switch_dpid].insert_task("update-net", net_id)
1056
1057 if r < 0:
tierno82232582017-03-15 18:09:16 +01001058 message = "Cannot insert a task for updating network '{}', {}".format(net_id, c)
mirabal7bbf50e2017-03-13 15:15:18 +01001059 self.logger.error(message)
1060 raise ovimException(message, HTTP_Internal_Server_Error)
1061
tierno57f7bda2017-02-09 12:01:55 +01001062 def delete_port(self, port_id):
1063 # Look for the previous port data
1064 result, ports = self.db.get_table(WHERE={'uuid': port_id, "type": "external"}, FROM='ports')
1065 if result < 0:
1066 raise ovimException("Cannot get port info from database: {}".format(ports), http_code=-result)
1067 # delete from the data base
1068 result, content = self.db.delete_row('ports', port_id)
1069 if result == 0:
1070 raise ovimException("External port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1071 elif result < 0:
1072 raise ovimException("Cannot delete port from database: {}".format(content), http_code=-result)
1073 # update network
1074 network = ports[0].get('net_id', None)
1075 if network:
1076 # change of net.
mirabal7bbf50e2017-03-13 15:15:18 +01001077
1078 try:
tiernoaa941462017-03-29 15:10:28 +02001079 self.net_update_ofc_thread(network, ofc_id=ports[0]["ofc_id"], switch_dpid=ports[0]["switch_dpid"])
mirabal7bbf50e2017-03-13 15:15:18 +01001080 except ovimException as e:
1081 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
1082 HTTP_Internal_Server_Error)
1083 except Exception as e:
1084 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network, str(e)),
1085 HTTP_Internal_Server_Error)
1086
tierno57f7bda2017-02-09 12:01:55 +01001087 return content
1088
tierno57f7bda2017-02-09 12:01:55 +01001089 def edit_port(self, port_id, port_data, admin=True):
1090 # Look for the previous port data
1091 result, content = self.db.get_table(FROM="ports", WHERE={'uuid': port_id})
1092 if result < 0:
1093 raise ovimException("Cannot get port info from database: {}".format(content), http_code=-result)
1094 elif result == 0:
1095 raise ovimException("Port '{}' not found".format(port_id), http_code=HTTP_Not_Found)
1096 port = content[0]
1097 nets = []
1098 host_id = None
1099 result = 1
1100 if 'net_id' in port_data:
1101 # change of net.
1102 old_net = port.get('net_id', None)
1103 new_net = port_data['net_id']
1104 if old_net != new_net:
1105
1106 if new_net:
1107 nets.append(new_net) # put first the new net, so that new openflow rules are created before removing the old ones
1108 if old_net:
1109 nets.append(old_net)
1110 if port['type'] == 'instance:bridge' or port['type'] == 'instance:ovs':
1111 raise ovimException("bridge interfaces cannot be attached to a different net", http_code=HTTP_Forbidden)
1112 elif port['type'] == 'external' and not admin:
1113 raise ovimException("Needed admin privileges",http_code=HTTP_Unauthorized)
1114 if new_net:
1115 # check that new net has the correct type
1116 result, new_net_dict = self.db.check_target_net(new_net, None, port['type'])
1117 if result < 0:
1118 raise ovimException("Error {}".format(new_net_dict), http_code=HTTP_Conflict)
1119 # change VLAN for SR-IOV ports
1120 if result >= 0 and port["type"] == "instance:data" and port["model"] == "VF": # TODO consider also VFnotShared
1121 if new_net:
1122 port_data["vlan"] = None
1123 else:
1124 port_data["vlan"] = new_net_dict["vlan"]
1125 # get host where this VM is allocated
1126 result, content = self.db.get_table(FROM="instances", WHERE={"uuid": port["instance_id"]})
1127 if result > 0:
1128 host_id = content[0]["host_id"]
1129
1130 # insert in data base
1131 if result >= 0:
1132 result, content = self.db.update_rows('ports', port_data, WHERE={'uuid': port_id}, log=False)
tiernoaa941462017-03-29 15:10:28 +02001133 port.update(port_data)
tierno57f7bda2017-02-09 12:01:55 +01001134
1135 # Insert task to complete actions
1136 if result > 0:
1137 for net_id in nets:
mirabal7bbf50e2017-03-13 15:15:18 +01001138 try:
tiernoaa941462017-03-29 15:10:28 +02001139 self.net_update_ofc_thread(net_id, port["ofc_id"], switch_dpid=port["switch_dpid"])
mirabal7bbf50e2017-03-13 15:15:18 +01001140 except ovimException as e:
1141 raise ovimException("Error updating network'{}' {}".format(net_id, str(e)),
1142 HTTP_Internal_Server_Error)
1143 except Exception as e:
1144 raise ovimException("Error updating network '{}' {}".format(net_id, str(e)),
1145 HTTP_Internal_Server_Error)
1146
tierno57f7bda2017-02-09 12:01:55 +01001147 if host_id:
1148 r, v = self.config['host_threads'][host_id].insert_task("edit-iface", port_id, old_net, new_net)
1149 if r < 0:
1150 self.logger.error("Error updating network '{}' {}".format(r,v))
1151 # TODO Do something if fails
1152 if result >= 0:
1153 return port_id
1154 else:
1155 raise ovimException("Error {}".format(content), http_code=-result)
mirabalb716ac52017-02-10 14:47:53 +01001156
mirabal9e194592017-02-17 11:03:25 +01001157 def new_of_controller(self, ofc_data):
1158 """
1159 Create a new openflow controller into DB
1160 :param ofc_data: Dict openflow controller data
1161 :return: openflow controller dpid
1162 """
1163
mirabal580435e2017-03-01 16:17:10 +01001164 result, ofc_uuid = self.db.new_row('ofcs', ofc_data, True, True)
mirabal9e194592017-02-17 11:03:25 +01001165 if result < 0:
mirabal580435e2017-03-01 16:17:10 +01001166 raise ovimException("New ofc Error %s" % ofc_uuid, HTTP_Internal_Server_Error)
1167
1168 ofc_data['uuid'] = ofc_uuid
1169 of_conn = self._load_of_module(ofc_data)
1170 self._create_ofc_task(ofc_uuid, ofc_data['dpid'], of_conn)
1171
1172 return ofc_uuid
mirabal9e194592017-02-17 11:03:25 +01001173
1174 def edit_of_controller(self, of_id, ofc_data):
1175 """
1176 Edit an openflow controller entry from DB
1177 :return:
1178 """
1179 if not ofc_data:
1180 raise ovimException("No data received during uptade OF contorller", http_code=HTTP_Internal_Server_Error)
1181
1182 old_of_controller = self.show_of_controller(of_id)
1183
1184 if old_of_controller:
1185 result, content = self.db.update_rows('ofcs', ofc_data, WHERE={'uuid': of_id}, log=False)
1186 if result >= 0:
1187 return ofc_data
1188 else:
1189 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1190 http_code=-result)
1191 else:
1192 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id),
1193 http_code=HTTP_Internal_Server_Error)
1194
1195 def delete_of_controller(self, of_id):
1196 """
1197 Delete an openflow controller from DB.
1198 :param of_id: openflow controller dpid
1199 :return:
1200 """
1201
mirabal580435e2017-03-01 16:17:10 +01001202 ofc = self.show_of_controller(of_id)
1203
Pablo Montes Moreno5b6f7492017-03-02 16:18:36 +01001204 result, content = self.db.delete_row("ofcs", of_id)
mirabal9e194592017-02-17 11:03:25 +01001205 if result < 0:
1206 raise ovimException("Cannot delete ofc from database: {}".format(content), http_code=-result)
1207 elif result == 0:
1208 raise ovimException("ofc {} not found ".format(content), http_code=HTTP_Not_Found)
mirabal580435e2017-03-01 16:17:10 +01001209
1210 ofc_thread = self.config['ofcs_thread'][of_id]
1211 del self.config['ofcs_thread'][of_id]
1212 for ofc_th in self.config['ofcs_thread_dpid']:
1213 if ofc['dpid'] in ofc_th:
1214 self.config['ofcs_thread_dpid'].remove(ofc_th)
1215
1216 ofc_thread.insert_task("exit")
1217 #ofc_thread.join()
1218
mirabal9e194592017-02-17 11:03:25 +01001219 return content
1220
1221 def show_of_controller(self, uuid):
1222 """
1223 Show an openflow controller by dpid from DB.
1224 :param db_filter: List with where query parameters
1225 :return:
1226 """
1227
1228 result, content = self.db.get_table(FROM='ofcs', WHERE={"uuid": uuid}, LIMIT=100)
1229
1230 if result == 0:
1231 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid),
1232 http_code=HTTP_Not_Found)
1233 elif result < 0:
1234 raise ovimException("Openflow controller with uuid '{}' error".format(uuid),
1235 http_code=HTTP_Internal_Server_Error)
Pablo Montes Moreno5b6f7492017-03-02 16:18:36 +01001236 return content[0]
mirabal9e194592017-02-17 11:03:25 +01001237
mirabalfbfb7972017-02-27 17:36:17 +01001238 def get_of_controllers(self, columns=None, db_filter={}, limit=None):
mirabal9e194592017-02-17 11:03:25 +01001239 """
1240 Show an openflow controllers from DB.
1241 :param columns: List with SELECT query parameters
1242 :param db_filter: List with where query parameters
mirabalfbfb7972017-02-27 17:36:17 +01001243 :param limit: result Limit
mirabal9e194592017-02-17 11:03:25 +01001244 :return:
1245 """
mirabalfbfb7972017-02-27 17:36:17 +01001246 result, content = self.db.get_table(SELECT=columns, FROM='ofcs', WHERE=db_filter, LIMIT=limit)
mirabal9e194592017-02-17 11:03:25 +01001247
1248 if result < 0:
1249 raise ovimException(str(content), -result)
1250
1251 return content
1252
mirabalfbfb7972017-02-27 17:36:17 +01001253 def get_tenants(self, columns=None, db_filter={}, limit=None):
1254 """
1255 Retrieve tenant list from DB
1256 :param columns: List with SELECT query parameters
1257 :param db_filter: List with where query parameters
1258 :param limit: result limit
1259 :return:
1260 """
1261 result, content = self.db.get_table(FROM='tenants', SELECT=columns, WHERE=db_filter, LIMIT=limit)
1262 if result < 0:
1263 raise ovimException('get_tenatns Error {}'.format(str(content)), -result)
1264 else:
1265 convert_boolean(content, ('enabled',))
1266 return content
1267
1268 def show_tenant_id(self, tenant_id):
1269 """
1270 Get tenant from DB by id
1271 :param tenant_id: tenant id
1272 :return:
1273 """
1274 result, content = self.db.get_table(FROM='tenants', SELECT=('uuid', 'name', 'description', 'enabled'),
1275 WHERE={"uuid": tenant_id})
1276 if result < 0:
1277 raise ovimException(str(content), -result)
1278 elif result == 0:
1279 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1280 else:
1281 convert_boolean(content, ('enabled',))
1282 return content[0]
1283
1284 def new_tentant(self, tenant):
1285 """
1286 Create a tenant and store in DB
1287 :param tenant: Dictionary with tenant data
1288 :return: the uuid of created tenant. Raise exception upon error
1289 """
1290
1291 # insert in data base
1292 result, tenant_uuid = self.db.new_tenant(tenant)
1293
1294 if result >= 0:
1295 return tenant_uuid
1296 else:
1297 raise ovimException(str(tenant_uuid), -result)
1298
1299 def delete_tentant(self, tenant_id):
1300 """
1301 Delete a tenant from the database.
1302 :param tenant_id: Tenant id
1303 :return: delete tenant id
1304 """
1305
1306 # check permissions
1307 r, tenants_flavors = self.db.get_table(FROM='tenants_flavors', SELECT=('flavor_id', 'tenant_id'),
1308 WHERE={'tenant_id': tenant_id})
1309 if r <= 0:
1310 tenants_flavors = ()
1311 r, tenants_images = self.db.get_table(FROM='tenants_images', SELECT=('image_id', 'tenant_id'),
1312 WHERE={'tenant_id': tenant_id})
1313 if r <= 0:
1314 tenants_images = ()
1315
1316 result, content = self.db.delete_row('tenants', tenant_id)
1317 if result == 0:
1318 raise ovimException("tenant '%s' not found" % tenant_id, HTTP_Not_Found)
1319 elif result > 0:
1320 for flavor in tenants_flavors:
1321 self.db.delete_row_by_key("flavors", "uuid", flavor['flavor_id'])
1322 for image in tenants_images:
1323 self.db.delete_row_by_key("images", "uuid", image['image_id'])
1324 return content
1325 else:
1326 raise ovimException("Error deleting tenant '%s' " % tenant_id, HTTP_Internal_Server_Error)
1327
1328 def edit_tenant(self, tenant_id, tenant_data):
1329 """
1330 Update a tenant data identified by tenant id
1331 :param tenant_id: tenant id
1332 :param tenant_data: Dictionary with tenant data
1333 :return:
1334 """
1335
1336 # Look for the previous data
1337 result, tenant_data_old = self.db.get_table(FROM='tenants', WHERE={'uuid': tenant_id})
1338 if result < 0:
1339 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id, tenant_data_old),
1340 HTTP_Internal_Server_Error)
1341 elif result == 0:
1342 raise ovimException("tenant with uuid='{}' not found".format(tenant_id), HTTP_Not_Found)
1343
1344 # insert in data base
1345 result, content = self.db.update_rows('tenants', tenant_data, WHERE={'uuid': tenant_id}, log=True)
1346 if result >= 0:
1347 return content
1348 else:
1349 raise ovimException(str(content), -result)
1350
mirabal6045a9d2017-03-06 11:36:55 +01001351 def set_of_port_mapping(self, of_maps, ofc_id=None, switch_dpid=None, region=None):
1352 """
1353 Create new port mapping entry
1354 :param of_maps: List with port mapping information
1355 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1356 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1357 :param ofc_id: ofc id
1358 :param switch_dpid: switch dpid
1359 :param region: datacenter region id
1360 :return:
1361 """
1362
1363 for map in of_maps:
1364 if ofc_id:
1365 map['ofc_id'] = ofc_id
1366 if switch_dpid:
1367 map['switch_dpid'] = switch_dpid
1368 if region:
1369 map['region'] = region
tierno338e9982017-09-08 12:44:15 +02001370 if map.get("pci"):
1371 map["pci"] = map["pci"].lower()
mirabal6045a9d2017-03-06 11:36:55 +01001372
1373 for of_map in of_maps:
1374 result, uuid = self.db.new_row('of_port_mappings', of_map, True)
1375 if result > 0:
1376 of_map["uuid"] = uuid
1377 else:
1378 raise ovimException(str(uuid), -result)
1379 return of_maps
1380
1381 def clear_of_port_mapping(self, db_filter={}):
1382 """
1383 Clear port mapping filtering using db_filter dict
1384 :param db_filter: Parameter to filter during remove process
1385 :return:
1386 """
1387 result, content = self.db.delete_row_by_dict(FROM='of_port_mappings', WHERE=db_filter)
1388 # delete_row_by_key
1389 if result >= 0:
1390 return content
1391 else:
1392 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter)),
1393 HTTP_Internal_Server_Error)
1394
1395 def get_of_port_mappings(self, column=None, db_filter=None, db_limit=None):
1396 """
1397 Retrive port mapping from DB
1398 :param column:
1399 :param db_filter:
1400 :return:
1401 """
1402 result, content = self.db.get_table(SELECT=column, WHERE=db_filter, FROM='of_port_mappings', LIMIT=db_limit)
1403
1404 if result < 0:
1405 self.logger.error("get_of_port_mappings Error %d %s", result, content)
1406 raise ovimException(str(content), -result)
1407 else:
1408 return content
1409
mirabalb716ac52017-02-10 14:47:53 +01001410 def get_dhcp_controller(self):
1411 """
1412 Create an host_thread object for manage openvim controller and not create a thread for itself
1413 :return: dhcp_host openvim controller object
1414 """
1415
1416 if 'openvim_controller' in self.config['host_threads']:
1417 return self.config['host_threads']['openvim_controller']
1418
1419 bridge_ifaces = []
1420 controller_ip = self.config['ovs_controller_ip']
tiernoa6933042017-05-24 16:54:33 +02001421 ovs_controller_user = self.config.get('ovs_controller_user')
mirabalb716ac52017-02-10 14:47:53 +01001422
1423 host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False
1424 host_develop_mode = True if self.config['mode'] == 'development' else False
1425
1426 dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip,
tiernoa6933042017-05-24 16:54:33 +02001427 password=self.config.get('ovs_controller_password'),
1428 keyfile=self.config.get('ovs_controller_keyfile'),
tiernoe0c28c12017-05-04 18:44:40 +02001429 db=self.config["db"], db_lock=self.config["db_lock"], test=host_test_mode,
tiernoa6933042017-05-24 16:54:33 +02001430 image_path=self.config['host_image_path'], version=self.config['version'],
mirabalb716ac52017-02-10 14:47:53 +01001431 host_id='openvim_controller', develop_mode=host_develop_mode,
tiernoe0c28c12017-05-04 18:44:40 +02001432 develop_bridge_iface=bridge_ifaces,
1433 logger_name=self.logger_name + ".host.controller",
tiernof135eff2017-04-19 19:11:53 +02001434 debug=self.config.get('log_level_host'))
tiernoa6933042017-05-24 16:54:33 +02001435 # dhcp_host.start()
mirabalb716ac52017-02-10 14:47:53 +01001436 self.config['host_threads']['openvim_controller'] = dhcp_host
mirabal42ca0092017-06-14 05:42:30 -05001437 try:
1438 dhcp_host.check_connectivity()
1439 except Exception as e:
1440 pass
1441
mirabalb716ac52017-02-10 14:47:53 +01001442 return dhcp_host
1443
mirabal6878e3f2017-06-05 09:19:26 -05001444 def launch_dhcp_server(self, vlan, first_ip, last_ip, cidr, gateway, dns, routes):
mirabalb716ac52017-02-10 14:47:53 +01001445 """
1446 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1447 :param vlan: vlan identifier
1448 :param first_ip: First dhcp range ip
1449 :param last_ip: Last dhcp range ip
1450 :param cidr: net cidr
mirabale9f6f1a2017-02-16 17:57:35 +01001451 :param gateway: net gateway
mirabalb716ac52017-02-10 14:47:53 +01001452 :return:
1453 """
1454 ip_tools = IPNetwork(cidr)
1455 dhcp_netmask = str(ip_tools.netmask)
1456 ip_range = [first_ip, last_ip]
1457
1458 dhcp_path = self.config['ovs_controller_file_path']
1459
1460 controller_host = self.get_dhcp_controller()
mirabale16a6362017-07-10 05:45:56 -05001461
mirabal6878e3f2017-06-05 09:19:26 -05001462 # controller_host.create_linux_bridge(vlan)
1463 controller_host.create_dhcp_interfaces(vlan, first_ip, dhcp_netmask)
1464 dhcp_path = self.config['ovs_controller_file_path']
1465 controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path, gateway, dns, routes)
1466
1467 def launch_link_bridge_to_ovs(self, vlan, gateway, dhcp_cidr, links=None, routes=None):
1468 """
1469 Launch creating of connections (veth) between user bridge (link) and OVS
1470 :param vlan:
1471 :param gateway:
1472 :param links:
1473 :return:
1474 """
1475
1476 if links:
1477 controller_host = self.get_dhcp_controller()
1478 for link in links:
1479 if 'iface' in link and 'nat' not in link:
1480 controller_host.create_link_bridge_to_ovs(vlan, link['iface'])
1481 elif 'nat' in link:
1482 controller_host.create_qrouter_ovs_connection(vlan, gateway, dhcp_cidr)
1483 controller_host.create_qrouter_br_connection(vlan, dhcp_cidr, link)
1484
1485 if len(routes):
1486 controller_host.add_ns_routes(vlan, routes)
1487
1488 def delete_link_bridge_to_ovs(self, vlan, links=None):
1489 """
1490 Delete connections (veth) between user bridge (link) and OVS
1491 :param vlan:
1492 :param links:
1493 :return:
1494 """
1495 if links:
1496 controller_host = self.get_dhcp_controller()
1497
1498 for link in links:
1499 if 'iface' in link and 'nat' not in link:
1500 controller_host.remove_link_bridge_to_ovs(vlan, link['iface'])
1501 elif 'nat' in link:
1502 controller_host.delete_qrouter_connection(vlan, link['iface'])
1503
mirabalb716ac52017-02-10 14:47:53 +01001504
mirabald87877c2017-03-31 15:15:52 +02001505if __name__ == "__main__":
1506
1507 parser = argparse.ArgumentParser()
tierno46ca3a92017-04-05 19:49:24 +02001508 parser.add_argument("-v","--version", help="show ovim library version", action="store_true")
1509 parser.add_argument("--database-version", help="show required database version", action="store_true")
mirabald87877c2017-03-31 15:15:52 +02001510 args = parser.parse_args()
1511 if args.version:
1512 print ('openvimd version {} {}'.format(ovim.get_version(), ovim.get_version_date()))
1513 print ('(c) Copyright Telefonica')
tierno46ca3a92017-04-05 19:49:24 +02001514 elif args.database_version:
1515 print ('required database version: {}'.format(ovim.get_database_version()))
mirabalb716ac52017-02-10 14:47:53 +01001516